static void prepare_color_select(action_struct * payload) { VALUE try_color = get_from_hash(payload->hash_arg, "source_select"); if (!NIL_P(try_color)) { process_select_color_list(&payload->pen.source_select, try_color); payload->pen.has_color_select = true; } try_color = get_from_hash(payload->hash_arg, "source_ignore"); if (!NIL_P(try_color)) { process_select_color_list(&payload->pen.source_ignore, try_color); payload->pen.has_color_select = true; } try_color = get_from_hash(payload->hash_arg, "dest_select"); if (!NIL_P(try_color)) { process_select_color_list(&payload->pen.dest_select, try_color); payload->pen.has_color_select = true; } try_color = get_from_hash(payload->hash_arg, "dest_ignore"); if (!NIL_P(try_color)) { process_select_color_list(&payload->pen.dest_ignore, try_color); payload->pen.has_color_select = true; } }
/* 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; } } } }
/** Get the next vertex in this basic block. There is a next vertex IFF there's one out-edge, and the vertex on that out-edge has one in-edge. Out-edge is forward if dir == 1 and backward if dir == 2. */ static NODE *get_bb_next(GRAPH *graph, NODE *vertex, int dir) { HASH *dir_hash, *rev_hash; if (dir == 1) { dir_hash = graph->forward; rev_hash = graph->backward; } else if (dir == 2) { dir_hash = graph->backward; rev_hash = graph->forward; } else error("Need to specify 1 or 2 for direction!"); HASH *succ_hash = get_from_hash(dir_hash, vertex, sizeof (void *)); if (!succ_hash || succ_hash->num != 1) return NULL; HASH_ITERATOR iter; hash_iterator(succ_hash, &iter); NODE *next = iter.entry->key; HASH *pred_hash = get_from_hash(rev_hash, next, sizeof (void *)); if (!pred_hash || pred_hash->num != 1) return NULL; return next; }
void cleanup_graph(FUNCTION *func) { GRAPH *graph = func->graph; int i; restart: for (i = 2; i < tree_num_children(graph); i++) { NODE *vertex = tree_get_child(graph, i); if (vertex == NULL) continue; if (!find_in_hash(graph->forward, vertex, sizeof(void *)) || !find_in_hash(graph->backward, vertex, sizeof(void *))) { //printf(" dead-end: "); //tree_print(vertex, 2); } if (tree_is_type(vertex, STMT_PASS)) { HASH *subhash = get_from_hash(graph->forward, vertex, sizeof(void *)); HASH_ITERATOR iter; hash_iterator(subhash, &iter); if (hash_iterator_valid(&iter)) { NODE *successor = iter.entry->key; EDGE_TYPE type = (EDGE_TYPE) iter.entry->data; replace_backward(graph, vertex, successor, type); remove_edge(graph, vertex, successor); remove_vertex(graph, vertex); goto restart; } } else if (tree_is_type(vertex, STMT_JOIN)) { HASH *subhash = get_from_hash(graph->forward, vertex, sizeof(void *)); if (subhash->num != 1) error("Join does not have exactly 1 successor"); HASH_ITERATOR iter; hash_iterator(subhash, &iter); if (hash_iterator_valid(&iter)) { NODE *successor = iter.entry->key; EDGE_TYPE type = (EDGE_TYPE) iter.entry->data; replace_backward(graph, vertex, successor, type); remove_edge(graph, vertex, successor); remove_vertex(graph, vertex); goto restart; } } } }
/** 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); }
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); }
/* 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); }
static int lookup_keyword(char *word) { if (!keyword_map) populate_keywords(); int val = (int) get_from_hash(keyword_map, word, strlen(word)); return val; }
/* returns true if 'hash' is a hash and the value mapped to key 'sym' is equal to 'val' */ bool hash_value_is(VALUE hash, char * sym, VALUE val) { if(TYPE(hash) != T_HASH) return false; if(get_from_hash(hash, sym) == val) return true; return false; }
static void vertex_printer(NODE *vertex, void *data) { DAA_SET *set = NULL; if (data) { DFA *dfa = data; LIST *input = get_from_hash(dfa->inputs, vertex, sizeof(void *)); set = input->size ? input->items[0] : NULL; } if (tree_is_type(vertex, STMT_ASSIGN)) { EXPRESSION *dest = tree_get_child(vertex, 0); print_expression(dest, set); printf(" = "); EXPRESSION *src = tree_get_child(vertex, 1); print_expression(src, set); } else if (tree_is_type(vertex, STMT_RETURN)) { printf("return "); EXPRESSION *expr = tree_get_child(vertex, 0); print_expression(expr, set); } else if (tree_is_type(vertex, STMT_TEST)) { printf("test "); EXPRESSION *expr = tree_get_child(vertex, 0); print_expression(expr, set); } else if (tree_is_type(vertex, STMT_PASS)) { printf("pass"); } else if (tree_is_type(vertex, STMT_JOIN)) { printf("join"); } else if (tree_is_type(vertex, STMT_ENTER)) { printf("enter"); } else if (tree_is_type(vertex, STMT_EXIT)) { printf("exit"); } else if (tree_is_type(vertex, DEF_VARIABLE)) { DECLARATION *decl = CAST_TO_DECLARATION(vertex); printf("%s", decl->name); } else printf("?%d?", vertex->type); }
bool has_optional_hash_arg(VALUE hash, char * sym) { if(TYPE(hash) != T_HASH) return false; if(NIL_P(get_from_hash(hash, sym))) return false; /* 'hash' is a hash and the sym exists */ return true; }
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; } } }
void replace_backward(GRAPH *graph, NODE *old, NODE *vertex, EDGE_TYPE type) { HASH *subhash = get_from_hash(graph->backward, old, sizeof(void *)); HASH_ITERATOR iter; for (hash_iterator(subhash, &iter); hash_iterator_valid(&iter); hash_iterator_next(&iter)) { NODE *pred = iter.entry->key; EDGE_TYPE type2 = (EDGE_TYPE) iter.entry->data; remove_edge(graph, pred, old); if (vertex != NULL) add_edge(graph, pred, vertex, type | type2); } }
static NODE *get_successor(GRAPH *graph, NODE *vertex, EDGE_TYPE type) { HASH *subhash = get_from_hash(graph->forward, vertex, sizeof(void *)); HASH_ITERATOR iter; for (hash_iterator(subhash, &iter); hash_iterator_valid(&iter); hash_iterator_next(&iter)) { NODE *succ = iter.entry->key; EDGE_TYPE succ_type = (EDGE_TYPE) iter.entry->data; if (succ_type & type) return succ; } return NULL; }
void inject_before(GRAPH *graph, NODE *vertex, NODE *before, EDGE_TYPE type) { HASH *subhash = get_from_hash(graph->backward, before, sizeof(void *)); HASH_ITERATOR iter; for (hash_iterator(subhash, &iter); hash_iterator_valid(&iter); hash_iterator_next(&iter)) { NODE *pred = iter.entry->key; EDGE_TYPE type = (EDGE_TYPE) iter.entry->data; remove_edge(graph, pred, before); add_edge(graph, pred, vertex, type); } add_edge(graph, vertex, before, EDGE_NORMAL | type); }
static void handle_inotify(csiebox_client* client) { int len = 0, i = 0; char buffer[EVENT_BUF_LEN]; memset(buffer, 0, EVENT_BUF_LEN); if ((len = read(client->inotify_fd, buffer, EVENT_BUF_LEN)) <= 0) { return; } i = 0; while (i < len) { struct inotify_event* event = (struct inotify_event*)&buffer[i]; char path[PATH_MAX]; memset(path, 0, PATH_MAX); char* wd_path; if (!get_from_hash(&(client->inotify_hash), (void**)&wd_path, event->wd)) { continue; } sprintf(path, "%s/", wd_path); strncat(path, event->name, event->len); fprintf(stderr, "wd: %d\n", event->wd); if (event->mask & IN_CREATE) { fprintf(stderr, "type: create\n"); fprintf(stderr, "sync file: %s\n", path); sync_file(client, path); if (event->mask & IN_ISDIR) { add_inotify(client, path); } } else if (event->mask & IN_ATTRIB) { fprintf(stderr, "type: attrib\n"); fprintf(stderr, "sync file meta: %s\n", path); sync_file_meta(client, path); } else if (event->mask & IN_DELETE) { fprintf(stderr, "type: delete\n"); fprintf(stderr, "rm file: %s\n", path); rm_file(client, path, event->mask & IN_ISDIR); } else { fprintf(stderr, "type: modify\n"); fprintf(stderr, "sync file: %s\n", path); sync_file(client, path); } i += EVENT_SIZE + event->len; } memset(buffer, 0, EVENT_BUF_LEN); }
static void prepare_alpha_blend(action_struct * cur) { if(has_optional_hash_arg(cur->hash_arg, "alpha_blend")) { VALUE blend_mode = get_from_hash(cur->hash_arg, "alpha_blend"); /* true is equivalent to default blend mode, 'source' */ if(blend_mode == Qtrue) blend_mode = string2sym("source"); /* where false or nil is passed */ if(!RTEST(blend_mode)) { cur->pen.alpha_blend = false; return; } cur->pen.alpha_blend = true; Check_Type(blend_mode, T_SYMBOL); if(blend_mode == string2sym("source")) { cur->pen.alpha_blend_mode = source; } else if(blend_mode == string2sym("dest")) { cur->pen.alpha_blend_mode = dest; } else if(blend_mode == string2sym("source_with_fixed_alpha")) { cur->pen.alpha_blend_mode = source_with_fixed_alpha; } else if(blend_mode == string2sym("dest_with_fixed_alpha")) { cur->pen.alpha_blend_mode = dest_with_fixed_alpha; } else rb_raise(rb_eArgError, "unrecognized blend mode: %s\n.", sym2string(blend_mode)); } }
static void edge_printer(NODE *from, NODE *to, void *data) { if (data) { DFA *dfa = data; LIST *output = get_from_hash(dfa->outputs, to, sizeof(void *)); DAA_SET *set = output->size ? output->items[0] : NULL; if (set) { printf("{"); HASH_ITERATOR iter; for (hash_iterator(set->set, &iter); hash_iterator_valid(&iter); hash_iterator_next(&iter)) { DECLARATION *decl = CAST_TO_DECLARATION(iter.entry->data); printf("<font color=\"%s\">%s</font>", get_colour(decl->colour), (char *) iter.entry->key); printf(","); } printf("}"); } } }
void print_graph(GRAPH *graph, char *name, void *data) { int i; graph_sequence++; printf("subgraph cluster_%s_%d {\n", name, graph_sequence); printf(" label=\"%s\"; labelloc=\"t\";\n", name); printf(" ranksep=0.1\n"); printf(" node [shape=\"box\", style=\"filled\"];\n"); /* Vertices. */ for (i = 0; i < tree_num_children(graph); i++) { NODE *vertex = tree_get_child(graph, i); if (vertex == NULL) continue; if (combine_bb && !tree_is_type(vertex, DEF_VARIABLE) && get_bb_next(graph, vertex, 2)) continue; printf(" %s_%d_%d [label=<<table border=\"0\">\n", name, graph_sequence, i); printf("<tr><td>%d. ", i); vertex_printer(vertex, data); printf("</td></tr>\n"); if (combine_bb && !tree_is_type(vertex, DEF_VARIABLE)) { NODE *next_vertex = get_bb_next(graph, vertex, 1); while (next_vertex) { vertex = next_vertex; int pos = (int) get_from_hash(graph->labels, vertex, sizeof(void *)); printf("<tr><td>%d. ", pos); vertex_printer(vertex, data); printf("</td></tr>\n"); next_vertex = get_bb_next(graph, vertex, 1); } } printf("</table>>"); if (tree_is_type(vertex, DEF_VARIABLE)) { DECLARATION *decl = CAST_TO_DECLARATION(vertex); printf(", fillcolor=%s", get_colour(decl->colour)); } printf("];\n"); HASH_ENTRY *he; NODE *from = vertex; he = find_in_hash(graph->forward, from, sizeof(void *)); if (he) { HASH *subhash = he->data; HASH_ITERATOR iter; for (hash_iterator(subhash, &iter); hash_iterator_valid(&iter); hash_iterator_next(&iter)) { NODE *to = iter.entry->key; HASH_ENTRY *he2 = find_in_hash(graph->labels, to, sizeof(void *)); if (he2) { EDGE_TYPE type = (EDGE_TYPE) iter.entry->data; if (type == EDGE_SYMMETRICAL) continue; printf(" %s_%d_%d -> %s_%d_%d [label=<", name, graph_sequence, i, name, graph_sequence, (int) he2->data); if (type & EDGE_YES) printf("Y"); if (type & EDGE_NO) printf("N"); if (type & EDGE_BACK) printf("B"); if (type & EDGE_LOOP) printf("L"); edge_printer(from, to, data); printf(">];\n"); } } } } printf("}\n"); }
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"); } }
/** 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); }
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); }
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)); } } }
/* 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); }
int emit_function(FUNCTION *func, EMIT_FUNCTIONS *functions, void *data) { GRAPH *graph = func->graph; QUEUE *queue = create_queue(); HASH *done = create_hash(10, key_type_direct); queue_push(queue, tree_get_child(graph, 0)); NODE *last = NULL; while (!queue_is_empty(queue)) { NODE *vertex = queue_pop(queue); if (find_in_hash(done, vertex, sizeof(void *))) continue; do_next: add_to_hash(done, vertex, sizeof(void *), (void *) 1); int label = (int) get_from_hash(graph->labels, vertex, sizeof(void *)); HASH *predecessor_hash = get_from_hash(graph->backward, vertex, sizeof(void *)); HASH_ITERATOR iter; hash_iterator(predecessor_hash, &iter); if (predecessor_hash && (predecessor_hash->num > 1 || (predecessor_hash->num == 1 && last != iter.entry->key))) { functions->emit_label(label, data); } functions->emit_comment(vertex, data); HASH *successor_hash = get_from_hash(graph->forward, vertex, sizeof(void *)); NODE *successor; int successor_label; if (successor_hash) { hash_iterator(successor_hash, &iter); successor = iter.entry->key; successor_label = (int) get_from_hash(graph->labels, successor, sizeof(void *)); } else successor = NULL; if (tree_is_type(vertex, STMT_ENTER)) { functions->emit_enter(vertex, data); } else if (tree_is_type(vertex, STMT_EXIT)) { functions->emit_exit(vertex, data); last = vertex; continue; } else if (tree_is_type(vertex, STMT_ASSIGN)) functions->emit_assign(vertex, data); else if (tree_is_type(vertex, STMT_RETURN)) functions->emit_return(vertex, data); else if (tree_is_type(vertex, STMT_TEST)) { hash_iterator_next(&iter); NODE *branch = iter.entry->key; EDGE_TYPE branch_type = (EDGE_TYPE) iter.entry->data; int branch_label = (int) get_from_hash(graph->labels, branch, sizeof(void *)); functions->emit_test(vertex, branch_type, branch_label, data); if (!find_in_hash(done, branch, sizeof(void *))) queue_push(queue, branch); /* Force label on next vertex, in case we jumped to it in the test's branch. Fixes a bug where the label is omitted just because the test was before it, by neglecting to notice that the test reaches it by a jump. */ vertex = NULL; } last = vertex; if (find_in_hash(done, successor, sizeof(void *))) { functions->emit_jump(successor_label, data); continue; } vertex = successor; if (vertex) goto do_next; } functions->emit_end(data); destroy_queue(queue); destroy_hash(done); return 1; }
/** splice algorithm **/ void splice_do_action(int x0, int y0, int cx1, int cy1, int cx2, int cy2, texture_info * splice_tex, texture_info * tex, VALUE hash_arg, texplay_sync sync_mode, bool primary, action_struct * payload) { action_struct cur; int xbound; int ybound; rgba chromakey; float * image_buf = NULL; bool inverse_chroma = false; bool same_image = false; bool has_chroma = false; constrain_boundaries(&cx1, &cy1, &cx2, &cy2, splice_tex->width, splice_tex->height); xbound = cx2 - cx1 + 1; ybound = cy2 - cy1 + 1; draw_prologue(&cur, tex, x0, y0, x0 + xbound, y0 + ybound, &hash_arg, sync_mode, primary, &payload); if(has_optional_hash_arg(hash_arg, "chroma_key")) { VALUE c = get_from_hash(hash_arg, "chroma_key"); chromakey = convert_rb_color_to_rgba(c); has_chroma = true; } else if(has_optional_hash_arg(hash_arg, "chroma_key_not")) { chromakey = convert_rb_color_to_rgba(get_from_hash(hash_arg, "chroma_key_not")); inverse_chroma = true; has_chroma = true; } if(splice_tex->image == tex->image) same_image = true; /* NB: we do not use this in the general case since it's almost 1.5 times as slow. It is necessary for splicing from/to the same region of pixels though. */ if(same_image) image_buf = get_image_chunk(splice_tex, cx1, cy1, cx2, cy2); for(int y = 0; y < ybound; y++) for(int x = 0; x < xbound; x++) { if(!same_image) payload->color = get_pixel_color(splice_tex, cx1 + x, cy1 + y); else payload->color = get_pixel_color_from_chunk(image_buf, xbound, ybound, x, y); if(has_chroma) { bool chroma_match = cmp_color(payload->color, chromakey); /* look at released 0.2.0 code to see how USED to do this. this is now a simplified boolean expression (XOR) */ if(chroma_match == inverse_chroma) set_pixel_color_with_style(payload, tex, x0 + x, y0 + y); } else set_pixel_color_with_style(payload, tex, x0 + x, y0 + y); } if(same_image) free(image_buf); draw_epilogue(&cur, tex, primary); }
static EXPRESSION *simplify_expression(MODULE *module, FUNCTION *func, BLOCK *block, EXPRESSION *expr, STATEMENT *before) { int i; int source_line = CAST_TO_AST(expr)->source_line; if (!has_graph(func) && is_short_circuit(expr)) { TYPE *new_temp_type = CAST_TO_EXPRESSION(tree_get_child(expr, 0))->type; EXPRESSION *new_temp = make_new_temp(module, func, new_temp_type, source_line); STATEMENT *new_assign = make_assignment(new_temp, tree_get_child(expr, 0), source_line); tree_add_before(CAST_TO_NODE(block), CAST_TO_NODE(new_assign), CAST_TO_NODE(before)); STATEMENT *new_assign2 = make_assignment(new_temp, tree_get_child(expr, 1), source_line); EXPRESSION *new_cond = new_temp; if (tree_is_type(expr, EXPR_OR)) new_cond = make_unary_expression(EXPR_NOT, new_cond, source_line); STATEMENT *new_if = make_if(new_cond, make_block(NULL, new_assign2, 0), NULL, 0); tree_add_before(CAST_TO_NODE(block), CAST_TO_NODE(new_if), CAST_TO_NODE(before)); return new_temp; } if (has_graph(func) && is_short_circuit(expr)) { GRAPH *graph = func->graph; EXPRESSION *sub0 = tree_get_child(expr, 0); EXPRESSION *sub1 = tree_get_child(expr, 1); STATEMENT *new_test = make_test(sub0, source_line); EDGE_TYPE inner_type = tree_is_type(expr, EXPR_OR) ? EDGE_NO : EDGE_YES; EDGE_TYPE outer_type = tree_is_type(expr, EXPR_OR) ? EDGE_YES : EDGE_NO; add_vertex(graph, CAST_TO_NODE(new_test)); HASH *subhash = get_from_hash(graph->forward, before, sizeof(void *)); HASH_ITERATOR iter; for (hash_iterator(subhash, &iter); hash_iterator_valid(&iter); hash_iterator_next(&iter)) { EDGE_TYPE type = (EDGE_TYPE) iter.entry->data; if (outer_type & type) add_edge(graph, CAST_TO_NODE(new_test), iter.entry->key, type); if (inner_type & type) inner_type = type; } inject_before(graph, CAST_TO_NODE(new_test), CAST_TO_NODE(before), inner_type); return sub1; } if (is_simple(expr)) return expr; if (tree_is_type(expr, EXPR_CALL)) { EXPRESSION *args = CAST_TO_EXPRESSION(tree_get_child(expr, 1)); args = atomise_expression(module, func, block, args, before); tree_get_child(expr, 1) = args; return expr; } for (i = 0; i < tree_num_children(expr); i++) { EXPRESSION *child = tree_get_child(expr, i); if (!is_atomic(child)) { TYPE *new_temp_type = CAST_TO_EXPRESSION(child)->type; EXPRESSION *new_temp = make_new_temp(module, func, new_temp_type, CAST_TO_AST(child)->source_line); STATEMENT *new_assign = make_assignment(new_temp, child, CAST_TO_AST(child)->source_line); if (has_graph(func)) { GRAPH *graph = func->graph; add_vertex(graph, CAST_TO_NODE(new_assign)); inject_before(graph, CAST_TO_NODE(new_assign), CAST_TO_NODE(before), 0); } else tree_add_before(CAST_TO_NODE(block), CAST_TO_NODE(new_assign), CAST_TO_NODE(before)); tree_get_child(expr, i) = new_temp; } } return expr; }
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); }