mirror of
https://github.com/brl/mutter.git
synced 2024-11-12 17:27:03 -05:00
cogl: Support retained paths
This adds three new API calls: CoglHandle cogl_path_get() void cogl_path_set(CoglHandle path) CoglHandle cogl_path_copy(CoglHandle path) All of the fields relating to the path have been moved from the Cogl context to a new CoglPath handle type. The cogl context now just contains a CoglPath handle. All of the existing path commands manipulate the data in the current path handle. cogl_path_new now just creates a new path handle and unrefs the old one. The path handle can be stored for later with cogl_path_get. The path can then be copied with cogl_path_copy. Internally it implements copy-on-write semantics with an extra optimisation that it will only copy the data if the new path is modified, but not if the original path is modified. It can do this because the only way to modify a path is by appending to it so the copied path is able to store its own path length and only render the nodes up to that length. For this to work the copied path also needs to keep its own copies of the path extents because the parent path may change these by adding nodes. The clip stack now uses the cogl_path_copy mechanism to store paths in the stack instead of directly copying the data. This should save some memory and processing time.
This commit is contained in:
parent
d1353b3c1a
commit
067a520f26
@ -97,6 +97,7 @@ cogl_sources_c = \
|
||||
$(srcdir)/cogl-bitmap-fallback.c \
|
||||
$(srcdir)/cogl-primitives.h \
|
||||
$(srcdir)/cogl-primitives.c \
|
||||
$(srcdir)/cogl-path-private.h \
|
||||
$(srcdir)/cogl-path.h \
|
||||
$(srcdir)/cogl-path.c \
|
||||
$(srcdir)/cogl-bitmap-pixbuf.c \
|
||||
|
@ -38,13 +38,7 @@
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-journal-private.h"
|
||||
#include "cogl-util.h"
|
||||
|
||||
void _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
|
||||
floatVec2 nodes_max,
|
||||
unsigned int path_size,
|
||||
CoglPathNode *path,
|
||||
gboolean merge,
|
||||
gboolean need_clear);
|
||||
#include "cogl-path-private.h"
|
||||
|
||||
typedef struct _CoglClipStack CoglClipStack;
|
||||
|
||||
@ -96,11 +90,7 @@ struct _CoglClipStackEntryPath
|
||||
/* The matrix that was current when the clip was set */
|
||||
CoglMatrix matrix;
|
||||
|
||||
floatVec2 path_nodes_min;
|
||||
floatVec2 path_nodes_max;
|
||||
|
||||
unsigned int path_size;
|
||||
CoglPathNode path[1];
|
||||
CoglHandle path;
|
||||
};
|
||||
|
||||
static void
|
||||
@ -567,15 +557,10 @@ cogl_clip_push_from_path_preserve (void)
|
||||
|
||||
stack = clip_state->stacks->data;
|
||||
|
||||
entry = g_malloc (sizeof (CoglClipStackEntryPath)
|
||||
+ sizeof (CoglPathNode) * (ctx->path_nodes->len - 1));
|
||||
entry = g_slice_new (CoglClipStackEntryPath);
|
||||
|
||||
entry->type = COGL_CLIP_STACK_PATH;
|
||||
entry->path_nodes_min = ctx->path_nodes_min;
|
||||
entry->path_nodes_max = ctx->path_nodes_max;
|
||||
entry->path_size = ctx->path_nodes->len;
|
||||
memcpy (entry->path, ctx->path_nodes->data,
|
||||
sizeof (CoglPathNode) * ctx->path_nodes->len);
|
||||
entry->path = cogl_path_copy (cogl_path_get ());
|
||||
|
||||
cogl_get_modelview_matrix (&entry->matrix);
|
||||
|
||||
@ -617,7 +602,10 @@ _cogl_clip_pop_real (CoglClipStackState *clip_state)
|
||||
else if (type == COGL_CLIP_STACK_WINDOW_RECT)
|
||||
g_slice_free (CoglClipStackEntryWindowRect, entry);
|
||||
else
|
||||
g_free (entry);
|
||||
{
|
||||
cogl_handle_unref (((CoglClipStackEntryPath *) entry)->path);
|
||||
g_slice_free (CoglClipStackEntryPath, entry);
|
||||
}
|
||||
|
||||
stack->stack_top = g_list_delete_link (stack->stack_top,
|
||||
stack->stack_top);
|
||||
@ -693,15 +681,12 @@ _cogl_flush_clip_state (CoglClipStackState *clip_state)
|
||||
|
||||
if (type == COGL_CLIP_STACK_PATH)
|
||||
{
|
||||
CoglClipStackEntryPath *path = (CoglClipStackEntryPath *) entry;
|
||||
CoglClipStackEntryPath *path_entry = (CoglClipStackEntryPath *) entry;
|
||||
|
||||
_cogl_matrix_stack_push (modelview_stack);
|
||||
_cogl_matrix_stack_set (modelview_stack, &path->matrix);
|
||||
_cogl_matrix_stack_set (modelview_stack, &path_entry->matrix);
|
||||
|
||||
_cogl_add_path_to_stencil_buffer (path->path_nodes_min,
|
||||
path->path_nodes_max,
|
||||
path->path_size,
|
||||
path->path,
|
||||
_cogl_add_path_to_stencil_buffer (path_entry->path,
|
||||
using_stencil_buffer,
|
||||
TRUE);
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "cogl-texture-private.h"
|
||||
#include "cogl-material-private.h"
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-path-private.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -108,8 +109,7 @@ cogl_create_context (void)
|
||||
_context->dirty_bound_framebuffer = TRUE;
|
||||
_context->dirty_gl_viewport = TRUE;
|
||||
|
||||
_context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
|
||||
_context->last_path = 0;
|
||||
_context->current_path = _cogl_path_new ();
|
||||
_context->stencil_material = cogl_material_new ();
|
||||
|
||||
_context->in_begin_gl_block = FALSE;
|
||||
@ -168,8 +168,8 @@ _cogl_destroy_context ()
|
||||
|
||||
_cogl_free_framebuffer_stack (_context->framebuffer_stack);
|
||||
|
||||
if (_context->path_nodes)
|
||||
g_array_free (_context->path_nodes, TRUE);
|
||||
if (_context->current_path)
|
||||
cogl_handle_unref (_context->current_path);
|
||||
|
||||
if (_context->default_gl_texture_2d_tex)
|
||||
cogl_handle_unref (_context->default_gl_texture_2d_tex);
|
||||
|
@ -99,12 +99,7 @@ typedef struct
|
||||
gboolean dirty_gl_viewport;
|
||||
|
||||
/* Primitives */
|
||||
floatVec2 path_start;
|
||||
floatVec2 path_pen;
|
||||
GArray *path_nodes;
|
||||
unsigned int last_path;
|
||||
floatVec2 path_nodes_min;
|
||||
floatVec2 path_nodes_max;
|
||||
CoglHandle current_path;
|
||||
CoglHandle stencil_material;
|
||||
|
||||
/* Pre-generated VBOs containing indices to generate GL_TRIANGLES
|
||||
|
@ -27,34 +27,6 @@
|
||||
#include "cogl.h"
|
||||
#include "cogl-matrix-stack.h"
|
||||
|
||||
typedef struct _floatVec2
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
} floatVec2;
|
||||
|
||||
typedef struct _CoglPathNode
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
unsigned int path_size;
|
||||
} CoglPathNode;
|
||||
|
||||
typedef struct _CoglBezQuad
|
||||
{
|
||||
floatVec2 p1;
|
||||
floatVec2 p2;
|
||||
floatVec2 p3;
|
||||
} CoglBezQuad;
|
||||
|
||||
typedef struct _CoglBezCubic
|
||||
{
|
||||
floatVec2 p1;
|
||||
floatVec2 p2;
|
||||
floatVec2 p3;
|
||||
floatVec2 p4;
|
||||
} CoglBezCubic;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COGL_FRONT_WINDING_CLOCKWISE,
|
||||
|
96
cogl/cogl-path-private.h
Normal file
96
cogl/cogl-path-private.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* An object oriented GL/GLES Abstraction/Utility Layer
|
||||
*
|
||||
* Copyright (C) 2010 Intel Corporation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __COGL_PATH_PRIVATE_H
|
||||
#define __COGL_PATH_PRIVATE_H
|
||||
|
||||
#include "cogl-handle.h"
|
||||
|
||||
#define COGL_PATH(tex) ((CoglPath *)(tex))
|
||||
|
||||
typedef struct _floatVec2
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
} floatVec2;
|
||||
|
||||
typedef struct _CoglPathNode
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
unsigned int path_size;
|
||||
} CoglPathNode;
|
||||
|
||||
typedef struct _CoglBezQuad
|
||||
{
|
||||
floatVec2 p1;
|
||||
floatVec2 p2;
|
||||
floatVec2 p3;
|
||||
} CoglBezQuad;
|
||||
|
||||
typedef struct _CoglBezCubic
|
||||
{
|
||||
floatVec2 p1;
|
||||
floatVec2 p2;
|
||||
floatVec2 p3;
|
||||
floatVec2 p4;
|
||||
} CoglBezCubic;
|
||||
|
||||
typedef struct _CoglPath CoglPath;
|
||||
|
||||
struct _CoglPath
|
||||
{
|
||||
CoglHandleObject _parent;
|
||||
|
||||
/* If this path was created with cogl_path_copy then parent_path
|
||||
will point to the copied path. Otherwise it will be
|
||||
COGL_INVALID_HANDLE to indicate that we own path_nodes. */
|
||||
CoglHandle parent_path;
|
||||
/* Pointer to the path nodes array. This will point directly into
|
||||
the parent path if this path is a copy */
|
||||
GArray *path_nodes;
|
||||
/* Number of nodes to render from the data. This may be different
|
||||
from path_nodes->len if this is a copied path and the parent path
|
||||
was appended to. If that is the case then we need to be careful
|
||||
to check that the size of a sub path doesn't extend past
|
||||
path_size */
|
||||
unsigned int path_size;
|
||||
|
||||
floatVec2 path_start;
|
||||
floatVec2 path_pen;
|
||||
unsigned int last_path;
|
||||
floatVec2 path_nodes_min;
|
||||
floatVec2 path_nodes_max;
|
||||
};
|
||||
|
||||
/* This is an internal version of cogl_path_new that doesn't affect
|
||||
the current path and just creates a new handle */
|
||||
CoglHandle
|
||||
_cogl_path_new (void);
|
||||
|
||||
void
|
||||
_cogl_add_path_to_stencil_buffer (CoglHandle path,
|
||||
gboolean merge,
|
||||
gboolean need_clear);
|
||||
|
||||
#endif /* __COGL_PATH_PRIVATE_H */
|
333
cogl/cogl-path.c
333
cogl/cogl-path.c
@ -31,6 +31,7 @@
|
||||
#include "cogl-journal-private.h"
|
||||
#include "cogl-material-private.h"
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-path-private.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
@ -41,37 +42,86 @@
|
||||
#define glClientActiveTexture ctx->drv.pf_glClientActiveTexture
|
||||
#endif
|
||||
|
||||
static void _cogl_path_free (CoglPath *path);
|
||||
|
||||
COGL_HANDLE_DEFINE (Path, path);
|
||||
|
||||
static void
|
||||
_cogl_path_modify (CoglPath *path)
|
||||
{
|
||||
/* This needs to be called whenever the path is about to be modified
|
||||
to implement copy-on-write semantics. Note that the current
|
||||
mechanism assumes that a path will only ever be appended to (ie,
|
||||
the path won't be cleared or have nodes in the middle
|
||||
changed). This means that we don't need to keep track of how many
|
||||
copies a node has because the copies can just keep track of the
|
||||
number of nodes they should draw */
|
||||
|
||||
/* If this path is a copy then we need to actually copy the data so
|
||||
we can modify it */
|
||||
if (path->parent_path)
|
||||
{
|
||||
CoglPath *old_path = COGL_PATH (path->parent_path);
|
||||
CoglPathNode *old_nodes = &g_array_index (old_path->path_nodes,
|
||||
CoglPathNode, 0);
|
||||
CoglPathNode *new_nodes;
|
||||
int i;
|
||||
|
||||
path->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
|
||||
/* The parent path may have extra nodes added after the copy was
|
||||
made so we need to truncate it */
|
||||
g_array_set_size (path->path_nodes, path->path_size);
|
||||
memcpy (path->path_nodes->data, old_nodes,
|
||||
sizeof (CoglPathNode) * path->path_size);
|
||||
/* We need to make sure the last path size doesn't extend past
|
||||
the total path size */
|
||||
new_nodes = &g_array_index (path->path_nodes, CoglPathNode, 0);
|
||||
for (i = 0; i < path->path_size; i += new_nodes[i].path_size)
|
||||
if (new_nodes[i].path_size >= path->path_size)
|
||||
new_nodes[i].path_size = path->path_size - i;
|
||||
|
||||
cogl_handle_unref (path->parent_path);
|
||||
path->parent_path = COGL_INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_path_add_node (gboolean new_sub_path,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
CoglPathNode new_node;
|
||||
CoglPath *path;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
_cogl_path_modify (path);
|
||||
|
||||
new_node.x = x;
|
||||
new_node.y = y;
|
||||
new_node.path_size = 0;
|
||||
|
||||
if (new_sub_path || ctx->path_nodes->len == 0)
|
||||
ctx->last_path = ctx->path_nodes->len;
|
||||
if (new_sub_path || path->path_size == 0)
|
||||
path->last_path = path->path_size;
|
||||
|
||||
g_array_append_val (ctx->path_nodes, new_node);
|
||||
g_array_append_val (path->path_nodes, new_node);
|
||||
path->path_size++;
|
||||
|
||||
g_array_index (ctx->path_nodes, CoglPathNode, ctx->last_path).path_size++;
|
||||
g_array_index (path->path_nodes, CoglPathNode, path->last_path).path_size++;
|
||||
|
||||
if (ctx->path_nodes->len == 1)
|
||||
if (path->path_size == 1)
|
||||
{
|
||||
ctx->path_nodes_min.x = ctx->path_nodes_max.x = x;
|
||||
ctx->path_nodes_min.y = ctx->path_nodes_max.y = y;
|
||||
path->path_nodes_min.x = path->path_nodes_max.x = x;
|
||||
path->path_nodes_min.y = path->path_nodes_max.y = y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x < ctx->path_nodes_min.x) ctx->path_nodes_min.x = x;
|
||||
if (x > ctx->path_nodes_max.x) ctx->path_nodes_max.x = x;
|
||||
if (y < ctx->path_nodes_min.y) ctx->path_nodes_min.y = y;
|
||||
if (y > ctx->path_nodes_max.y) ctx->path_nodes_max.y = y;
|
||||
if (x < path->path_nodes_min.x) path->path_nodes_min.x = x;
|
||||
if (x > path->path_nodes_max.x) path->path_nodes_max.x = x;
|
||||
if (y < path->path_nodes_min.y) path->path_nodes_min.y = y;
|
||||
if (y > path->path_nodes_max.y) path->path_nodes_max.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,10 +130,13 @@ _cogl_path_stroke_nodes (void)
|
||||
{
|
||||
unsigned int path_start = 0;
|
||||
unsigned long enable_flags = COGL_ENABLE_VERTEX_ARRAY;
|
||||
CoglPath *path;
|
||||
CoglMaterialFlushOptions options;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
_cogl_journal_flush ();
|
||||
|
||||
/* NB: _cogl_framebuffer_flush_state may disrupt various state (such
|
||||
@ -100,17 +153,19 @@ _cogl_path_stroke_nodes (void)
|
||||
|
||||
_cogl_material_flush_gl_state (ctx->source_material, &options);
|
||||
|
||||
while (path_start < ctx->path_nodes->len)
|
||||
while (path_start < path->path_size)
|
||||
{
|
||||
CoglPathNode *path = &g_array_index (ctx->path_nodes, CoglPathNode,
|
||||
CoglPathNode *node = &g_array_index (path->path_nodes, CoglPathNode,
|
||||
path_start);
|
||||
|
||||
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
|
||||
(guint8 *) path
|
||||
+ G_STRUCT_OFFSET (CoglPathNode, x)) );
|
||||
GE( glDrawArrays (GL_LINE_STRIP, 0, path->path_size) );
|
||||
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), &node->x) );
|
||||
/* We need to limit the size of the sub path to the size of our
|
||||
path in case this path is a copy and the parent path has
|
||||
grown */
|
||||
GE( glDrawArrays (GL_LINE_STRIP, 0,
|
||||
MIN (node->path_size, path->path_size - path_start)) );
|
||||
|
||||
path_start += path->path_size;
|
||||
path_start += node->path_size;
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,12 +184,9 @@ _cogl_path_get_bounds (floatVec2 nodes_min,
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
|
||||
floatVec2 nodes_max,
|
||||
unsigned int path_size,
|
||||
CoglPathNode *path,
|
||||
gboolean merge,
|
||||
gboolean need_clear)
|
||||
_cogl_add_path_to_stencil_buffer (CoglHandle path_handle,
|
||||
gboolean merge,
|
||||
gboolean need_clear)
|
||||
{
|
||||
unsigned int path_start = 0;
|
||||
unsigned int sub_path_num = 0;
|
||||
@ -150,10 +202,12 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
|
||||
_cogl_framebuffer_get_modelview_stack (framebuffer);
|
||||
CoglMatrixStack *projection_stack =
|
||||
_cogl_framebuffer_get_projection_stack (framebuffer);
|
||||
|
||||
CoglPath *path;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
path = COGL_PATH (path_handle);
|
||||
|
||||
/* We don't track changes to the stencil buffer in the journal
|
||||
* so we need to flush any batched geometry first */
|
||||
_cogl_journal_flush ();
|
||||
@ -173,7 +227,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
|
||||
_cogl_material_get_cogl_enable_flags (ctx->source_material);
|
||||
_cogl_enable (enable_flags);
|
||||
|
||||
_cogl_path_get_bounds (nodes_min, nodes_max,
|
||||
_cogl_path_get_bounds (path->path_nodes_min, path->path_nodes_max,
|
||||
&bounds_x, &bounds_y, &bounds_w, &bounds_h);
|
||||
|
||||
GE( glEnable (GL_STENCIL_TEST) );
|
||||
@ -222,12 +276,17 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
|
||||
}
|
||||
ctx->n_texcoord_arrays_enabled = 0;
|
||||
|
||||
while (path_start < path_size)
|
||||
while (path_start < path->path_size)
|
||||
{
|
||||
GE (glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
|
||||
(guint8 *) path
|
||||
+ G_STRUCT_OFFSET (CoglPathNode, x)));
|
||||
GE (glDrawArrays (GL_TRIANGLE_FAN, 0, path->path_size));
|
||||
CoglPathNode *node =
|
||||
&g_array_index (path->path_nodes, CoglPathNode, path_start);
|
||||
|
||||
GE (glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), &node->x));
|
||||
/* We need to limit the size of the sub path to the size of our
|
||||
path in case this path is a copy and the parent path has
|
||||
grown */
|
||||
GE (glDrawArrays (GL_TRIANGLE_FAN, 0,
|
||||
MIN (node->path_size, path->path_size - path_start)));
|
||||
|
||||
if (sub_path_num > 0)
|
||||
{
|
||||
@ -251,8 +310,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
|
||||
|
||||
GE (glStencilMask (merge ? 4 : 2));
|
||||
|
||||
path_start += path->path_size;
|
||||
path += path->path_size;
|
||||
path_start += node->path_size;
|
||||
sub_path_num++;
|
||||
}
|
||||
|
||||
@ -488,6 +546,7 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path,
|
||||
static void
|
||||
_cogl_path_fill_nodes (void)
|
||||
{
|
||||
CoglPath *path;
|
||||
float bounds_x;
|
||||
float bounds_y;
|
||||
float bounds_w;
|
||||
@ -495,7 +554,9 @@ _cogl_path_fill_nodes (void)
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
_cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max,
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
_cogl_path_get_bounds (path->path_nodes_min, path->path_nodes_max,
|
||||
&bounds_x, &bounds_y, &bounds_w, &bounds_h);
|
||||
|
||||
if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_FORCE_SCANLINE_PATHS)) &&
|
||||
@ -509,11 +570,7 @@ _cogl_path_fill_nodes (void)
|
||||
framebuffer = _cogl_get_framebuffer ();
|
||||
clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
|
||||
|
||||
_cogl_add_path_to_stencil_buffer (ctx->path_nodes_min,
|
||||
ctx->path_nodes_max,
|
||||
ctx->path_nodes->len,
|
||||
&g_array_index (ctx->path_nodes,
|
||||
CoglPathNode, 0),
|
||||
_cogl_add_path_to_stencil_buffer (ctx->current_path,
|
||||
clip_state->stencil_used,
|
||||
FALSE);
|
||||
|
||||
@ -535,17 +592,21 @@ _cogl_path_fill_nodes (void)
|
||||
{
|
||||
unsigned int path_start = 0;
|
||||
|
||||
while (path_start < ctx->path_nodes->len)
|
||||
while (path_start < path->path_size)
|
||||
{
|
||||
CoglPathNode *path = &g_array_index (ctx->path_nodes, CoglPathNode,
|
||||
CoglPathNode *node = &g_array_index (path->path_nodes, CoglPathNode,
|
||||
path_start);
|
||||
|
||||
_cogl_path_fill_nodes_scanlines (path,
|
||||
path->path_size,
|
||||
/* We need to limit the size of the sub path to the size of
|
||||
our path in case this path is a copy and the parent path
|
||||
has grown */
|
||||
_cogl_path_fill_nodes_scanlines (node,
|
||||
MIN (node->path_size,
|
||||
path->path_size - path_start),
|
||||
bounds_x, bounds_y,
|
||||
bounds_w, bounds_h);
|
||||
|
||||
path_start += path->path_size;
|
||||
path_start += node->path_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -563,7 +624,7 @@ cogl_path_fill_preserve (void)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (ctx->path_nodes->len == 0)
|
||||
if (COGL_PATH (ctx->current_path)->path_size == 0)
|
||||
return;
|
||||
|
||||
_cogl_path_fill_nodes ();
|
||||
@ -582,7 +643,7 @@ cogl_path_stroke_preserve (void)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (ctx->path_nodes->len == 0)
|
||||
if (COGL_PATH (ctx->current_path)->path_size == 0)
|
||||
return;
|
||||
|
||||
_cogl_path_stroke_nodes ();
|
||||
@ -592,57 +653,77 @@ void
|
||||
cogl_path_move_to (float x,
|
||||
float y)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
CoglPath *path;
|
||||
|
||||
/* FIXME: handle multiple contours maybe? */
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
_cogl_path_add_node (TRUE, x, y);
|
||||
|
||||
ctx->path_start.x = x;
|
||||
ctx->path_start.y = y;
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
ctx->path_pen = ctx->path_start;
|
||||
path->path_start.x = x;
|
||||
path->path_start.y = y;
|
||||
|
||||
path->path_pen = path->path_start;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_path_rel_move_to (float x,
|
||||
float y)
|
||||
{
|
||||
CoglPath *path;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
cogl_path_move_to (ctx->path_pen.x + x,
|
||||
ctx->path_pen.y + y);
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
cogl_path_move_to (path->path_pen.x + x,
|
||||
path->path_pen.y + y);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_path_line_to (float x,
|
||||
float y)
|
||||
{
|
||||
CoglPath *path;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
_cogl_path_add_node (FALSE, x, y);
|
||||
|
||||
ctx->path_pen.x = x;
|
||||
ctx->path_pen.y = y;
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
path->path_pen.x = x;
|
||||
path->path_pen.y = y;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_path_rel_line_to (float x,
|
||||
float y)
|
||||
{
|
||||
CoglPath *path;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
cogl_path_line_to (ctx->path_pen.x + x,
|
||||
ctx->path_pen.y + y);
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
cogl_path_line_to (path->path_pen.x + x,
|
||||
path->path_pen.y + y);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_path_close (void)
|
||||
{
|
||||
CoglPath *path;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
_cogl_path_add_node (FALSE, ctx->path_start.x, ctx->path_start.y);
|
||||
ctx->path_pen = ctx->path_start;
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
_cogl_path_add_node (FALSE, path->path_start.x,
|
||||
path->path_start.y);
|
||||
|
||||
path->path_pen = path->path_start;
|
||||
}
|
||||
|
||||
void
|
||||
@ -650,7 +731,8 @@ cogl_path_new (void)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
g_array_set_size (ctx->path_nodes, 0);
|
||||
cogl_handle_unref (ctx->current_path);
|
||||
ctx->current_path = _cogl_path_new ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -789,10 +871,14 @@ cogl_path_arc_rel (float center_x,
|
||||
float angle_2,
|
||||
float angle_step)
|
||||
{
|
||||
CoglPath *path;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
_cogl_path_arc (ctx->path_pen.x + center_x,
|
||||
ctx->path_pen.y + center_y,
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
_cogl_path_arc (path->path_pen.x + center_x,
|
||||
path->path_pen.y + center_y,
|
||||
radius_x, radius_y,
|
||||
angle_1, angle_2,
|
||||
angle_step, 0 /* no move */);
|
||||
@ -825,11 +911,14 @@ cogl_path_round_rectangle (float x_1,
|
||||
float radius,
|
||||
float arc_step)
|
||||
{
|
||||
CoglPath *path;
|
||||
float inner_width = x_2 - x_1 - radius * 2;
|
||||
float inner_height = y_2 - y_1 - radius * 2;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
cogl_path_move_to (x_1, y_1 + radius);
|
||||
cogl_path_arc_rel (radius, 0,
|
||||
radius, radius,
|
||||
@ -837,16 +926,16 @@ cogl_path_round_rectangle (float x_1,
|
||||
270,
|
||||
arc_step);
|
||||
|
||||
cogl_path_line_to (ctx->path_pen.x + inner_width,
|
||||
ctx->path_pen.y);
|
||||
cogl_path_line_to (path->path_pen.x + inner_width,
|
||||
path->path_pen.y);
|
||||
cogl_path_arc_rel (0, radius,
|
||||
radius, radius,
|
||||
-90,
|
||||
0,
|
||||
arc_step);
|
||||
|
||||
cogl_path_line_to (ctx->path_pen.x,
|
||||
ctx->path_pen.y + inner_height);
|
||||
cogl_path_line_to (path->path_pen.x,
|
||||
path->path_pen.y + inner_height);
|
||||
|
||||
cogl_path_arc_rel (-radius, 0,
|
||||
radius, radius,
|
||||
@ -854,8 +943,8 @@ cogl_path_round_rectangle (float x_1,
|
||||
90,
|
||||
arc_step);
|
||||
|
||||
cogl_path_line_to (ctx->path_pen.x - inner_width,
|
||||
ctx->path_pen.y);
|
||||
cogl_path_line_to (path->path_pen.x - inner_width,
|
||||
path->path_pen.y);
|
||||
cogl_path_arc_rel (0, -radius,
|
||||
radius, radius,
|
||||
90,
|
||||
@ -970,11 +1059,14 @@ cogl_path_curve_to (float x_1,
|
||||
float y_3)
|
||||
{
|
||||
CoglBezCubic cubic;
|
||||
CoglPath *path;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
/* Prepare cubic curve */
|
||||
cubic.p1 = ctx->path_pen;
|
||||
cubic.p1 = path->path_pen;
|
||||
cubic.p2.x = x_1;
|
||||
cubic.p2.y = y_1;
|
||||
cubic.p3.x = x_2;
|
||||
@ -987,7 +1079,7 @@ cogl_path_curve_to (float x_1,
|
||||
|
||||
/* Add last point */
|
||||
_cogl_path_add_node (FALSE, cubic.p4.x, cubic.p4.y);
|
||||
ctx->path_pen = cubic.p4;
|
||||
path->path_pen = cubic.p4;
|
||||
}
|
||||
|
||||
void
|
||||
@ -998,16 +1090,85 @@ cogl_path_rel_curve_to (float x_1,
|
||||
float x_3,
|
||||
float y_3)
|
||||
{
|
||||
CoglPath *path;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
cogl_path_curve_to (ctx->path_pen.x + x_1,
|
||||
ctx->path_pen.y + y_1,
|
||||
ctx->path_pen.x + x_2,
|
||||
ctx->path_pen.y + y_2,
|
||||
ctx->path_pen.x + x_3,
|
||||
ctx->path_pen.y + y_3);
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
cogl_path_curve_to (path->path_pen.x + x_1,
|
||||
path->path_pen.y + y_1,
|
||||
path->path_pen.x + x_2,
|
||||
path->path_pen.y + y_2,
|
||||
path->path_pen.x + x_3,
|
||||
path->path_pen.y + y_3);
|
||||
}
|
||||
|
||||
CoglHandle
|
||||
cogl_path_get (void)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
return ctx->current_path;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_path_set (CoglHandle handle)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (!cogl_is_path (handle))
|
||||
return;
|
||||
|
||||
/* Reference the new handle first in case it is the same as the old
|
||||
handle */
|
||||
cogl_handle_ref (handle);
|
||||
cogl_handle_unref (ctx->current_path);
|
||||
ctx->current_path = handle;
|
||||
}
|
||||
|
||||
CoglHandle
|
||||
_cogl_path_new (void)
|
||||
{
|
||||
CoglPath *path;
|
||||
|
||||
path = g_slice_new (CoglPath);
|
||||
path->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
|
||||
path->last_path = 0;
|
||||
path->parent_path = COGL_INVALID_HANDLE;
|
||||
path->path_size = 0;
|
||||
|
||||
return _cogl_path_handle_new (path);
|
||||
}
|
||||
|
||||
CoglHandle
|
||||
cogl_path_copy (CoglHandle handle)
|
||||
{
|
||||
CoglPath *old_path, *new_path;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
if (!cogl_is_path (handle))
|
||||
return COGL_INVALID_HANDLE;
|
||||
|
||||
old_path = COGL_PATH (handle);
|
||||
|
||||
new_path = g_slice_dup (CoglPath, old_path);
|
||||
new_path->parent_path = cogl_handle_ref (handle);
|
||||
|
||||
return _cogl_path_handle_new (new_path);
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_path_free (CoglPath *path)
|
||||
{
|
||||
if (path->parent_path)
|
||||
cogl_handle_unref (path->parent_path);
|
||||
else
|
||||
g_array_free (path->path_nodes, TRUE);
|
||||
|
||||
g_slice_free (CoglPath, path);
|
||||
}
|
||||
|
||||
/* If second order beziers were needed the following code could
|
||||
* be re-enabled:
|
||||
@ -1086,9 +1247,12 @@ cogl_path_curve2_to (float x_1,
|
||||
float x_2,
|
||||
float y_2)
|
||||
{
|
||||
CoglPath *path;
|
||||
CoglBezQuad quad;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
CoglBezQuad quad;
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
/* Prepare quadratic curve */
|
||||
quad.p1 = ctx->path_pen;
|
||||
@ -1102,7 +1266,7 @@ cogl_path_curve2_to (float x_1,
|
||||
|
||||
/* Add last point */
|
||||
_cogl_path_add_node (FALSE, quad.p3.x, quad.p3.y);
|
||||
ctx->path_pen = quad.p3;
|
||||
path->path_pen = quad.p3;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1111,11 +1275,16 @@ cogl_rel_curve2_to (float x_1,
|
||||
float x_2,
|
||||
float y_2)
|
||||
{
|
||||
CoglPath *path;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
cogl_path_curve2_to (ctx->path_pen.x + x_1,
|
||||
ctx->path_pen.y + y_1,
|
||||
ctx->path_pen.x + x_2,
|
||||
ctx->path_pen.y + y_2);
|
||||
path = COGL_PATH (ctx->current_path);
|
||||
|
||||
cogl_path_curve2_to (path->path_pen.x + x_1,
|
||||
path->path_pen.y + y_1,
|
||||
path->path_pen.x + x_2,
|
||||
path->path_pen.y + y_2);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -341,6 +341,52 @@ cogl_path_round_rectangle (float x_1,
|
||||
float radius,
|
||||
float arc_step);
|
||||
|
||||
/**
|
||||
* cogl_path_get:
|
||||
*
|
||||
* Gets a handle to the current path. The path can later be used again
|
||||
* by calling cogl_path_set(). Note that the path isn't copied so if
|
||||
* you later call any functions to add to the path it will affect the
|
||||
* returned handle too. No reference is taken on the path so if you
|
||||
* want to retain it you should take your own reference with
|
||||
* cogl_handle_ref().
|
||||
*
|
||||
* Return value: a handle to the current path.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
CoglHandle
|
||||
cogl_path_get (void);
|
||||
|
||||
/**
|
||||
* cogl_path_set:
|
||||
* @handle: A %CoglHandle to a path
|
||||
*
|
||||
* Replaces the current path with @handle. A reference is taken on the
|
||||
* handle so if you no longer need the path you should unref with
|
||||
* cogl_handle_unref().
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_path_set (CoglHandle handle);
|
||||
|
||||
/**
|
||||
* cogl_path_copy:
|
||||
* @handle: A %CoglHandle to a path
|
||||
*
|
||||
* Returns a new copy of the path in @handle. The new path has a
|
||||
* reference count of 1 so you should unref it with
|
||||
* cogl_handle_unref() if you no longer need it.
|
||||
*
|
||||
* Internally the path will share the data until one of the paths is
|
||||
* modified so copying paths should be relatively cheap.
|
||||
*
|
||||
* Return value: a copy of the path in @handle.
|
||||
*/
|
||||
CoglHandle
|
||||
cogl_path_copy (CoglHandle handle);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COGL_PATH_H__ */
|
||||
|
@ -155,6 +155,9 @@ cogl_polygon
|
||||
|
||||
<SUBSECTION>
|
||||
cogl_path_new
|
||||
cogl_path_get
|
||||
cogl_path_set
|
||||
cogl_path_copy
|
||||
cogl_path_move_to
|
||||
cogl_path_close
|
||||
cogl_path_line_to
|
||||
|
Loading…
Reference in New Issue
Block a user