Esempio n. 1
0
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;
  }

}
Esempio n. 2
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;
            }

        }
    }
}
Esempio n. 3
0
/** 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;
}
Esempio n. 4
0
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;
            }
        }
    }
}
Esempio n. 5
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);
}
Esempio n. 6
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);
}
Esempio n. 7
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);
}
Esempio n. 8
0
static int lookup_keyword(char *word)
{
    if (!keyword_map)
        populate_keywords();
    
    int val = (int) get_from_hash(keyword_map, word, strlen(word));
    
    return val;
}
Esempio n. 9
0
/* 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;
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
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;
}
Esempio n. 12
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;
        }
    }
}
Esempio n. 13
0
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);
    }
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
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);
}
Esempio n. 16
0
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);
}
Esempio n. 17
0
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));

  }


}
Esempio n. 18
0
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("}");
        }
    }
}
Esempio n. 19
0
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");
}
Esempio n. 20
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");
    }
}
Esempio n. 21
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);
}
Esempio n. 22
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);
}
Esempio n. 23
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));
    }
  }
}
Esempio n. 24
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);
}
Esempio n. 25
0
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;
}
Esempio n. 26
0
/** 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);
}
Esempio n. 27
0
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;
}
Esempio n. 28
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);
}