1 | #include <sstream> |
2 | #include <algorithm> |
3 | #include <list> |
4 | |
5 | #include "ostream_utility.hpp" |
6 | #include "read_path.hpp" |
7 | |
8 | namespace |
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 | |
52 | void |
53 | read_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 ¤t_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 ¤t_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 ¤t_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 | |