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 (at) antigrain.com 13 // mcseemagg (at) 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: 33 vertex_source() {} 34 vertex_source(const path_storage& p) : m_path(&p), m_vertex_idx(0) {} 35 void rewind(unsigned path_id) 36 { 37 m_vertex_idx = path_id; 38 } 39 unsigned vertex(FX_FLOAT* x, FX_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(FX_FLOAT* x, FX_FLOAT* y) const; 52 unsigned prev_vertex(FX_FLOAT* x, FX_FLOAT* y) const; 53 void move_to(FX_FLOAT x, FX_FLOAT y); 54 void line_to(FX_FLOAT x, FX_FLOAT y); 55 void curve4(FX_FLOAT x_ctrl1, FX_FLOAT y_ctrl1, 56 FX_FLOAT x_ctrl2, FX_FLOAT y_ctrl2, 57 FX_FLOAT x_to, FX_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 FX_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 FX_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 } 89 unsigned total_vertices() const 90 { 91 return m_total_vertices; 92 } 93 unsigned vertex(unsigned idx, FX_FLOAT* x, FX_FLOAT* y) const 94 { 95 unsigned nb = idx >> block_shift; 96 const FX_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 } 101 unsigned command(unsigned idx) const 102 { 103 return m_cmd_blocks[idx >> block_shift][idx & block_mask]; 104 } 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(FX_FLOAT* x, FX_FLOAT* y); 111 void add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd); 112 void end_poly(); 113 private: 114 void allocate_block(unsigned nb); 115 unsigned char* storage_ptrs(FX_FLOAT** xy_ptr); 116 private: 117 unsigned m_total_vertices; 118 unsigned m_total_blocks; 119 unsigned m_max_blocks; 120 FX_FLOAT** m_coord_blocks; 121 unsigned char** m_cmd_blocks; 122 unsigned m_iterator; 123 }; 124 inline unsigned path_storage::vertex(FX_FLOAT* x, FX_FLOAT* y) 125 { 126 if(m_iterator >= m_total_vertices) { 127 return path_cmd_stop; 128 } 129 return vertex(m_iterator++, x, y); 130 } 131 inline unsigned path_storage::prev_vertex(FX_FLOAT* x, FX_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 } 138 inline unsigned path_storage::last_vertex(FX_FLOAT* x, FX_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 } 145 inline unsigned char* path_storage::storage_ptrs(FX_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 } 154 inline void path_storage::add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd) 155 { 156 FX_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 } 163 inline void path_storage::move_to(FX_FLOAT x, FX_FLOAT y) 164 { 165 add_vertex(x, y, path_cmd_move_to); 166 } 167 inline void path_storage::line_to(FX_FLOAT x, FX_FLOAT y) 168 { 169 add_vertex(x, y, path_cmd_line_to); 170 } 171 } 172 #endif 173