1#include <sstream>
2#include <algorithm>
3#include <list>
4
5#include "ostream_utility.hpp"
6#include "read_path.hpp"
7
8namespace
9{
10 enum arc_mode_t
11 {
12 not_arc,
13 arc
14 };
15
16 enum add_mode_t
17 {
18 add_mode,
19 add_reverse_mode,
20 add_no_mode,
21 };
22
23 class edge
24 {
25 public:
26 edge(const fastuidraw::vec2 &pt):
27 m_pt(pt),
28 m_arc_mode(not_arc),
29 m_angle(0.0f)
30 {}
31
32 /*
33 m_pt is the starting point of the edge
34 and the rest of the data describe how
35 to interpolate -to- the next point.
36 */
37 fastuidraw::vec2 m_pt;
38 std::vector<fastuidraw::vec2> m_control_pts;
39 enum arc_mode_t m_arc_mode;
40 float m_angle;
41 };
42
43 class outline:public std::vector<edge>
44 {
45 public:
46 bool m_is_closed;
47 };
48}
49
50
51
52void
53read_path(fastuidraw::Path &path, const std::string &source,
54 std::string *dst_cpp_code)
55{
56 std::string filtered(source);
57
58 std::replace(filtered.begin(), filtered.end(), '(', ' ');
59 std::replace(filtered.begin(), filtered.end(), ')', ' ');
60 std::replace(filtered.begin(), filtered.end(), ',', ' ');
61 std::istringstream istr(filtered);
62
63 bool adding_control_pts(false);
64 std::list<outline> data;
65 enum arc_mode_t arc_mode(not_arc);
66 enum add_mode_t mode(add_no_mode);
67 fastuidraw::vec2 current_value;
68 int current_slot(0);
69 std::ostringstream cpp_code;
70
71 /*
72 this is so hideous.
73 */
74 while(istr)
75 {
76 std::string token;
77 istr >> token;
78 if (!istr.fail())
79 {
80 if (token == "]" || token == "}")
81 {
82 if (mode == add_reverse_mode && !data.empty())
83 {
84 std::reverse(data.back().begin(), data.back().end());
85 }
86 mode = add_no_mode;
87 }
88 else if (token == "[" || token == "{")
89 {
90 mode = add_mode;
91 adding_control_pts = false;
92 data.push_back(outline());
93 data.back().m_is_closed = (token == "[");
94 }
95 else if (token == "R[")
96 {
97 mode = add_reverse_mode;
98 adding_control_pts = false;
99 data.push_back(outline());
100 }
101 else if (token == "[[")
102 {
103 adding_control_pts = true;
104 }
105 else if (token == "]]")
106 {
107 adding_control_pts = false;
108 }
109 else if (token == "arc")
110 {
111 arc_mode = arc;
112 }
113 else
114 {
115 /* not a funky token so should be a number.
116 */
117 float number;
118 std::istringstream token_istr(token);
119 token_istr >> number;
120 if (!token_istr.fail())
121 {
122 if (arc_mode != not_arc)
123 {
124 data.back().back().m_angle = number;
125 data.back().back().m_arc_mode = arc_mode;
126 arc_mode = not_arc;
127 }
128 else
129 {
130 current_value[current_slot] = number;
131 if (current_slot == 1)
132 {
133 /* just finished reading a vec2 */
134 current_slot = 0;
135 if (!adding_control_pts)
136 {
137 data.back().push_back(current_value);
138 }
139 else if (!data.empty() && !data.back().empty())
140 {
141 data.back().back().m_control_pts.push_back(current_value);
142 }
143 }
144 else
145 {
146 FASTUIDRAWassert(current_slot == 0);
147 current_slot = 1;
148 }
149 }
150 }
151 }
152 }
153 }
154
155 /* now walk the list of outlines.
156 */
157 bool draw_space(false);
158 for(std::list<outline>::const_iterator iter = data.begin(), end = data.end();
159 iter != end; ++iter)
160 {
161 const outline &current_outline(*iter);
162
163 if (!current_outline.empty())
164 {
165 path << fastuidraw::Path::contour_start(current_outline[0].m_pt);
166 if (!draw_space)
167 {
168 draw_space = true;
169 cpp_code << "path";
170 }
171 else
172 {
173 cpp_code << " ";
174 }
175 cpp_code << " << fastuidraw::Path::contour_start(fastuidraw::vec2"
176 << current_outline[0].m_pt << ")\n";
177 for(unsigned int i = 0; i + 1 < current_outline.size(); ++i)
178 {
179 const edge &current_edge(current_outline[i]);
180 const edge &next_edge(current_outline[i+1]);
181
182 if (current_edge.m_arc_mode == not_arc)
183 {
184 for(unsigned int c = 0; c < current_edge.m_control_pts.size(); ++c)
185 {
186 path << fastuidraw::Path::control_point(current_edge.m_control_pts[c]);
187 cpp_code << " << fastuidraw::Path::control_point(fastuidraw::vec2"
188 << current_edge.m_control_pts[c] << ")\n";
189 }
190 path << next_edge.m_pt;
191 cpp_code << " << fastuidraw::vec2" << next_edge.m_pt << "\n";
192 }
193 else
194 {
195 path << fastuidraw::Path::arc_degrees(current_edge.m_angle, next_edge.m_pt);
196 cpp_code << " << fastuidraw::Path::arc_degrees("
197 << current_edge.m_angle << ", fastuidraw::vec2"
198 << next_edge.m_pt << ")\n";
199 }
200 }
201
202 const edge &current_edge(current_outline.back());
203 if (current_edge.m_arc_mode == not_arc)
204 {
205 for(unsigned int c = 0; c < current_edge.m_control_pts.size(); ++c)
206 {
207 path << fastuidraw::Path::control_point(current_edge.m_control_pts[c]);
208 cpp_code << " << fastuidraw::Path::control_point(fastuidraw::vec2"
209 << current_edge.m_control_pts[c] << ")\n";
210 }
211
212 if (current_outline.m_is_closed)
213 {
214 path << fastuidraw::Path::contour_close();
215 cpp_code << " << fastuidraw::Path::contour_close()\n";
216 }
217 else
218 {
219 path << fastuidraw::Path::contour_end();
220 cpp_code << " << fastuidraw::Path::contour_end()\n";
221 }
222 }
223 else
224 {
225 if (current_outline.m_is_closed)
226 {
227 path << fastuidraw::Path::contour_close_arc_degrees(current_edge.m_angle);
228 cpp_code << " << fastuidraw::Path::contour_close_arc_degrees("
229 << current_edge.m_angle << ")\n";
230 }
231 }
232 }
233 }
234
235 cpp_code << " ;\n";
236 if (dst_cpp_code)
237 {
238 *dst_cpp_code = cpp_code.str();
239 }
240}
241