/* if 2nd param is Qnil, then create a blank image with 'width' and 'height otherwise, try to use the 2nd param (dup) to create a duplicate image */ VALUE create_image(VALUE window, int width, int height) { static VALUE empty_image_stub = 0; static VALUE image = 0; if (empty_image_stub == 0) { VALUE gosu = rb_const_get(rb_cObject, rb_intern("Gosu")); VALUE tp = rb_const_get(rb_cObject, rb_intern("TexPlay")); empty_image_stub = rb_const_get(tp, rb_intern("EmptyImageStub")); image = rb_const_get(gosu, rb_intern("Image")); } VALUE rmagick_img; VALUE new_image; VALUE options = rb_hash_new(); set_hash_value(options, "caching", Qfalse); rmagick_img = rb_funcall(empty_image_stub, rb_intern("new"), 2, INT2FIX(width), INT2FIX(height)); new_image = rb_funcall(image, rb_intern("new"), 3, window, rmagick_img, options); return new_image; }
/* 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); }
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"); } }