summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/ps.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/puzzles/src/ps.c')
-rw-r--r--apps/plugins/puzzles/src/ps.c432
1 files changed, 0 insertions, 432 deletions
diff --git a/apps/plugins/puzzles/src/ps.c b/apps/plugins/puzzles/src/ps.c
deleted file mode 100644
index ab8a1589f4..0000000000
--- a/apps/plugins/puzzles/src/ps.c
+++ /dev/null
@@ -1,432 +0,0 @@
1/*
2 * ps.c: PostScript printing functions.
3 */
4
5#include <stdio.h>
6#include <stdarg.h>
7#include <string.h>
8#include <assert.h>
9
10#include "puzzles.h"
11
12struct psdata {
13 FILE *fp;
14 bool colour;
15 int ytop;
16 bool clipped;
17 float hatchthick, hatchspace;
18 int gamewidth, gameheight;
19 drawing *drawing;
20};
21
22static void ps_printf(psdata *ps, const char *fmt, ...)
23{
24 va_list ap;
25
26 va_start(ap, fmt);
27 vfprintf(ps->fp, fmt, ap);
28 va_end(ap);
29}
30
31static void ps_fill(psdata *ps, int colour)
32{
33 int hatch;
34 float r, g, b;
35
36 print_get_colour(ps->drawing, colour, ps->colour, &hatch, &r, &g, &b);
37
38 if (hatch < 0) {
39 if (ps->colour)
40 ps_printf(ps, "%g %g %g setrgbcolor fill\n", r, g, b);
41 else
42 ps_printf(ps, "%g setgray fill\n", r);
43 } else {
44 /* Clip to the region. */
45 ps_printf(ps, "gsave clip\n");
46 /* Hatch the entire game printing area. */
47 ps_printf(ps, "newpath\n");
48 if (hatch == HATCH_VERT || hatch == HATCH_PLUS)
49 ps_printf(ps, "0 %g %d {\n"
50 " 0 moveto 0 %d rlineto\n"
51 "} for\n", ps->hatchspace, ps->gamewidth,
52 ps->gameheight);
53 if (hatch == HATCH_HORIZ || hatch == HATCH_PLUS)
54 ps_printf(ps, "0 %g %d {\n"
55 " 0 exch moveto %d 0 rlineto\n"
56 "} for\n", ps->hatchspace, ps->gameheight,
57 ps->gamewidth);
58 if (hatch == HATCH_SLASH || hatch == HATCH_X)
59 ps_printf(ps, "%d %g %d {\n"
60 " 0 moveto %d dup rlineto\n"
61 "} for\n", -ps->gameheight, ps->hatchspace * ROOT2,
62 ps->gamewidth, max(ps->gamewidth, ps->gameheight));
63 if (hatch == HATCH_BACKSLASH || hatch == HATCH_X)
64 ps_printf(ps, "0 %g %d {\n"
65 " 0 moveto %d neg dup neg rlineto\n"
66 "} for\n", ps->hatchspace * ROOT2,
67 ps->gamewidth+ps->gameheight,
68 max(ps->gamewidth, ps->gameheight));
69 ps_printf(ps, "0 setgray %g setlinewidth stroke grestore\n",
70 ps->hatchthick);
71 }
72}
73
74static void ps_setcolour_internal(psdata *ps, int colour, const char *suffix)
75{
76 int hatch;
77 float r, g, b;
78
79 print_get_colour(ps->drawing, colour, ps->colour, &hatch, &r, &g, &b);
80
81 /*
82 * Stroking in hatched colours is not permitted.
83 */
84 assert(hatch < 0);
85
86 if (ps->colour)
87 ps_printf(ps, "%g %g %g setrgbcolor%s\n", r, g, b, suffix);
88 else
89 ps_printf(ps, "%g setgray%s\n", r, suffix);
90}
91
92static void ps_setcolour(psdata *ps, int colour)
93{
94 ps_setcolour_internal(ps, colour, "");
95}
96
97static void ps_stroke(psdata *ps, int colour)
98{
99 ps_setcolour_internal(ps, colour, " stroke");
100}
101
102static void ps_draw_text(void *handle, int x, int y, int fonttype,
103 int fontsize, int align, int colour,
104 const char *text)
105{
106 psdata *ps = (psdata *)handle;
107
108 y = ps->ytop - y;
109 ps_setcolour(ps, colour);
110 ps_printf(ps, "/%s findfont %d scalefont setfont\n",
111 fonttype == FONT_FIXED ? "Courier-L1" : "Helvetica-L1",
112 fontsize);
113 if (align & ALIGN_VCENTRE) {
114 ps_printf(ps, "newpath 0 0 moveto (X) true charpath flattenpath"
115 " pathbbox\n"
116 "3 -1 roll add 2 div %d exch sub %d exch moveto pop pop\n",
117 y, x);
118 } else {
119 ps_printf(ps, "%d %d moveto\n", x, y);
120 }
121 ps_printf(ps, "(");
122 while (*text) {
123 if (*text == '\\' || *text == '(' || *text == ')')
124 ps_printf(ps, "\\");
125 ps_printf(ps, "%c", *text);
126 text++;
127 }
128 ps_printf(ps, ") ");
129 if (align & (ALIGN_HCENTRE | ALIGN_HRIGHT))
130 ps_printf(ps, "dup stringwidth pop %sneg 0 rmoveto show\n",
131 (align & ALIGN_HCENTRE) ? "2 div " : "");
132 else
133 ps_printf(ps, "show\n");
134}
135
136static void ps_draw_rect(void *handle, int x, int y, int w, int h, int colour)
137{
138 psdata *ps = (psdata *)handle;
139
140 y = ps->ytop - y;
141 /*
142 * Offset by half a pixel for the exactness requirement.
143 */
144 ps_printf(ps, "newpath %g %g moveto %d 0 rlineto 0 %d rlineto"
145 " %d 0 rlineto closepath\n", x - 0.5, y + 0.5, w, -h, -w);
146 ps_fill(ps, colour);
147}
148
149static void ps_draw_line(void *handle, int x1, int y1, int x2, int y2,
150 int colour)
151{
152 psdata *ps = (psdata *)handle;
153
154 y1 = ps->ytop - y1;
155 y2 = ps->ytop - y2;
156 ps_printf(ps, "newpath %d %d moveto %d %d lineto\n", x1, y1, x2, y2);
157 ps_stroke(ps, colour);
158}
159
160static void ps_draw_polygon(void *handle, int *coords, int npoints,
161 int fillcolour, int outlinecolour)
162{
163 psdata *ps = (psdata *)handle;
164
165 int i;
166
167 ps_printf(ps, "newpath %d %d moveto\n", coords[0], ps->ytop - coords[1]);
168
169 for (i = 1; i < npoints; i++)
170 ps_printf(ps, "%d %d lineto\n", coords[i*2], ps->ytop - coords[i*2+1]);
171
172 ps_printf(ps, "closepath\n");
173
174 if (fillcolour >= 0) {
175 ps_printf(ps, "gsave\n");
176 ps_fill(ps, fillcolour);
177 ps_printf(ps, "grestore\n");
178 }
179 ps_stroke(ps, outlinecolour);
180}
181
182static void ps_draw_circle(void *handle, int cx, int cy, int radius,
183 int fillcolour, int outlinecolour)
184{
185 psdata *ps = (psdata *)handle;
186
187 cy = ps->ytop - cy;
188
189 ps_printf(ps, "newpath %d %d %d 0 360 arc closepath\n", cx, cy, radius);
190
191 if (fillcolour >= 0) {
192 ps_printf(ps, "gsave\n");
193 ps_fill(ps, fillcolour);
194 ps_printf(ps, "grestore\n");
195 }
196 ps_stroke(ps, outlinecolour);
197}
198
199static void ps_unclip(void *handle)
200{
201 psdata *ps = (psdata *)handle;
202
203 assert(ps->clipped);
204 ps_printf(ps, "grestore\n");
205 ps->clipped = false;
206}
207
208static void ps_clip(void *handle, int x, int y, int w, int h)
209{
210 psdata *ps = (psdata *)handle;
211
212 if (ps->clipped)
213 ps_unclip(ps);
214
215 y = ps->ytop - y;
216 /*
217 * Offset by half a pixel for the exactness requirement.
218 */
219 ps_printf(ps, "gsave\n");
220 ps_printf(ps, "newpath %g %g moveto %d 0 rlineto 0 %d rlineto"
221 " %d 0 rlineto closepath\n", x - 0.5, y + 0.5, w, -h, -w);
222 ps_printf(ps, "clip\n");
223 ps->clipped = true;
224}
225
226static void ps_line_width(void *handle, float width)
227{
228 psdata *ps = (psdata *)handle;
229
230 ps_printf(ps, "%g setlinewidth\n", width);
231}
232
233static void ps_line_dotted(void *handle, bool dotted)
234{
235 psdata *ps = (psdata *)handle;
236
237 if (dotted) {
238 ps_printf(ps, "[ currentlinewidth 3 mul ] 0 setdash\n");
239 } else {
240 ps_printf(ps, "[ ] 0 setdash\n");
241 }
242}
243
244static char *ps_text_fallback(void *handle, const char *const *strings,
245 int nstrings)
246{
247 /*
248 * We can handle anything in ISO 8859-1, and we'll manually
249 * translate it out of UTF-8 for the purpose.
250 */
251 int i, maxlen;
252 char *ret;
253
254 maxlen = 0;
255 for (i = 0; i < nstrings; i++) {
256 int len = strlen(strings[i]);
257 if (maxlen < len) maxlen = len;
258 }
259
260 ret = snewn(maxlen + 1, char);
261
262 for (i = 0; i < nstrings; i++) {
263 const char *p = strings[i];
264 char *q = ret;
265
266 while (*p) {
267 int c = (unsigned char)*p++;
268 if (c < 0x80) {
269 *q++ = c; /* ASCII */
270 } else if ((c == 0xC2 || c == 0xC3) && (*p & 0xC0) == 0x80) {
271 *q++ = (c << 6) | (*p++ & 0x3F); /* top half of 8859-1 */
272 } else {
273 break;
274 }
275 }
276
277 if (!*p) {
278 *q = '\0';
279 return ret;
280 }
281 }
282
283 assert(!"Should never reach here");
284 return NULL;
285}
286
287static void ps_begin_doc(void *handle, int pages)
288{
289 psdata *ps = (psdata *)handle;
290
291 fputs("%!PS-Adobe-3.0\n", ps->fp);
292 fputs("%%Creator: Simon Tatham's Portable Puzzle Collection\n", ps->fp);
293 fputs("%%DocumentData: Clean7Bit\n", ps->fp);
294 fputs("%%LanguageLevel: 1\n", ps->fp);
295 fprintf(ps->fp, "%%%%Pages: %d\n", pages);
296 fputs("%%DocumentNeededResources:\n", ps->fp);
297 fputs("%%+ font Helvetica\n", ps->fp);
298 fputs("%%+ font Courier\n", ps->fp);
299 fputs("%%EndComments\n", ps->fp);
300 fputs("%%BeginSetup\n", ps->fp);
301 fputs("%%IncludeResource: font Helvetica\n", ps->fp);
302 fputs("%%IncludeResource: font Courier\n", ps->fp);
303 fputs("%%EndSetup\n", ps->fp);
304 fputs("%%BeginProlog\n", ps->fp);
305 /*
306 * Re-encode Helvetica and Courier into ISO-8859-1, which gives
307 * us times and divide signs - and also (according to the
308 * Language Reference Manual) a bonus in that the ASCII '-' code
309 * point now points to a minus sign instead of a hyphen.
310 */
311 fputs("/Helvetica findfont " /* get the font dictionary */
312 "dup maxlength dict dup begin " /* create and open a new dict */
313 "exch " /* move the original font to top of stack */
314 "{1 index /FID ne {def} {pop pop} ifelse} forall "
315 /* copy everything except FID */
316 "/Encoding ISOLatin1Encoding def "
317 /* set the thing we actually wanted to change */
318 "/FontName /Helvetica-L1 def " /* set a new font name */
319 "FontName end exch definefont" /* and define the font */
320 "\n", ps->fp);
321 fputs("/Courier findfont " /* get the font dictionary */
322 "dup maxlength dict dup begin " /* create and open a new dict */
323 "exch " /* move the original font to top of stack */
324 "{1 index /FID ne {def} {pop pop} ifelse} forall "
325 /* copy everything except FID */
326 "/Encoding ISOLatin1Encoding def "
327 /* set the thing we actually wanted to change */
328 "/FontName /Courier-L1 def " /* set a new font name */
329 "FontName end exch definefont" /* and define the font */
330 "\n", ps->fp);
331 fputs("%%EndProlog\n", ps->fp);
332}
333
334static void ps_begin_page(void *handle, int number)
335{
336 psdata *ps = (psdata *)handle;
337
338 fprintf(ps->fp, "%%%%Page: %d %d\ngsave save\n%g dup scale\n",
339 number, number, 72.0 / 25.4);
340}
341
342static void ps_begin_puzzle(void *handle, float xm, float xc,
343 float ym, float yc, int pw, int ph, float wmm)
344{
345 psdata *ps = (psdata *)handle;
346
347 fprintf(ps->fp, "gsave\n"
348 "clippath flattenpath pathbbox pop pop translate\n"
349 "clippath flattenpath pathbbox 4 2 roll pop pop\n"
350 "exch %g mul %g add exch dup %g mul %g add sub translate\n"
351 "%g dup scale\n"
352 "0 -%d translate\n", xm, xc, ym, yc, wmm/pw, ph);
353 ps->ytop = ph;
354 ps->clipped = false;
355 ps->gamewidth = pw;
356 ps->gameheight = ph;
357 ps->hatchthick = 0.2 * pw / wmm;
358 ps->hatchspace = 1.0 * pw / wmm;
359}
360
361static void ps_end_puzzle(void *handle)
362{
363 psdata *ps = (psdata *)handle;
364
365 fputs("grestore\n", ps->fp);
366}
367
368static void ps_end_page(void *handle, int number)
369{
370 psdata *ps = (psdata *)handle;
371
372 fputs("restore grestore showpage\n", ps->fp);
373}
374
375static void ps_end_doc(void *handle)
376{
377 psdata *ps = (psdata *)handle;
378
379 fputs("%%EOF\n", ps->fp);
380}
381
382static const struct drawing_api ps_drawing = {
383 ps_draw_text,
384 ps_draw_rect,
385 ps_draw_line,
386 ps_draw_polygon,
387 ps_draw_circle,
388 NULL /* draw_update */,
389 ps_clip,
390 ps_unclip,
391 NULL /* start_draw */,
392 NULL /* end_draw */,
393 NULL /* status_bar */,
394 NULL /* blitter_new */,
395 NULL /* blitter_free */,
396 NULL /* blitter_save */,
397 NULL /* blitter_load */,
398 ps_begin_doc,
399 ps_begin_page,
400 ps_begin_puzzle,
401 ps_end_puzzle,
402 ps_end_page,
403 ps_end_doc,
404 ps_line_width,
405 ps_line_dotted,
406 ps_text_fallback,
407};
408
409psdata *ps_init(FILE *outfile, bool colour)
410{
411 psdata *ps = snew(psdata);
412
413 ps->fp = outfile;
414 ps->colour = colour;
415 ps->ytop = 0;
416 ps->clipped = false;
417 ps->hatchthick = ps->hatchspace = ps->gamewidth = ps->gameheight = 0;
418 ps->drawing = drawing_new(&ps_drawing, NULL, ps);
419
420 return ps;
421}
422
423void ps_free(psdata *ps)
424{
425 drawing_free(ps->drawing);
426 sfree(ps);
427}
428
429drawing *ps_drawing_api(psdata *ps)
430{
431 return ps->drawing;
432}