1//----------------------------------------------------------------------------
2// Anti-Grain Geometry - Version 2.4
3// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4//
5// Permission to copy, use, modify, sell and distribute this software
6// is granted provided this copyright notice appears in all copies.
7// This software is provided "as is" without express or implied
8// warranty, and with no claim as to its suitability for any purpose.
9//
10//----------------------------------------------------------------------------
11// Contact: mcseem@antigrain.com
12//          mcseemagg@yahoo.com
13//          http://www.antigrain.com
14//----------------------------------------------------------------------------
15
16#ifndef AGG_PATH_STORAGE_INTEGER_INCLUDED
17#define AGG_PATH_STORAGE_INTEGER_INCLUDED
18
19#include <string.h>
20#include "agg_array.h"
21
22namespace agg
23{
24    //---------------------------------------------------------vertex_integer
25    template<class T, unsigned CoordShift=6> struct vertex_integer
26    {
27        enum path_cmd
28        {
29            cmd_move_to = 0,
30            cmd_line_to = 1,
31            cmd_curve3  = 2,
32            cmd_curve4  = 3
33        };
34
35        enum coord_scale_e
36        {
37            coord_shift = CoordShift,
38            coord_scale  = 1 << coord_shift
39        };
40
41        T x,y;
42        vertex_integer() {}
43        vertex_integer(T x_, T y_, unsigned flag) :
44            x(((x_ << 1) & ~1) | (flag &  1)),
45            y(((y_ << 1) & ~1) | (flag >> 1)) {}
46
47        unsigned vertex(double* x_, double* y_,
48                        double dx=0, double dy=0,
49                        double scale=1.0) const
50        {
51            *x_ = dx + (double(x >> 1) / coord_scale) * scale;
52            *y_ = dy + (double(y >> 1) / coord_scale) * scale;
53            switch(((y & 1) << 1) | (x & 1))
54            {
55                case cmd_move_to: return path_cmd_move_to;
56                case cmd_line_to: return path_cmd_line_to;
57                case cmd_curve3:  return path_cmd_curve3;
58                case cmd_curve4:  return path_cmd_curve4;
59            }
60            return path_cmd_stop;
61        }
62    };
63
64
65    //---------------------------------------------------path_storage_integer
66    template<class T, unsigned CoordShift=6> class path_storage_integer
67    {
68    public:
69        typedef T value_type;
70        typedef vertex_integer<T, CoordShift> vertex_integer_type;
71
72        //--------------------------------------------------------------------
73        path_storage_integer() : m_storage(), m_vertex_idx(0), m_closed(true) {}
74
75        //--------------------------------------------------------------------
76        void remove_all() { m_storage.remove_all(); }
77
78        //--------------------------------------------------------------------
79        void move_to(T x, T y)
80        {
81            m_storage.add(vertex_integer_type(x, y, vertex_integer_type::cmd_move_to));
82        }
83
84        //--------------------------------------------------------------------
85        void line_to(T x, T y)
86        {
87            m_storage.add(vertex_integer_type(x, y, vertex_integer_type::cmd_line_to));
88        }
89
90        //--------------------------------------------------------------------
91        void curve3(T x_ctrl,  T y_ctrl,
92                    T x_to,    T y_to)
93        {
94            m_storage.add(vertex_integer_type(x_ctrl, y_ctrl, vertex_integer_type::cmd_curve3));
95            m_storage.add(vertex_integer_type(x_to,   y_to,   vertex_integer_type::cmd_curve3));
96        }
97
98        //--------------------------------------------------------------------
99        void curve4(T x_ctrl1, T y_ctrl1,
100                    T x_ctrl2, T y_ctrl2,
101                    T x_to,    T y_to)
102        {
103            m_storage.add(vertex_integer_type(x_ctrl1, y_ctrl1, vertex_integer_type::cmd_curve4));
104            m_storage.add(vertex_integer_type(x_ctrl2, y_ctrl2, vertex_integer_type::cmd_curve4));
105            m_storage.add(vertex_integer_type(x_to,    y_to,    vertex_integer_type::cmd_curve4));
106        }
107
108        //--------------------------------------------------------------------
109        void close_polygon() {}
110
111        //--------------------------------------------------------------------
112        unsigned size() const { return m_storage.size(); }
113        unsigned vertex(unsigned idx, double* x, double* y) const
114        {
115            return m_storage[idx].vertex(x, y);
116        }
117
118        //--------------------------------------------------------------------
119        unsigned byte_size() const { return m_storage.size() * sizeof(vertex_integer_type); }
120        void serialize(int8u* ptr) const
121        {
122            unsigned i;
123            for(i = 0; i < m_storage.size(); i++)
124            {
125                memcpy(ptr, &m_storage[i], sizeof(vertex_integer_type));
126                ptr += sizeof(vertex_integer_type);
127            }
128        }
129
130        //--------------------------------------------------------------------
131        void rewind(unsigned)
132        {
133            m_vertex_idx = 0;
134            m_closed = true;
135        }
136
137        //--------------------------------------------------------------------
138        unsigned vertex(double* x, double* y)
139        {
140            if(m_storage.size() < 2 || m_vertex_idx > m_storage.size())
141            {
142                *x = 0;
143                *y = 0;
144                return path_cmd_stop;
145            }
146            if(m_vertex_idx == m_storage.size())
147            {
148                *x = 0;
149                *y = 0;
150                ++m_vertex_idx;
151                return path_cmd_end_poly | path_flags_close;
152            }
153            unsigned cmd = m_storage[m_vertex_idx].vertex(x, y);
154            if(is_move_to(cmd) && !m_closed)
155            {
156                *x = 0;
157                *y = 0;
158                m_closed = true;
159                return path_cmd_end_poly | path_flags_close;
160            }
161            m_closed = false;
162            ++m_vertex_idx;
163            return cmd;
164        }
165
166        //--------------------------------------------------------------------
167        rect_d bounding_rect() const
168        {
169            rect_d bounds(1e100, 1e100, -1e100, -1e100);
170            if(m_storage.size() == 0)
171            {
172                bounds.x1 = bounds.y1 = bounds.x2 = bounds.y2 = 0.0;
173            }
174            else
175            {
176                unsigned i;
177                for(i = 0; i < m_storage.size(); i++)
178                {
179                    double x, y;
180                    m_storage[i].vertex(&x, &y);
181                    if(x < bounds.x1) bounds.x1 = x;
182                    if(y < bounds.y1) bounds.y1 = y;
183                    if(x > bounds.x2) bounds.x2 = x;
184                    if(y > bounds.y2) bounds.y2 = y;
185                }
186            }
187            return bounds;
188        }
189
190    private:
191        pod_bvector<vertex_integer_type, 6> m_storage;
192        unsigned                            m_vertex_idx;
193        bool                                m_closed;
194    };
195
196
197
198
199    //-----------------------------------------serialized_integer_path_adaptor
200    template<class T, unsigned CoordShift=6> class serialized_integer_path_adaptor
201    {
202    public:
203        typedef vertex_integer<T, CoordShift> vertex_integer_type;
204
205        //--------------------------------------------------------------------
206        serialized_integer_path_adaptor() :
207            m_data(0),
208            m_end(0),
209            m_ptr(0),
210            m_dx(0.0),
211            m_dy(0.0),
212            m_scale(1.0),
213            m_vertices(0)
214        {}
215
216        //--------------------------------------------------------------------
217        serialized_integer_path_adaptor(const int8u* data, unsigned size,
218                                        double dx, double dy) :
219            m_data(data),
220            m_end(data + size),
221            m_ptr(data),
222            m_dx(dx),
223            m_dy(dy),
224            m_vertices(0)
225        {}
226
227        //--------------------------------------------------------------------
228        void init(const int8u* data, unsigned size,
229                  double dx, double dy, double scale=1.0)
230        {
231            m_data     = data;
232            m_end      = data + size;
233            m_ptr      = data;
234            m_dx       = dx;
235            m_dy       = dy;
236            m_scale    = scale;
237            m_vertices = 0;
238        }
239
240
241        //--------------------------------------------------------------------
242        void rewind(unsigned)
243        {
244            m_ptr      = m_data;
245            m_vertices = 0;
246        }
247
248        //--------------------------------------------------------------------
249        unsigned vertex(double* x, double* y)
250        {
251            if(m_data == 0 || m_ptr > m_end)
252            {
253                *x = 0;
254                *y = 0;
255                return path_cmd_stop;
256            }
257
258            if(m_ptr == m_end)
259            {
260                *x = 0;
261                *y = 0;
262                m_ptr += sizeof(vertex_integer_type);
263                return path_cmd_end_poly | path_flags_close;
264            }
265
266            vertex_integer_type v;
267            memcpy(&v, m_ptr, sizeof(vertex_integer_type));
268            unsigned cmd = v.vertex(x, y, m_dx, m_dy, m_scale);
269            if(is_move_to(cmd) && m_vertices > 2)
270            {
271                *x = 0;
272                *y = 0;
273                m_vertices = 0;
274                return path_cmd_end_poly | path_flags_close;
275            }
276            ++m_vertices;
277            m_ptr += sizeof(vertex_integer_type);
278            return cmd;
279        }
280
281    private:
282        const int8u* m_data;
283        const int8u* m_end;
284        const int8u* m_ptr;
285        double       m_dx;
286        double       m_dy;
287        double       m_scale;
288        unsigned     m_vertices;
289    };
290
291}
292
293
294#endif
295
296