diff options
Diffstat (limited to 'apps/plugins/puzzles/src/drawing.c')
-rw-r--r-- | apps/plugins/puzzles/src/drawing.c | 212 |
1 files changed, 130 insertions, 82 deletions
diff --git a/apps/plugins/puzzles/src/drawing.c b/apps/plugins/puzzles/src/drawing.c index a8eb8cfd5f..a754b068f3 100644 --- a/apps/plugins/puzzles/src/drawing.c +++ b/apps/plugins/puzzles/src/drawing.c | |||
@@ -27,7 +27,11 @@ | |||
27 | #include <stdlib.h> | 27 | #include <stdlib.h> |
28 | #include <string.h> | 28 | #include <string.h> |
29 | #include <assert.h> | 29 | #include <assert.h> |
30 | #include <math.h> | 30 | #ifdef NO_TGMATH_H |
31 | # include <math.h> | ||
32 | #else | ||
33 | # include <tgmath.h> | ||
34 | #endif | ||
31 | 35 | ||
32 | #include "puzzles.h" | 36 | #include "puzzles.h" |
33 | 37 | ||
@@ -38,9 +42,12 @@ struct print_colour { | |||
38 | float grey; | 42 | float grey; |
39 | }; | 43 | }; |
40 | 44 | ||
41 | struct drawing { | 45 | typedef struct drawing_internal { |
42 | const drawing_api *api; | 46 | /* we implement data hiding by casting `struct drawing*` pointers |
43 | void *handle; | 47 | * to `struct drawing_internal*` */ |
48 | struct drawing pub; | ||
49 | |||
50 | /* private data */ | ||
44 | struct print_colour *colours; | 51 | struct print_colour *colours; |
45 | int ncolours, coloursize; | 52 | int ncolours, coloursize; |
46 | float scale; | 53 | float scale; |
@@ -48,61 +55,78 @@ struct drawing { | |||
48 | * this may set it to NULL. */ | 55 | * this may set it to NULL. */ |
49 | midend *me; | 56 | midend *me; |
50 | char *laststatus; | 57 | char *laststatus; |
51 | }; | 58 | } drawing_internal; |
59 | |||
60 | #define PRIVATE_CAST(dr) ((drawing_internal*)(dr)) | ||
61 | #define PUBLIC_CAST(dri) ((drawing*)(dri)) | ||
62 | |||
63 | /* See puzzles.h for a description of the version number. */ | ||
64 | #define DRAWING_API_VERSION 1 | ||
52 | 65 | ||
53 | drawing *drawing_new(const drawing_api *api, midend *me, void *handle) | 66 | drawing *drawing_new(const drawing_api *api, midend *me, void *handle) |
54 | { | 67 | { |
55 | drawing *dr = snew(drawing); | 68 | if(api->version != DRAWING_API_VERSION) { |
56 | dr->api = api; | 69 | fatal("Drawing API version mismatch: expected: %d, actual: %d\n", DRAWING_API_VERSION, api->version); |
57 | dr->handle = handle; | 70 | /* shouldn't get here */ |
58 | dr->colours = NULL; | 71 | return NULL; |
59 | dr->ncolours = dr->coloursize = 0; | 72 | } |
60 | dr->scale = 1.0F; | 73 | |
61 | dr->me = me; | 74 | drawing_internal *dri = snew(drawing_internal); |
62 | dr->laststatus = NULL; | 75 | dri->pub.api = api; |
63 | return dr; | 76 | dri->pub.handle = handle; |
77 | dri->colours = NULL; | ||
78 | dri->ncolours = dri->coloursize = 0; | ||
79 | dri->scale = 1.0F; | ||
80 | dri->me = me; | ||
81 | dri->laststatus = NULL; | ||
82 | return PUBLIC_CAST(dri); | ||
64 | } | 83 | } |
65 | 84 | ||
66 | void drawing_free(drawing *dr) | 85 | void drawing_free(drawing *dr) |
67 | { | 86 | { |
68 | sfree(dr->laststatus); | 87 | drawing_internal *dri = PRIVATE_CAST(dr); |
69 | sfree(dr->colours); | 88 | sfree(dri->laststatus); |
70 | sfree(dr); | 89 | sfree(dri->colours); |
90 | sfree(dri); | ||
71 | } | 91 | } |
72 | 92 | ||
73 | void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, | 93 | void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, |
74 | int align, int colour, const char *text) | 94 | int align, int colour, const char *text) |
75 | { | 95 | { |
76 | dr->api->draw_text(dr->handle, x, y, fonttype, fontsize, align, | 96 | drawing_internal *dri = PRIVATE_CAST(dr); |
77 | colour, text); | 97 | dri->pub.api->draw_text(dr, x, y, fonttype, fontsize, align, |
98 | colour, text); | ||
78 | } | 99 | } |
79 | 100 | ||
80 | void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) | 101 | void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) |
81 | { | 102 | { |
82 | dr->api->draw_rect(dr->handle, x, y, w, h, colour); | 103 | drawing_internal *dri = PRIVATE_CAST(dr); |
104 | dri->pub.api->draw_rect(dr, x, y, w, h, colour); | ||
83 | } | 105 | } |
84 | 106 | ||
85 | void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) | 107 | void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) |
86 | { | 108 | { |
87 | dr->api->draw_line(dr->handle, x1, y1, x2, y2, colour); | 109 | drawing_internal *dri = PRIVATE_CAST(dr); |
110 | dri->pub.api->draw_line(dr, x1, y1, x2, y2, colour); | ||
88 | } | 111 | } |
89 | 112 | ||
90 | void draw_thick_line(drawing *dr, float thickness, | 113 | void draw_thick_line(drawing *dr, float thickness, |
91 | float x1, float y1, float x2, float y2, int colour) | 114 | float x1, float y1, float x2, float y2, int colour) |
92 | { | 115 | { |
93 | if (thickness < 1.0) | 116 | drawing_internal *dri = PRIVATE_CAST(dr); |
94 | thickness = 1.0; | 117 | if (thickness < 1.0F) |
95 | if (dr->api->draw_thick_line) { | 118 | thickness = 1.0F; |
96 | dr->api->draw_thick_line(dr->handle, thickness, | 119 | if (dri->pub.api->draw_thick_line) { |
97 | x1, y1, x2, y2, colour); | 120 | dri->pub.api->draw_thick_line(dr, thickness, |
121 | x1, y1, x2, y2, colour); | ||
98 | } else { | 122 | } else { |
99 | /* We'll fake it up with a filled polygon. The tweak to the | 123 | /* We'll fake it up with a filled polygon. The tweak to the |
100 | * thickness empirically compensates for rounding errors, because | 124 | * thickness empirically compensates for rounding errors, because |
101 | * polygon rendering uses integer coordinates. | 125 | * polygon rendering uses integer coordinates. |
102 | */ | 126 | */ |
103 | float len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); | 127 | float len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); |
104 | float tvhatx = (x2 - x1)/len * (thickness/2 - 0.2); | 128 | float tvhatx = (x2 - x1)/len * (thickness/2 - 0.2F); |
105 | float tvhaty = (y2 - y1)/len * (thickness/2 - 0.2); | 129 | float tvhaty = (y2 - y1)/len * (thickness/2 - 0.2F); |
106 | int p[8]; | 130 | int p[8]; |
107 | 131 | ||
108 | p[0] = x1 - tvhaty; | 132 | p[0] = x1 - tvhaty; |
@@ -113,59 +137,67 @@ void draw_thick_line(drawing *dr, float thickness, | |||
113 | p[5] = y2 - tvhatx; | 137 | p[5] = y2 - tvhatx; |
114 | p[6] = x1 + tvhaty; | 138 | p[6] = x1 + tvhaty; |
115 | p[7] = y1 - tvhatx; | 139 | p[7] = y1 - tvhatx; |
116 | dr->api->draw_polygon(dr->handle, p, 4, colour, colour); | 140 | dri->pub.api->draw_polygon(dr, p, 4, colour, colour); |
117 | } | 141 | } |
118 | } | 142 | } |
119 | 143 | ||
120 | void draw_polygon(drawing *dr, int *coords, int npoints, | 144 | void draw_polygon(drawing *dr, const int *coords, int npoints, |
121 | int fillcolour, int outlinecolour) | 145 | int fillcolour, int outlinecolour) |
122 | { | 146 | { |
123 | dr->api->draw_polygon(dr->handle, coords, npoints, fillcolour, | 147 | drawing_internal *dri = PRIVATE_CAST(dr); |
124 | outlinecolour); | 148 | dri->pub.api->draw_polygon(dr, coords, npoints, fillcolour, |
149 | outlinecolour); | ||
125 | } | 150 | } |
126 | 151 | ||
127 | void draw_circle(drawing *dr, int cx, int cy, int radius, | 152 | void draw_circle(drawing *dr, int cx, int cy, int radius, |
128 | int fillcolour, int outlinecolour) | 153 | int fillcolour, int outlinecolour) |
129 | { | 154 | { |
130 | dr->api->draw_circle(dr->handle, cx, cy, radius, fillcolour, | 155 | drawing_internal *dri = PRIVATE_CAST(dr); |
131 | outlinecolour); | 156 | dri->pub.api->draw_circle(dr, cx, cy, radius, fillcolour, |
157 | outlinecolour); | ||
132 | } | 158 | } |
133 | 159 | ||
134 | void draw_update(drawing *dr, int x, int y, int w, int h) | 160 | void draw_update(drawing *dr, int x, int y, int w, int h) |
135 | { | 161 | { |
136 | if (dr->api->draw_update) | 162 | drawing_internal *dri = PRIVATE_CAST(dr); |
137 | dr->api->draw_update(dr->handle, x, y, w, h); | 163 | if (dri->pub.api->draw_update) |
164 | dri->pub.api->draw_update(dr, x, y, w, h); | ||
138 | } | 165 | } |
139 | 166 | ||
140 | void clip(drawing *dr, int x, int y, int w, int h) | 167 | void clip(drawing *dr, int x, int y, int w, int h) |
141 | { | 168 | { |
142 | dr->api->clip(dr->handle, x, y, w, h); | 169 | drawing_internal *dri = PRIVATE_CAST(dr); |
170 | dri->pub.api->clip(dr, x, y, w, h); | ||
143 | } | 171 | } |
144 | 172 | ||
145 | void unclip(drawing *dr) | 173 | void unclip(drawing *dr) |
146 | { | 174 | { |
147 | dr->api->unclip(dr->handle); | 175 | drawing_internal *dri = PRIVATE_CAST(dr); |
176 | dri->pub.api->unclip(dr); | ||
148 | } | 177 | } |
149 | 178 | ||
150 | void start_draw(drawing *dr) | 179 | void start_draw(drawing *dr) |
151 | { | 180 | { |
152 | dr->api->start_draw(dr->handle); | 181 | drawing_internal *dri = PRIVATE_CAST(dr); |
182 | dri->pub.api->start_draw(dr); | ||
153 | } | 183 | } |
154 | 184 | ||
155 | void end_draw(drawing *dr) | 185 | void end_draw(drawing *dr) |
156 | { | 186 | { |
157 | dr->api->end_draw(dr->handle); | 187 | drawing_internal *dri = PRIVATE_CAST(dr); |
188 | dri->pub.api->end_draw(dr); | ||
158 | } | 189 | } |
159 | 190 | ||
160 | char *text_fallback(drawing *dr, const char *const *strings, int nstrings) | 191 | char *text_fallback(drawing *dr, const char *const *strings, int nstrings) |
161 | { | 192 | { |
193 | drawing_internal *dri = PRIVATE_CAST(dr); | ||
162 | int i; | 194 | int i; |
163 | 195 | ||
164 | /* | 196 | /* |
165 | * If the drawing implementation provides one of these, use it. | 197 | * If the drawing implementation provides one of these, use it. |
166 | */ | 198 | */ |
167 | if (dr && dr->api->text_fallback) | 199 | if (dr && dri->pub.api->text_fallback) |
168 | return dr->api->text_fallback(dr->handle, strings, nstrings); | 200 | return dri->pub.api->text_fallback(dr, strings, nstrings); |
169 | 201 | ||
170 | /* | 202 | /* |
171 | * Otherwise, do the simple thing and just pick the first string | 203 | * Otherwise, do the simple thing and just pick the first string |
@@ -192,18 +224,19 @@ char *text_fallback(drawing *dr, const char *const *strings, int nstrings) | |||
192 | 224 | ||
193 | void status_bar(drawing *dr, const char *text) | 225 | void status_bar(drawing *dr, const char *text) |
194 | { | 226 | { |
227 | drawing_internal *dri = PRIVATE_CAST(dr); | ||
195 | char *rewritten; | 228 | char *rewritten; |
196 | 229 | ||
197 | if (!dr->api->status_bar) | 230 | if (!dri->pub.api->status_bar) |
198 | return; | 231 | return; |
199 | 232 | ||
200 | assert(dr->me); | 233 | assert(dri->me); |
201 | 234 | ||
202 | rewritten = midend_rewrite_statusbar(dr->me, text); | 235 | rewritten = midend_rewrite_statusbar(dri->me, text); |
203 | if (!dr->laststatus || strcmp(rewritten, dr->laststatus)) { | 236 | if (!dri->laststatus || strcmp(rewritten, dri->laststatus)) { |
204 | dr->api->status_bar(dr->handle, rewritten); | 237 | dri->pub.api->status_bar(dr, rewritten); |
205 | sfree(dr->laststatus); | 238 | sfree(dri->laststatus); |
206 | dr->laststatus = rewritten; | 239 | dri->laststatus = rewritten; |
207 | } else { | 240 | } else { |
208 | sfree(rewritten); | 241 | sfree(rewritten); |
209 | } | 242 | } |
@@ -211,74 +244,85 @@ void status_bar(drawing *dr, const char *text) | |||
211 | 244 | ||
212 | blitter *blitter_new(drawing *dr, int w, int h) | 245 | blitter *blitter_new(drawing *dr, int w, int h) |
213 | { | 246 | { |
214 | return dr->api->blitter_new(dr->handle, w, h); | 247 | drawing_internal *dri = PRIVATE_CAST(dr); |
248 | return dri->pub.api->blitter_new(dr, w, h); | ||
215 | } | 249 | } |
216 | 250 | ||
217 | void blitter_free(drawing *dr, blitter *bl) | 251 | void blitter_free(drawing *dr, blitter *bl) |
218 | { | 252 | { |
219 | dr->api->blitter_free(dr->handle, bl); | 253 | drawing_internal *dri = PRIVATE_CAST(dr); |
254 | dri->pub.api->blitter_free(dr, bl); | ||
220 | } | 255 | } |
221 | 256 | ||
222 | void blitter_save(drawing *dr, blitter *bl, int x, int y) | 257 | void blitter_save(drawing *dr, blitter *bl, int x, int y) |
223 | { | 258 | { |
224 | dr->api->blitter_save(dr->handle, bl, x, y); | 259 | drawing_internal *dri = PRIVATE_CAST(dr); |
260 | dri->pub.api->blitter_save(dr, bl, x, y); | ||
225 | } | 261 | } |
226 | 262 | ||
227 | void blitter_load(drawing *dr, blitter *bl, int x, int y) | 263 | void blitter_load(drawing *dr, blitter *bl, int x, int y) |
228 | { | 264 | { |
229 | dr->api->blitter_load(dr->handle, bl, x, y); | 265 | drawing_internal *dri = PRIVATE_CAST(dr); |
266 | dri->pub.api->blitter_load(dr, bl, x, y); | ||
230 | } | 267 | } |
231 | 268 | ||
232 | void print_begin_doc(drawing *dr, int pages) | 269 | void print_begin_doc(drawing *dr, int pages) |
233 | { | 270 | { |
234 | dr->api->begin_doc(dr->handle, pages); | 271 | drawing_internal *dri = PRIVATE_CAST(dr); |
272 | dri->pub.api->begin_doc(dr, pages); | ||
235 | } | 273 | } |
236 | 274 | ||
237 | void print_begin_page(drawing *dr, int number) | 275 | void print_begin_page(drawing *dr, int number) |
238 | { | 276 | { |
239 | dr->api->begin_page(dr->handle, number); | 277 | drawing_internal *dri = PRIVATE_CAST(dr); |
278 | dri->pub.api->begin_page(dr, number); | ||
240 | } | 279 | } |
241 | 280 | ||
242 | void print_begin_puzzle(drawing *dr, float xm, float xc, | 281 | void print_begin_puzzle(drawing *dr, float xm, float xc, |
243 | float ym, float yc, int pw, int ph, float wmm, | 282 | float ym, float yc, int pw, int ph, float wmm, |
244 | float scale) | 283 | float scale) |
245 | { | 284 | { |
246 | dr->scale = scale; | 285 | drawing_internal *dri = PRIVATE_CAST(dr); |
247 | dr->ncolours = 0; | 286 | dri->scale = scale; |
248 | dr->api->begin_puzzle(dr->handle, xm, xc, ym, yc, pw, ph, wmm); | 287 | dri->ncolours = 0; |
288 | dri->pub.api->begin_puzzle(dr, xm, xc, ym, yc, pw, ph, wmm); | ||
249 | } | 289 | } |
250 | 290 | ||
251 | void print_end_puzzle(drawing *dr) | 291 | void print_end_puzzle(drawing *dr) |
252 | { | 292 | { |
253 | dr->api->end_puzzle(dr->handle); | 293 | drawing_internal *dri = PRIVATE_CAST(dr); |
254 | dr->scale = 1.0F; | 294 | dri->pub.api->end_puzzle(dr); |
295 | dri->scale = 1.0F; | ||
255 | } | 296 | } |
256 | 297 | ||
257 | void print_end_page(drawing *dr, int number) | 298 | void print_end_page(drawing *dr, int number) |
258 | { | 299 | { |
259 | dr->api->end_page(dr->handle, number); | 300 | drawing_internal *dri = PRIVATE_CAST(dr); |
301 | dri->pub.api->end_page(dr, number); | ||
260 | } | 302 | } |
261 | 303 | ||
262 | void print_end_doc(drawing *dr) | 304 | void print_end_doc(drawing *dr) |
263 | { | 305 | { |
264 | dr->api->end_doc(dr->handle); | 306 | drawing_internal *dri = PRIVATE_CAST(dr); |
307 | dri->pub.api->end_doc(dr); | ||
265 | } | 308 | } |
266 | 309 | ||
267 | void print_get_colour(drawing *dr, int colour, bool printing_in_colour, | 310 | void print_get_colour(drawing *dr, int colour, bool printing_in_colour, |
268 | int *hatch, float *r, float *g, float *b) | 311 | int *hatch, float *r, float *g, float *b) |
269 | { | 312 | { |
270 | assert(colour >= 0 && colour < dr->ncolours); | 313 | drawing_internal *dri = PRIVATE_CAST(dr); |
271 | if (dr->colours[colour].hatch_when == 2 || | 314 | assert(colour >= 0 && colour < dri->ncolours); |
272 | (dr->colours[colour].hatch_when == 1 && !printing_in_colour)) { | 315 | if (dri->colours[colour].hatch_when == 2 || |
273 | *hatch = dr->colours[colour].hatch; | 316 | (dri->colours[colour].hatch_when == 1 && !printing_in_colour)) { |
317 | *hatch = dri->colours[colour].hatch; | ||
274 | } else { | 318 | } else { |
275 | *hatch = -1; | 319 | *hatch = -1; |
276 | if (printing_in_colour) { | 320 | if (printing_in_colour) { |
277 | *r = dr->colours[colour].r; | 321 | *r = dri->colours[colour].r; |
278 | *g = dr->colours[colour].g; | 322 | *g = dri->colours[colour].g; |
279 | *b = dr->colours[colour].b; | 323 | *b = dri->colours[colour].b; |
280 | } else { | 324 | } else { |
281 | *r = *g = *b = dr->colours[colour].grey; | 325 | *r = *g = *b = dri->colours[colour].grey; |
282 | } | 326 | } |
283 | } | 327 | } |
284 | } | 328 | } |
@@ -286,18 +330,19 @@ void print_get_colour(drawing *dr, int colour, bool printing_in_colour, | |||
286 | static int print_generic_colour(drawing *dr, float r, float g, float b, | 330 | static int print_generic_colour(drawing *dr, float r, float g, float b, |
287 | float grey, int hatch, int hatch_when) | 331 | float grey, int hatch, int hatch_when) |
288 | { | 332 | { |
289 | if (dr->ncolours >= dr->coloursize) { | 333 | drawing_internal *dri = PRIVATE_CAST(dr); |
290 | dr->coloursize = dr->ncolours + 16; | 334 | if (dri->ncolours >= dri->coloursize) { |
291 | dr->colours = sresize(dr->colours, dr->coloursize, | 335 | dri->coloursize = dri->ncolours + 16; |
336 | dri->colours = sresize(dri->colours, dri->coloursize, | ||
292 | struct print_colour); | 337 | struct print_colour); |
293 | } | 338 | } |
294 | dr->colours[dr->ncolours].hatch = hatch; | 339 | dri->colours[dri->ncolours].hatch = hatch; |
295 | dr->colours[dr->ncolours].hatch_when = hatch_when; | 340 | dri->colours[dri->ncolours].hatch_when = hatch_when; |
296 | dr->colours[dr->ncolours].r = r; | 341 | dri->colours[dri->ncolours].r = r; |
297 | dr->colours[dr->ncolours].g = g; | 342 | dri->colours[dri->ncolours].g = g; |
298 | dr->colours[dr->ncolours].b = b; | 343 | dri->colours[dri->ncolours].b = b; |
299 | dr->colours[dr->ncolours].grey = grey; | 344 | dri->colours[dri->ncolours].grey = grey; |
300 | return dr->ncolours++; | 345 | return dri->ncolours++; |
301 | } | 346 | } |
302 | 347 | ||
303 | int print_mono_colour(drawing *dr, int grey) | 348 | int print_mono_colour(drawing *dr, int grey) |
@@ -332,6 +377,8 @@ int print_rgb_hatched_colour(drawing *dr, float r, float g, float b, int hatch) | |||
332 | 377 | ||
333 | void print_line_width(drawing *dr, int width) | 378 | void print_line_width(drawing *dr, int width) |
334 | { | 379 | { |
380 | drawing_internal *dri = PRIVATE_CAST(dr); | ||
381 | |||
335 | /* | 382 | /* |
336 | * I don't think it's entirely sensible to have line widths be | 383 | * I don't think it's entirely sensible to have line widths be |
337 | * entirely relative to the puzzle size; there is a point | 384 | * entirely relative to the puzzle size; there is a point |
@@ -344,10 +391,11 @@ void print_line_width(drawing *dr, int width) | |||
344 | * _square root_ of the main puzzle scale. Double the puzzle | 391 | * _square root_ of the main puzzle scale. Double the puzzle |
345 | * size, and the line width multiplies by 1.4. | 392 | * size, and the line width multiplies by 1.4. |
346 | */ | 393 | */ |
347 | dr->api->line_width(dr->handle, (float)sqrt(dr->scale) * width); | 394 | dri->pub.api->line_width(dr, (float)sqrt(dri->scale) * width); |
348 | } | 395 | } |
349 | 396 | ||
350 | void print_line_dotted(drawing *dr, bool dotted) | 397 | void print_line_dotted(drawing *dr, bool dotted) |
351 | { | 398 | { |
352 | dr->api->line_dotted(dr->handle, dotted); | 399 | drawing_internal *dri = PRIVATE_CAST(dr); |
400 | dri->pub.api->line_dotted(dr, dotted); | ||
353 | } | 401 | } |