1
2 //----------------------------------------------------------------------------
3 // Anti-Grain Geometry - Version 2.3
4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
5 //
6 // Permission to copy, use, modify, sell and distribute this software
7 // is granted provided this copyright notice appears in all copies.
8 // This software is provided "as is" without express or implied
9 // warranty, and with no claim as to its suitability for any purpose.
10 //
11 //----------------------------------------------------------------------------
12 // Contact: mcseem@antigrain.com
13 // mcseemagg@yahoo.com
14 // http://www.antigrain.com
15 //----------------------------------------------------------------------------
16 #ifndef AGG_PATH_STORAGE_INCLUDED
17 #define AGG_PATH_STORAGE_INCLUDED
18 #include "agg_basics.h"
19 namespace agg
20 {
21 class path_storage
22 {
23 enum block_scale_e {
24 block_shift = 8,
25 block_size = 1 << block_shift,
26 block_mask = block_size - 1,
27 block_pool = 256
28 };
29 public:
30 class vertex_source
31 {
32 public:
vertex_source()33 vertex_source() {}
vertex_source(const path_storage & p)34 vertex_source(const path_storage& p) : m_path(&p), m_vertex_idx(0) {}
rewind(unsigned path_id)35 void rewind(unsigned path_id)
36 {
37 m_vertex_idx = path_id;
38 }
vertex(float * x,float * y)39 unsigned vertex(float* x, float* y)
40 {
41 return (m_vertex_idx < m_path->total_vertices())
42 ? m_path->vertex(m_vertex_idx++, x, y)
43 : static_cast<unsigned>(path_cmd_stop);
44 }
45 private:
46 const path_storage* m_path;
47 unsigned m_vertex_idx;
48 };
49 ~path_storage();
50 path_storage();
51 unsigned last_vertex(float* x, float* y) const;
52 unsigned prev_vertex(float* x, float* y) const;
53 void move_to(float x, float y);
54 void line_to(float x, float y);
55 void curve4(float x_ctrl1, float y_ctrl1,
56 float x_ctrl2, float y_ctrl2,
57 float x_to, float y_to);
58 template<class VertexSource>
59 void add_path(VertexSource& vs,
60 unsigned path_id = 0,
61 bool solid_path = true)
62 {
63 float x, y;
64 unsigned cmd;
65 vs.rewind(path_id);
66 while(!is_stop(cmd = vs.vertex(&x, &y))) {
67 if(is_move_to(cmd) && solid_path && m_total_vertices) {
68 cmd = path_cmd_line_to;
69 }
70 add_vertex(x, y, cmd);
71 }
72 }
73 template<class VertexSource>
74 void add_path_curve(VertexSource& vs,
75 unsigned path_id = 0,
76 bool solid_path = true)
77 {
78 float x, y;
79 unsigned cmd;
80 int flag;
81 vs.rewind(path_id);
82 while(!is_stop(cmd = vs.vertex_curve_flag(&x, &y, flag))) {
83 if(is_move_to(cmd) && solid_path && m_total_vertices) {
84 cmd = path_cmd_line_to | flag;
85 }
86 add_vertex(x, y, cmd | flag);
87 }
88 }
total_vertices()89 unsigned total_vertices() const
90 {
91 return m_total_vertices;
92 }
vertex(unsigned idx,float * x,float * y)93 unsigned vertex(unsigned idx, float* x, float* y) const
94 {
95 unsigned nb = idx >> block_shift;
96 const float* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1);
97 *x = *pv++;
98 *y = *pv;
99 return m_cmd_blocks[nb][idx & block_mask];
100 }
command(unsigned idx)101 unsigned command(unsigned idx) const
102 {
103 return m_cmd_blocks[idx >> block_shift][idx & block_mask];
104 }
getflag(unsigned idx)105 unsigned getflag(unsigned idx) const
106 {
107 return m_cmd_blocks[idx >> block_shift][idx & block_mask] & path_flags_jr;
108 }
109 void rewind(unsigned path_id);
110 unsigned vertex(float* x, float* y);
111 void add_vertex(float x, float y, unsigned cmd);
112 void end_poly();
113 private:
114 void allocate_block(unsigned nb);
115 unsigned char* storage_ptrs(float** xy_ptr);
116 private:
117 unsigned m_total_vertices;
118 unsigned m_total_blocks;
119 unsigned m_max_blocks;
120 float** m_coord_blocks;
121 unsigned char** m_cmd_blocks;
122 unsigned m_iterator;
123 };
vertex(float * x,float * y)124 inline unsigned path_storage::vertex(float* x, float* y)
125 {
126 if(m_iterator >= m_total_vertices) {
127 return path_cmd_stop;
128 }
129 return vertex(m_iterator++, x, y);
130 }
prev_vertex(float * x,float * y)131 inline unsigned path_storage::prev_vertex(float* x, float* y) const
132 {
133 if(m_total_vertices > 1) {
134 return vertex(m_total_vertices - 2, x, y);
135 }
136 return path_cmd_stop;
137 }
last_vertex(float * x,float * y)138 inline unsigned path_storage::last_vertex(float* x, float* y) const
139 {
140 if(m_total_vertices) {
141 return vertex(m_total_vertices - 1, x, y);
142 }
143 return path_cmd_stop;
144 }
storage_ptrs(float ** xy_ptr)145 inline unsigned char* path_storage::storage_ptrs(float** xy_ptr)
146 {
147 unsigned nb = m_total_vertices >> block_shift;
148 if(nb >= m_total_blocks) {
149 allocate_block(nb);
150 }
151 *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1);
152 return m_cmd_blocks[nb] + (m_total_vertices & block_mask);
153 }
add_vertex(float x,float y,unsigned cmd)154 inline void path_storage::add_vertex(float x, float y, unsigned cmd)
155 {
156 float* coord_ptr = 0;
157 unsigned char* cmd_ptr = storage_ptrs(&coord_ptr);
158 *cmd_ptr = (unsigned char)cmd;
159 *coord_ptr++ = x;
160 *coord_ptr = y;
161 m_total_vertices++;
162 }
move_to(float x,float y)163 inline void path_storage::move_to(float x, float y)
164 {
165 add_vertex(x, y, path_cmd_move_to);
166 }
line_to(float x,float y)167 inline void path_storage::line_to(float x, float y)
168 {
169 add_vertex(x, y, path_cmd_line_to);
170 }
171 }
172 #endif
173