summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/drawing.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/puzzles/src/drawing.c')
-rw-r--r--apps/plugins/puzzles/src/drawing.c212
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
41struct drawing { 45typedef 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
53drawing *drawing_new(const drawing_api *api, midend *me, void *handle) 66drawing *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
66void drawing_free(drawing *dr) 85void 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
73void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, 93void 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
80void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) 101void 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
85void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) 107void 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
90void draw_thick_line(drawing *dr, float thickness, 113void 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
120void draw_polygon(drawing *dr, int *coords, int npoints, 144void 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
127void draw_circle(drawing *dr, int cx, int cy, int radius, 152void 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
134void draw_update(drawing *dr, int x, int y, int w, int h) 160void 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
140void clip(drawing *dr, int x, int y, int w, int h) 167void 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
145void unclip(drawing *dr) 173void 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
150void start_draw(drawing *dr) 179void 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
155void end_draw(drawing *dr) 185void 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
160char *text_fallback(drawing *dr, const char *const *strings, int nstrings) 191char *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
193void status_bar(drawing *dr, const char *text) 225void 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
212blitter *blitter_new(drawing *dr, int w, int h) 245blitter *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
217void blitter_free(drawing *dr, blitter *bl) 251void 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
222void blitter_save(drawing *dr, blitter *bl, int x, int y) 257void 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
227void blitter_load(drawing *dr, blitter *bl, int x, int y) 263void 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
232void print_begin_doc(drawing *dr, int pages) 269void 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
237void print_begin_page(drawing *dr, int number) 275void 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
242void print_begin_puzzle(drawing *dr, float xm, float xc, 281void 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
251void print_end_puzzle(drawing *dr) 291void 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
257void print_end_page(drawing *dr, int number) 298void 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
262void print_end_doc(drawing *dr) 304void 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
267void print_get_colour(drawing *dr, int colour, bool printing_in_colour, 310void 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,
286static int print_generic_colour(drawing *dr, float r, float g, float b, 330static 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
303int print_mono_colour(drawing *dr, int grey) 348int 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
333void print_line_width(drawing *dr, int width) 378void 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
350void print_line_dotted(drawing *dr, bool dotted) 397void 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}