| //---------------------------------------------------------------------------- | |
| // Anti-Grain Geometry - Version 2.3 | |
| // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) | |
| // | |
| // Permission to copy, use, modify, sell and distribute this software | |
| // is granted provided this copyright notice appears in all copies. | |
| // This software is provided "as is" without express or implied | |
| // warranty, and with no claim as to its suitability for any purpose. | |
| // | |
| //---------------------------------------------------------------------------- | |
| // Contact: mcseem@antigrain.com | |
| // mcseemagg@yahoo.com | |
| // http://www.antigrain.com | |
| //---------------------------------------------------------------------------- | |
| #ifndef AGG_PATH_STORAGE_INCLUDED | |
| #define AGG_PATH_STORAGE_INCLUDED | |
| #include "agg_basics.h" | |
| namespace agg | |
| { | |
| class path_storage | |
| { | |
| enum block_scale_e { | |
| block_shift = 8, | |
| block_size = 1 << block_shift, | |
| block_mask = block_size - 1, | |
| block_pool = 256 | |
| }; | |
| public: | |
| class vertex_source | |
| { | |
| public: | |
| vertex_source() {} | |
| vertex_source(const path_storage& p) : m_path(&p), m_vertex_idx(0) {} | |
| void rewind(unsigned path_id) | |
| { | |
| m_vertex_idx = path_id; | |
| } | |
| unsigned vertex(FX_FLOAT* x, FX_FLOAT* y) | |
| { | |
| return (m_vertex_idx < m_path->total_vertices()) | |
| ? m_path->vertex(m_vertex_idx++, x, y) | |
| : static_cast<unsigned>(path_cmd_stop); | |
| } | |
| private: | |
| const path_storage* m_path; | |
| unsigned m_vertex_idx; | |
| }; | |
| ~path_storage(); | |
| path_storage(); | |
| unsigned last_vertex(FX_FLOAT* x, FX_FLOAT* y) const; | |
| unsigned prev_vertex(FX_FLOAT* x, FX_FLOAT* y) const; | |
| void move_to(FX_FLOAT x, FX_FLOAT y); | |
| void line_to(FX_FLOAT x, FX_FLOAT y); | |
| void curve4(FX_FLOAT x_ctrl1, FX_FLOAT y_ctrl1, | |
| FX_FLOAT x_ctrl2, FX_FLOAT y_ctrl2, | |
| FX_FLOAT x_to, FX_FLOAT y_to); | |
| template<class VertexSource> | |
| void add_path(VertexSource& vs, | |
| unsigned path_id = 0, | |
| bool solid_path = true) | |
| { | |
| FX_FLOAT x, y; | |
| unsigned cmd; | |
| vs.rewind(path_id); | |
| while(!is_stop(cmd = vs.vertex(&x, &y))) { | |
| if(is_move_to(cmd) && solid_path && m_total_vertices) { | |
| cmd = path_cmd_line_to; | |
| } | |
| add_vertex(x, y, cmd); | |
| } | |
| } | |
| template<class VertexSource> | |
| void add_path_curve(VertexSource& vs, | |
| unsigned path_id = 0, | |
| bool solid_path = true) | |
| { | |
| FX_FLOAT x, y; | |
| unsigned cmd; | |
| int flag; | |
| vs.rewind(path_id); | |
| while(!is_stop(cmd = vs.vertex_curve_flag(&x, &y, flag))) { | |
| if(is_move_to(cmd) && solid_path && m_total_vertices) { | |
| cmd = path_cmd_line_to | flag; | |
| } | |
| add_vertex(x, y, cmd | flag); | |
| } | |
| } | |
| unsigned total_vertices() const | |
| { | |
| return m_total_vertices; | |
| } | |
| unsigned vertex(unsigned idx, FX_FLOAT* x, FX_FLOAT* y) const | |
| { | |
| unsigned nb = idx >> block_shift; | |
| const FX_FLOAT* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1); | |
| *x = *pv++; | |
| *y = *pv; | |
| return m_cmd_blocks[nb][idx & block_mask]; | |
| } | |
| unsigned command(unsigned idx) const | |
| { | |
| return m_cmd_blocks[idx >> block_shift][idx & block_mask]; | |
| } | |
| unsigned getflag(unsigned idx) const | |
| { | |
| return m_cmd_blocks[idx >> block_shift][idx & block_mask] & path_flags_jr; | |
| } | |
| void rewind(unsigned path_id); | |
| unsigned vertex(FX_FLOAT* x, FX_FLOAT* y); | |
| void add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd); | |
| void end_poly(); | |
| private: | |
| void allocate_block(unsigned nb); | |
| unsigned char* storage_ptrs(FX_FLOAT** xy_ptr); | |
| private: | |
| unsigned m_total_vertices; | |
| unsigned m_total_blocks; | |
| unsigned m_max_blocks; | |
| FX_FLOAT** m_coord_blocks; | |
| unsigned char** m_cmd_blocks; | |
| unsigned m_iterator; | |
| }; | |
| inline unsigned path_storage::vertex(FX_FLOAT* x, FX_FLOAT* y) | |
| { | |
| if(m_iterator >= m_total_vertices) { | |
| return path_cmd_stop; | |
| } | |
| return vertex(m_iterator++, x, y); | |
| } | |
| inline unsigned path_storage::prev_vertex(FX_FLOAT* x, FX_FLOAT* y) const | |
| { | |
| if(m_total_vertices > 1) { | |
| return vertex(m_total_vertices - 2, x, y); | |
| } | |
| return path_cmd_stop; | |
| } | |
| inline unsigned path_storage::last_vertex(FX_FLOAT* x, FX_FLOAT* y) const | |
| { | |
| if(m_total_vertices) { | |
| return vertex(m_total_vertices - 1, x, y); | |
| } | |
| return path_cmd_stop; | |
| } | |
| inline unsigned char* path_storage::storage_ptrs(FX_FLOAT** xy_ptr) | |
| { | |
| unsigned nb = m_total_vertices >> block_shift; | |
| if(nb >= m_total_blocks) { | |
| allocate_block(nb); | |
| } | |
| *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1); | |
| return m_cmd_blocks[nb] + (m_total_vertices & block_mask); | |
| } | |
| inline void path_storage::add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd) | |
| { | |
| FX_FLOAT* coord_ptr = 0; | |
| unsigned char* cmd_ptr = storage_ptrs(&coord_ptr); | |
| *cmd_ptr = (unsigned char)cmd; | |
| *coord_ptr++ = x; | |
| *coord_ptr = y; | |
| m_total_vertices++; | |
| } | |
| inline void path_storage::move_to(FX_FLOAT x, FX_FLOAT y) | |
| { | |
| add_vertex(x, y, path_cmd_move_to); | |
| } | |
| inline void path_storage::line_to(FX_FLOAT x, FX_FLOAT y) | |
| { | |
| add_vertex(x, y, path_cmd_line_to); | |
| } | |
| } | |
| #endif |