/************************************************************************** * * Copyright 2009 VMware, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #include "polygon.h" #include "matrix.h" /*for floatsEqual*/ #include "vg_context.h" #include "vg_state.h" #include "renderer.h" #include "util_array.h" #include "VG/openvg.h" #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "pipe/p_state.h" #include "util/u_inlines.h" #include "pipe/p_screen.h" #include "util/u_draw_quad.h" #include "util/u_math.h" #include <string.h> #include <stdlib.h> #define DEBUG_POLYGON 0 #define COMPONENTS 2 struct polygon { VGfloat *data; VGint size; VGint num_verts; VGboolean dirty; void *user_vbuf; struct pipe_screen *screen; }; static float *ptr_to_vertex(float *data, int idx) { return data + (idx * COMPONENTS); } #if 0 static void polygon_print(struct polygon *poly) { int i; float *vert; debug_printf("Polygon %p, size = %d\n", poly, poly->num_verts); for (i = 0; i < poly->num_verts; ++i) { vert = ptr_to_vertex(poly->data, i); debug_printf("%f, %f, ", vert[0], vert[1]); } debug_printf("\nend\n"); } #endif struct polygon * polygon_create(int size) { struct polygon *poly = (struct polygon*)malloc(sizeof(struct polygon)); poly->data = malloc(sizeof(float) * COMPONENTS * size); poly->size = size; poly->num_verts = 0; poly->dirty = VG_TRUE; poly->user_vbuf = NULL; return poly; } struct polygon * polygon_create_from_data(float *data, int size) { struct polygon *poly = polygon_create(size); memcpy(poly->data, data, sizeof(float) * COMPONENTS * size); poly->num_verts = size; poly->dirty = VG_TRUE; poly->user_vbuf = NULL; return poly; } void polygon_destroy(struct polygon *poly) { free(poly->data); free(poly); } void polygon_resize(struct polygon *poly, int new_size) { float *data = (float*)malloc(sizeof(float) * COMPONENTS * new_size); int size = MIN2(sizeof(float) * COMPONENTS * new_size, sizeof(float) * COMPONENTS * poly->size); memcpy(data, poly->data, size); free(poly->data); poly->data = data; poly->size = new_size; poly->dirty = VG_TRUE; } int polygon_size(struct polygon *poly) { return poly->size; } int polygon_vertex_count(struct polygon *poly) { return poly->num_verts; } float * polygon_data(struct polygon *poly) { return poly->data; } void polygon_vertex_append(struct polygon *p, float x, float y) { float *vert; #if DEBUG_POLYGON debug_printf("Append vertex [%f, %f]\n", x, y); #endif if (p->num_verts >= p->size) { polygon_resize(p, p->size * 2); } vert = ptr_to_vertex(p->data, p->num_verts); vert[0] = x; vert[1] = y; ++p->num_verts; p->dirty = VG_TRUE; } void polygon_set_vertex(struct polygon *p, int idx, float x, float y) { float *vert; if (idx >= p->num_verts) { /*fixme: error reporting*/ abort(); return; } vert = ptr_to_vertex(p->data, idx); vert[0] = x; vert[1] = y; p->dirty = VG_TRUE; } void polygon_vertex(struct polygon *p, int idx, float *vertex) { float *vert; if (idx >= p->num_verts) { /*fixme: error reporting*/ abort(); return; } vert = ptr_to_vertex(p->data, idx); vertex[0] = vert[0]; vertex[1] = vert[1]; } void polygon_bounding_rect(struct polygon *p, float *rect) { int i; float minx, miny, maxx, maxy; float *vert = ptr_to_vertex(p->data, 0); minx = vert[0]; maxx = vert[0]; miny = vert[1]; maxy = vert[1]; for (i = 1; i < p->num_verts; ++i) { vert = ptr_to_vertex(p->data, i); minx = MIN2(vert[0], minx); miny = MIN2(vert[1], miny); maxx = MAX2(vert[0], maxx); maxy = MAX2(vert[1], maxy); } rect[0] = minx; rect[1] = miny; rect[2] = maxx - minx; rect[3] = maxy - miny; } int polygon_contains_point(struct polygon *p, float x, float y) { return 0; } void polygon_append_polygon(struct polygon *dst, struct polygon *src) { if (dst->num_verts + src->num_verts >= dst->size) { polygon_resize(dst, dst->num_verts + src->num_verts * 1.5); } memcpy(ptr_to_vertex(dst->data, dst->num_verts), src->data, src->num_verts * COMPONENTS * sizeof(VGfloat)); dst->num_verts += src->num_verts; } VGboolean polygon_is_closed(struct polygon *p) { VGfloat start[2], end[2]; polygon_vertex(p, 0, start); polygon_vertex(p, p->num_verts - 1, end); return floatsEqual(start[0], end[0]) && floatsEqual(start[1], end[1]); } static void polygon_prepare_buffer(struct vg_context *ctx, struct polygon *poly) { struct pipe_context *pipe; /*polygon_print(poly);*/ pipe = ctx->pipe; if (poly->user_vbuf == NULL || poly->dirty) { poly->screen = pipe->screen; poly->user_vbuf = poly->data; poly->dirty = VG_FALSE; } } void polygon_fill(struct polygon *poly, struct vg_context *ctx) { struct pipe_vertex_element velement; struct pipe_vertex_buffer vbuffer; VGfloat bounds[4]; VGfloat min_x, min_y, max_x, max_y; assert(poly); polygon_bounding_rect(poly, bounds); min_x = bounds[0]; min_y = bounds[1]; max_x = bounds[0] + bounds[2]; max_y = bounds[1] + bounds[3]; #if DEBUG_POLYGON debug_printf("Poly bounds are [%f, %f], [%f, %f]\n", min_x, min_y, max_x, max_y); #endif polygon_prepare_buffer(ctx, poly); /* tell renderer about the vertex attributes */ memset(&velement, 0, sizeof(velement)); velement.src_offset = 0; velement.instance_divisor = 0; velement.vertex_buffer_index = 0; velement.src_format = PIPE_FORMAT_R32G32_FLOAT; /* tell renderer about the vertex buffer */ memset(&vbuffer, 0, sizeof(vbuffer)); vbuffer.user_buffer = poly->user_vbuf; vbuffer.stride = COMPONENTS * sizeof(float); /* vertex size */ renderer_polygon_stencil_begin(ctx->renderer, &velement, ctx->state.vg.fill_rule, VG_FALSE); renderer_polygon_stencil(ctx->renderer, &vbuffer, PIPE_PRIM_TRIANGLE_FAN, 0, (VGuint) poly->num_verts); renderer_polygon_stencil_end(ctx->renderer); renderer_polygon_fill_begin(ctx->renderer, VG_FALSE); renderer_polygon_fill(ctx->renderer, min_x, min_y, max_x, max_y); renderer_polygon_fill_end(ctx->renderer); } void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx) { struct array *polys = polyarray->array; VGfloat min_x = polyarray->min_x; VGfloat min_y = polyarray->min_y; VGfloat max_x = polyarray->max_x; VGfloat max_y = polyarray->max_y; struct pipe_vertex_element velement; struct pipe_vertex_buffer vbuffer; VGint i; #if DEBUG_POLYGON debug_printf("%s: Poly bounds are [%f, %f], [%f, %f]\n", __FUNCTION__, min_x, min_y, max_x, max_y); #endif /* tell renderer about the vertex attributes */ memset(&velement, 0, sizeof(velement)); velement.src_offset = 0; velement.instance_divisor = 0; velement.vertex_buffer_index = 0; velement.src_format = PIPE_FORMAT_R32G32_FLOAT; /* tell renderer about the vertex buffer */ memset(&vbuffer, 0, sizeof(vbuffer)); vbuffer.stride = COMPONENTS * sizeof(float); /* vertex size */ /* prepare the stencil buffer */ renderer_polygon_stencil_begin(ctx->renderer, &velement, ctx->state.vg.fill_rule, VG_FALSE); for (i = 0; i < polys->num_elements; ++i) { struct polygon *poly = (((struct polygon**)polys->data)[i]); polygon_prepare_buffer(ctx, poly); vbuffer.user_buffer = poly->user_vbuf; renderer_polygon_stencil(ctx->renderer, &vbuffer, PIPE_PRIM_TRIANGLE_FAN, 0, (VGuint) poly->num_verts); } renderer_polygon_stencil_end(ctx->renderer); /* fill it */ renderer_polygon_fill_begin(ctx->renderer, VG_FALSE); renderer_polygon_fill(ctx->renderer, min_x, min_y, max_x, max_y); renderer_polygon_fill_end(ctx->renderer); }