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