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) {
VALUE save_rgba_to_image_local_color(VALUE image, rgba color) { /* abbreviation for image_local_color */ VALUE ilc = get_image_local(image, IMAGE_COLOR); set_array_value(ilc, 0, rb_float_new(color.red)); set_array_value(ilc, 1, rb_float_new(color.green)); set_array_value(ilc, 2, rb_float_new(color.blue)); set_array_value(ilc, 3, rb_float_new(color.alpha)); return ilc; }
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; }
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); }
/* 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); }
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); }
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); }