chiark / gitweb /
63e27a4f04d0410dd47c7a39d4159f39248b2b77
[sgt-puzzles.git] / drawing.c
1 /*
2  * drawing.c: Intermediary between the drawing interface as
3  * presented to the back end, and that implemented by the front
4  * end.
5  * 
6  * Mostly just looks up calls in a vtable and passes them through
7  * unchanged. However, on the printing side it tracks print colours
8  * so the front end API doesn't have to.
9  * 
10  * FIXME: could we also sort out rewrite_statusbar in here? Also
11  * I'd _like_ to do automatic draw_updates, but it's a pain for
12  * draw_text in particular - I could invent a front end API which
13  * retrieved the text bounds and then do the alignment myself as
14  * well, except that that doesn't work for PS. As usual.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <assert.h>
20 #include <math.h>
21
22 #include "puzzles.h"
23
24 struct print_colour {
25     int hatch;
26     float r, g, b;
27 };
28
29 struct drawing {
30     const drawing_api *api;
31     void *handle;
32     struct print_colour *colours;
33     int ncolours, coloursize;
34     float scale;
35 };
36
37 drawing *drawing_init(const drawing_api *api, void *handle)
38 {
39     drawing *dr = snew(drawing);
40     dr->api = api;
41     dr->handle = handle;
42     dr->colours = NULL;
43     dr->ncolours = dr->coloursize = 0;
44     dr->scale = 1.0F;
45     return dr;
46 }
47
48 void drawing_free(drawing *dr)
49 {
50     sfree(dr->colours);
51     sfree(dr);
52 }
53
54 void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize,
55                int align, int colour, char *text)
56 {
57     dr->api->draw_text(dr->handle, x, y, fonttype, fontsize, align,
58                        colour, text);
59 }
60
61 void draw_rect(drawing *dr, int x, int y, int w, int h, int colour)
62 {
63     dr->api->draw_rect(dr->handle, x, y, w, h, colour);
64 }
65
66 void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour)
67 {
68     dr->api->draw_line(dr->handle, x1, y1, x2, y2, colour);
69 }
70
71 void draw_polygon(drawing *dr, int *coords, int npoints,
72                   int fillcolour, int outlinecolour)
73 {
74     dr->api->draw_polygon(dr->handle, coords, npoints, fillcolour,
75                           outlinecolour);
76 }
77
78 void draw_circle(drawing *dr, int cx, int cy, int radius,
79                  int fillcolour, int outlinecolour)
80 {
81     dr->api->draw_circle(dr->handle, cx, cy, radius, fillcolour,
82                          outlinecolour);
83 }
84
85 void draw_update(drawing *dr, int x, int y, int w, int h)
86 {
87     if (dr->api->draw_update)
88         dr->api->draw_update(dr->handle, x, y, w, h);
89 }
90
91 void clip(drawing *dr, int x, int y, int w, int h)
92 {
93     dr->api->clip(dr->handle, x, y, w, h);
94 }
95
96 void unclip(drawing *dr)
97 {
98     dr->api->unclip(dr->handle);
99 }
100
101 void start_draw(drawing *dr)
102 {
103     dr->api->start_draw(dr->handle);
104 }
105
106 void end_draw(drawing *dr)
107 {
108     dr->api->end_draw(dr->handle);
109 }
110
111 void status_bar(drawing *dr, char *text)
112 {
113     if (dr->api->status_bar)
114         dr->api->status_bar(dr->handle, text);
115 }
116
117 blitter *blitter_new(drawing *dr, int w, int h)
118 {
119     return dr->api->blitter_new(dr->handle, w, h);
120 }
121
122 void blitter_free(drawing *dr, blitter *bl)
123 {
124     dr->api->blitter_free(dr->handle, bl);
125 }
126
127 void blitter_save(drawing *dr, blitter *bl, int x, int y)
128 {
129     dr->api->blitter_save(dr->handle, bl, x, y);
130 }
131
132 void blitter_load(drawing *dr, blitter *bl, int x, int y)
133 {
134     dr->api->blitter_load(dr->handle, bl, x, y);
135 }
136
137 void print_begin_doc(drawing *dr, int pages)
138 {
139     dr->api->begin_doc(dr->handle, pages);
140 }
141
142 void print_begin_page(drawing *dr, int number)
143 {
144     dr->api->begin_page(dr->handle, number);
145 }
146
147 void print_begin_puzzle(drawing *dr, float xm, float xc,
148                         float ym, float yc, int pw, int ph, float wmm,
149                         float scale)
150 {
151     dr->scale = scale;
152     dr->ncolours = 0;
153     dr->api->begin_puzzle(dr->handle, xm, xc, ym, yc, pw, ph, wmm);
154 }
155
156 void print_end_puzzle(drawing *dr)
157 {
158     dr->api->end_puzzle(dr->handle);
159     dr->scale = 1.0F;
160 }
161
162 void print_end_page(drawing *dr, int number)
163 {
164     dr->api->end_page(dr->handle, number);
165 }
166
167 void print_end_doc(drawing *dr)
168 {
169     dr->api->end_doc(dr->handle);
170 }
171
172 void print_get_colour(drawing *dr, int colour, int *hatch,
173                       float *r, float *g, float *b)
174 {
175     assert(colour >= 0 && colour < dr->ncolours);
176     *hatch = dr->colours[colour].hatch;
177     *r = dr->colours[colour].r;
178     *g = dr->colours[colour].g;
179     *b = dr->colours[colour].b;
180 }
181
182 int print_rgb_colour(drawing *dr, int hatch, float r, float g, float b)
183 {
184     if (dr->ncolours >= dr->coloursize) {
185         dr->coloursize = dr->ncolours + 16;
186         dr->colours = sresize(dr->colours, dr->coloursize,
187                               struct print_colour);
188     }
189     dr->colours[dr->ncolours].hatch = hatch;
190     dr->colours[dr->ncolours].r = r;
191     dr->colours[dr->ncolours].g = g;
192     dr->colours[dr->ncolours].b = b;
193     return dr->ncolours++;
194 }
195
196 int print_grey_colour(drawing *dr, int hatch, float grey)
197 {
198     return print_rgb_colour(dr, hatch, grey, grey, grey);
199 }
200
201 int print_mono_colour(drawing *dr, int grey)
202 {
203     return print_rgb_colour(dr, grey ? HATCH_CLEAR : HATCH_SOLID,
204                             grey, grey, grey);
205 }
206
207 void print_line_width(drawing *dr, int width)
208 {
209     /*
210      * I don't think it's entirely sensible to have line widths be
211      * entirely relative to the puzzle size; there is a point
212      * beyond which lines are just _stupidly_ thick. On the other
213      * hand, absolute line widths aren't particularly nice either
214      * because they start to feel a bit feeble at really large
215      * scales.
216      * 
217      * My experimental answer is to scale line widths as the
218      * _square root_ of the main puzzle scale. Double the puzzle
219      * size, and the line width multiplies by 1.4.
220      */
221     dr->api->line_width(dr->handle, sqrt(dr->scale) * width);
222 }