Home | History | Annotate | Download | only in agg23
      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 : public CFX_Object
     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 : public CFX_Object
     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                    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