summaryrefslogtreecommitdiff
path: root/core/src/fxge/agg/agg23/agg_path_storage.h
blob: dc13851d09f4344fa541c0239ce3f1a05f9f82de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

//----------------------------------------------------------------------------
// 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) :
                   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