Ejemplo n.º 1
1
/** bezier curve algorithm **/
static void
bezier_point(VALUE points, float u, float * x, float * y, int n, int format,
             int draw_offset_x, int draw_offset_y)
{
    int xy_index;
    double sumx = 0, sumy = 0;
 

    for(int k = 0; k < n; k++) {
        switch(format) {
        case POINT_FORMAT:
            
            sumx += NUM2DBL(point_x(get_from_array(points, k))) * bernstein(n - 1, k, u);
            sumy += NUM2DBL(point_y(get_from_array(points, k))) * bernstein(n - 1, k, u);
            break;
        case SIMPLE_FORMAT:
             
            xy_index = k * 2;
            sumx +=  NUM2DBL(get_from_array(points, xy_index)) * bernstein(n - 1, k, u);
            sumy +=  NUM2DBL(get_from_array(points, xy_index + 1)) * bernstein(n - 1, k, u);
            break;
        default:
            rb_raise(rb_eArgError, "pixel format must be either POINT_FORMAT or SIMPLE_FORMAT");
        }
    }

    *x = sumx + draw_offset_x;
    *y = sumy + draw_offset_y;
}
Ejemplo n.º 2
0
static void
process_x_y_pairs(VALUE image, int num_pairs, VALUE * argv, ...)
{
    va_list ap;
    int i;
    int draw_offset_x;
    int draw_offset_y;
    VALUE offset_val;

    offset_val = get_image_local(image, DRAW_OFFSET);

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

    va_start(ap, argv);
    if(is_a_point(argv[0])) {
        for(i = 0; i < num_pairs; i++) {
            int *x_ptr, *y_ptr;

            x_ptr = va_arg(ap, int*);
            y_ptr = va_arg(ap, int*);

            *x_ptr = NUM2INT(rb_funcall(argv[i], rb_intern("x"), 0)) + draw_offset_x;
            *y_ptr = NUM2INT(rb_funcall(argv[i], rb_intern("y"), 0)) + draw_offset_y;
        }
    }
    else {
        for(i = 0; i < (num_pairs * 2); i+=2) {
Ejemplo n.º 3
0
bool
is_rb_raw_color(VALUE cval)
{
  return TYPE(cval) == T_ARRAY &&
    is_a_num(get_from_array(cval, 0)) &&
    is_a_num(get_from_array(cval, 1)) &&
    is_a_num(get_from_array(cval, 2)) &&
    is_a_num(get_from_array(cval, 3));
}
Ejemplo n.º 4
0
rgba
convert_image_local_color_to_rgba(VALUE image)
{
  rgba color;
  VALUE image_local_color = get_image_local(image, IMAGE_COLOR);

  color.red = NUM2DBL(get_from_array(image_local_color, red)); 
  color.green = NUM2DBL(get_from_array(image_local_color, green)); 
  color.blue = NUM2DBL(get_from_array(image_local_color, blue)); 
  color.alpha = NUM2DBL(get_from_array(image_local_color, alpha)); 
    
  return color;
}
Ejemplo n.º 5
0
void
update_lazy_bounds(action_struct * cur, texture_info * tex)
{

    /* only update global bounds if we're doing a lazy_sync */
    if (cur->sync_mode != lazy_sync)
      return;

    VALUE lazy_bounds;
    int xmin, ymin, xmax, ymax;

    lazy_bounds = get_image_local(tex->image, LAZY_BOUNDS);

    xmin = INT2FIX(MIN(cur->xmin, FIX2INT(get_from_array(lazy_bounds, 0))));
    ymin = INT2FIX(MIN(cur->ymin, FIX2INT(get_from_array(lazy_bounds, 1))));
    xmax = INT2FIX(MAX(cur->xmax, FIX2INT(get_from_array(lazy_bounds, 2))));
    ymax = INT2FIX(MAX(cur->ymax, FIX2INT(get_from_array(lazy_bounds, 3))));

    set_array_value(lazy_bounds, 0, xmin);
    set_array_value(lazy_bounds, 1, ymin);
    set_array_value(lazy_bounds, 2, xmax);
    set_array_value(lazy_bounds, 3, ymax);
}
Ejemplo n.º 6
0
static void
process_select_color_list(rgba_list * clist, VALUE try_color)
{
    /* is a general array of colors? i.e [:red, Gosu::Color::RED, [1,1,1,1] ] */
    if (TYPE(try_color) == T_ARRAY && not_rb_raw_color(try_color)) {
      int num_colors = RARRAY_LEN(try_color);

      if (num_colors > RGBA_LIST_SIZE)
        rb_raise(rb_eArgError, "Too many colors given in array. Maximum is %d\n. Got %d\n",
                 RGBA_LIST_SIZE, num_colors);

      for (int i = 0; i < RARRAY_LEN(try_color); ++i) {
        clist->colors[i] = convert_rb_color_to_rgba(get_from_array(try_color, i));
      }

      clist->size = num_colors;
    }

    /* is a single color value? i.e :red, [1,1,1,1], Gosu::Color::GREEN */
    else {
        clist->colors[0] = convert_rb_color_to_rgba(try_color);
        clist->size = 1;
    }
}
Ejemplo n.º 7
0
bool
not_rb_raw_color(VALUE cval)
{
  return TYPE(cval) != T_ARRAY ||
    !is_a_num(get_from_array(cval, 0));
}
Ejemplo n.º 8
0
VALUE
get_image_local(VALUE image, int name)
{
  VALUE image_local;
  VALUE val;

  init_image_local(image);

  /* this var holds all the image local variables in an array */
  image_local = rb_iv_get(image, "__image_local__");

  /* a particular image_local variable */
  val = get_from_array(image_local, name);
    
  /* if the variable exists then return it */
  if(!NIL_P(val))
    return val;

  /* otherwise initialize the variable and then return it */
  else {
    switch(name) {
      VALUE init_offset, init_bounds, init_color, init_defaults;
    case DRAW_OFFSET:
      init_offset = rb_ary_new2(2);
      set_array_value(init_offset, 0, INT2FIX(0));
      set_array_value(init_offset, 1, INT2FIX(0));

      set_array_value(image_local, DRAW_OFFSET, init_offset);

      return init_offset;
      break;
    case LAZY_BOUNDS:
      init_bounds = rb_ary_new2(4);
      set_array_value(init_bounds, 0, INT2FIX(XMAX_OOB));
      set_array_value(init_bounds, 1, INT2FIX(YMAX_OOB));
      set_array_value(init_bounds, 2, INT2FIX(XMIN_OOB));
      set_array_value(init_bounds, 3, INT2FIX(YMIN_OOB));

      set_array_value(image_local, LAZY_BOUNDS, init_bounds);

      return init_bounds;
      break;
    case IMAGE_COLOR:
      init_color = rb_ary_new2(4);
      set_array_value(init_color, 0, rb_float_new(1.0));
      set_array_value(init_color, 1, rb_float_new(1.0));
      set_array_value(init_color, 2, rb_float_new(1.0));
      set_array_value(init_color, 3, rb_float_new(1.0));

      set_array_value(image_local, IMAGE_COLOR, init_color);

      return init_color;
      break;
    case USER_DEFAULTS:
      init_defaults = rb_hash_new();

      set_array_value(image_local, USER_DEFAULTS, init_defaults);

      return init_defaults;
      break;
    default:
      rb_raise(rb_eArgError, "unrecognized image_local variable number. got %d", name);
    }
  }
    
  /* never reached */
  return Qnil;
}
Ejemplo n.º 9
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);
}
Ejemplo n.º 10
0
trace_match
line_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)
{
    int x, y, W, H, F;
    int xinc, yinc;
    action_struct cur;
    int thickness = 1;

    bool has_trace = false;
    rgba trace_color;
    trace_mode_type trace_mode = no_mode;
    
    if(has_optional_hash_arg(hash_arg, "thickness")) 
        thickness = NUM2INT(get_from_hash(hash_arg, "thickness"));
    
    if(has_optional_hash_arg(hash_arg, "trace") && primary) {
      VALUE trace_hash = get_from_hash(hash_arg, "trace");

      /* we're tracing (not drawing) */
      has_trace = true;

      /* since we're not drawing, no need to sync */
      sync_mode = no_sync;

      if(has_optional_hash_arg(trace_hash, "until_color")) {
        VALUE c = get_from_hash(trace_hash, "until_color");
        trace_color = convert_rb_color_to_rgba(c);
        trace_mode = until_color;
      }
      else if(has_optional_hash_arg(trace_hash, "while_color")) {
        VALUE c = get_from_hash(trace_hash, "while_color");
        trace_color = convert_rb_color_to_rgba(c);
        trace_mode = while_color;
      }
    }

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

    /* clip the line */
    cohen_sutherland_clip(&x1, &y1, &x2, &y2, 0, 0, tex->width - 1, tex->height - 1);
    
    W = ABS(x2 - x1);
    H = ABS(y2 - y1);
    	
    if(x1 < x2)
        xinc = 1;
    else
        xinc = -1;
		
    if(y1 < y2)
        yinc = 1;
    else
        yinc = -1;
		
    x = x1;
    y = y1;
	
    if(W >= H) {
        F = 2 * H - W;
        while(x != x2) {
           if(thickness <= 1) {
             if(!has_trace)
                set_pixel_color_with_style(payload, tex, x, y);
             else {
               rgba c = get_pixel_color(tex, x, y);

               if (is_trace_match(payload, c, trace_color, trace_mode)) 
                 return (trace_match) { x, y, c };
             }
            }
            else {
                set_hash_value(hash_arg, "fill", Qtrue);
                circle_do_action(x, y, thickness / 2, tex, hash_arg, no_sync, false, payload);
            }
           
            if(F < 0)
                F += 2 * H;
            else {
                F += 2 * (H - W);
                y += yinc;
            }
            x += xinc;
        }
    }
    else {
        F = 2 * W - H;
        while(y != y2 ) {

            if(thickness <= 1) {
             if(!has_trace)
                set_pixel_color_with_style(payload, tex, x, y);
             else {
               rgba c = get_pixel_color(tex, x, y);

               if (is_trace_match(payload, c, trace_color, trace_mode)) 
                 return (trace_match) { x, y, c };
             }                
            }
            else {
                set_hash_value(hash_arg, "fill", Qtrue);
                circle_do_action(x, y, thickness / 2, tex, hash_arg, no_sync, false, payload);
            }
            
            if(F < 0)
                F += 2 * W;
            else {
                F += 2 * (W - H);
                x += xinc;
            }
            y += yinc;
        }
    }

    if(thickness <= 1) {
        if(!has_trace)
          set_pixel_color_with_style(payload, tex, x2, y2);
        else {
          rgba c = get_pixel_color(tex, x, y);
          
          if (is_trace_match(payload, c, trace_color, trace_mode)) 
            return (trace_match) { x, y, c };
        }        
    }
    else {
        set_hash_value(hash_arg, "fill", Qtrue);
        circle_do_action(x2, y2, thickness / 2, tex, hash_arg, no_sync, false, payload);
                
    }
    draw_epilogue(&cur, tex, primary);

    return (trace_match) { .x = -9999, .y = -9999, .color = not_a_color_v };
}
/** end line **/

/** polyline algorithm **/

/* used by both polyline and bezier */
#define SIMPLE_FORMAT 0
#define POINT_FORMAT 1

/* calculate a single point */
static void
polyline_point(VALUE points, int k, int * x, int * y, int format, int draw_offset_x,
               int draw_offset_y)
{
    int xy_index;
    
    switch(format) {
    case POINT_FORMAT:
        *x = NUM2INT(point_x(get_from_array(points, k))) + draw_offset_x;
        *y = NUM2INT(point_y(get_from_array(points, k))) + draw_offset_y;
        break;
        
    case SIMPLE_FORMAT:
        xy_index = k * 2;
        *x = NUM2INT(get_from_array(points, xy_index)) + draw_offset_x;
        *y = NUM2INT(get_from_array(points, xy_index + 1)) + draw_offset_y;

        break;
    default:
        rb_raise(rb_eArgError, "pixel format must be either POINT_FORMAT or SIMPLE_FORMAT");
    }
}
Ejemplo n.º 11
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);
}