1 /* ======================================================================== */
2 /* Graphics Prescaler */
3 /* */
4 /* The graphics prescaler allows scaling up the 160x200 bitmap to some */
5 /* other size prior to final scaling to display resolution. This is */
6 /* where we'd apply transforms such as Scale2X or a variant. */
7 /* ======================================================================== */
8
9 #include "config.h"
10 #include "periph/periph.h"
11 #include "gfx/gfx.h"
12 #include "gfx/gfx_prescale.h"
13 #include "scale/scale2x.h"
14 #include "scale/scale3x.h"
15
16 typedef struct gfx_prescaler_typ_pvt_t
17 {
18 int orig_x, orig_y;
19 uint8_t *intermediate; // for scale4x only
20 } gfx_prescaler_typ_pvt_t;
21
22 /* ======================================================================== */
23 /* Prescalers */
24 /* ======================================================================== */
25
26 /* ------------------------------------------------------------------------ */
27 /* NULL prescaler */
28 /* ------------------------------------------------------------------------ */
gfx_prescaler_null_init(int orig_x,int orig_y,int * RESTRICT new_x,int * RESTRICT new_y,int * RESTRICT need_inter_vid,gfx_dirtyrect_spec * RESTRICT dr_spec)29 LOCAL void *gfx_prescaler_null_init(int orig_x, int orig_y,
30 int *RESTRICT new_x,
31 int *RESTRICT new_y,
32 int *RESTRICT need_inter_vid,
33 gfx_dirtyrect_spec *RESTRICT dr_spec)
34 {
35 *new_x = orig_x;
36 *new_y = orig_y;
37 *need_inter_vid = 0;
38
39 dr_spec->active_first_x = 0;
40 dr_spec->active_first_y = 4;
41 dr_spec->active_last_x = orig_x - 1;
42 dr_spec->active_last_y = orig_y - 5;
43
44 dr_spec->x_step = 8;
45 dr_spec->y_step = 16;
46
47 dr_spec->pitch = orig_x;
48
49 dr_spec->bord_first_x = 0;
50 dr_spec->bord_first_y = 0;
51 dr_spec->bord_last_x = orig_x - 1;
52 dr_spec->bord_last_y = orig_y - 1;
53
54 return NULL;
55 }
56
gfx_prescaler_null(const uint8_t * RESTRICT src,uint8_t * RESTRICT dst,void * RESTRICT opaque)57 LOCAL void gfx_prescaler_null(const uint8_t *RESTRICT src,
58 uint8_t *RESTRICT dst,
59 void *RESTRICT opaque)
60 {
61 UNUSED(src);
62 UNUSED(dst);
63 UNUSED(opaque);
64 return;
65 }
66
gfx_prescaler_null_dtor(void * u)67 LOCAL void gfx_prescaler_null_dtor(void *u)
68 {
69 UNUSED(u);
70 return;
71 }
72
73 /* ------------------------------------------------------------------------ */
74 /* SCALE2X */
75 /* ------------------------------------------------------------------------ */
gfx_prescaler_scale2x_init(int orig_x,int orig_y,int * RESTRICT new_x,int * RESTRICT new_y,int * RESTRICT need_inter_vid,gfx_dirtyrect_spec * RESTRICT dr_spec)76 LOCAL void *gfx_prescaler_scale2x_init(int orig_x, int orig_y,
77 int *RESTRICT new_x,
78 int *RESTRICT new_y,
79 int *RESTRICT need_inter_vid,
80 gfx_dirtyrect_spec *RESTRICT dr_spec)
81 {
82 gfx_prescaler_typ_pvt_t *pvt = CALLOC(gfx_prescaler_typ_pvt_t, 1);
83
84 if (!pvt)
85 {
86 fprintf(stderr, "Out of memory in gfx_prescale\n");
87 exit(1);
88 }
89
90 pvt->orig_x = orig_x;
91 pvt->orig_y = orig_y;
92 pvt->intermediate = NULL;
93
94 *new_x = orig_x * 2;
95 *new_y = orig_y * 2;
96 *need_inter_vid = 1;
97
98 dr_spec->active_first_x = 0;
99 dr_spec->active_first_y = 8;
100 dr_spec->active_last_x = 2*orig_x - 1;
101 dr_spec->active_last_y = 2*orig_y - 9;
102
103 dr_spec->x_step = 16;
104 dr_spec->y_step = 32;
105
106 dr_spec->pitch = 2*orig_x;
107
108 dr_spec->bord_first_x = 0;
109 dr_spec->bord_first_y = 0;
110 dr_spec->bord_last_x = 2*orig_x - 1;
111 dr_spec->bord_last_y = 2*orig_y - 1;
112
113 return pvt;
114 }
115
116 /* Factored out and reused by scale4x */
perform_scale2x_8(int orig_x,int orig_y,const uint8_t * RESTRICT src,uint8_t * RESTRICT dst)117 LOCAL void perform_scale2x_8(int orig_x,
118 int orig_y,
119 const uint8_t *RESTRICT src,
120 uint8_t *RESTRICT dst)
121 {
122 int src_pitch = orig_x,
123 dst_pitch = orig_x * 2;
124 const uint8_t *src_prev = src;
125 const uint8_t *src_curr = src;
126 const uint8_t *src_next = src + src_pitch;
127 int y;
128
129 scale2x_8_def((scale2x_uint8 *)dst, (scale2x_uint8 *)(dst + dst_pitch),
130 (const scale2x_uint8 *)src_prev,
131 (const scale2x_uint8 *)src_curr,
132 (const scale2x_uint8 *)src_next, src_pitch);
133
134 for (y = 2 ; y < orig_y; y++)
135 {
136 dst += dst_pitch * 2;
137 src_prev = src_curr;
138 src_curr = src_next;
139 src_next += src_pitch;
140
141 scale2x_8_def((scale2x_uint8 *)dst, (scale2x_uint8 *)(dst + dst_pitch),
142 (const scale2x_uint8 *)src_prev,
143 (const scale2x_uint8 *)src_curr,
144 (const scale2x_uint8 *)src_next, src_pitch);
145 }
146
147 dst += dst_pitch * 2;
148 src_prev = src_curr;
149 src_curr = src_next;
150
151 scale2x_8_def((scale2x_uint8 *)dst, (scale2x_uint8 *)(dst + dst_pitch),
152 (const scale2x_uint8 *)src_prev,
153 (const scale2x_uint8 *)src_curr,
154 (const scale2x_uint8 *)src_next, src_pitch);
155 }
156
gfx_prescaler_scale2x(const uint8_t * RESTRICT src,uint8_t * RESTRICT dst,void * RESTRICT opaque)157 LOCAL void gfx_prescaler_scale2x(const uint8_t *RESTRICT src,
158 uint8_t *RESTRICT dst,
159 void *RESTRICT opaque)
160 {
161 gfx_prescaler_typ_pvt_t *pvt = (gfx_prescaler_typ_pvt_t *)opaque;
162 int orig_x = pvt->orig_x, orig_y = pvt->orig_y;
163
164 perform_scale2x_8(orig_x, orig_y, src, dst);
165
166 return;
167 }
168
169
170 /* ------------------------------------------------------------------------ */
171 /* SCALE3X */
172 /* ------------------------------------------------------------------------ */
gfx_prescaler_scale3x_init(int orig_x,int orig_y,int * RESTRICT new_x,int * RESTRICT new_y,int * RESTRICT need_inter_vid,gfx_dirtyrect_spec * RESTRICT dr_spec)173 LOCAL void *gfx_prescaler_scale3x_init(int orig_x, int orig_y,
174 int *RESTRICT new_x,
175 int *RESTRICT new_y,
176 int *RESTRICT need_inter_vid,
177 gfx_dirtyrect_spec *RESTRICT dr_spec)
178 {
179 gfx_prescaler_typ_pvt_t *pvt = CALLOC(gfx_prescaler_typ_pvt_t, 1);
180
181 if (!pvt)
182 {
183 fprintf(stderr, "Out of memory in gfx_prescale\n");
184 exit(1);
185 }
186
187 pvt->orig_x = orig_x;
188 pvt->orig_y = orig_y;
189 pvt->intermediate = NULL;
190
191 *new_x = orig_x * 3;
192 *new_y = orig_y * 3;
193 *need_inter_vid = 1;
194
195 dr_spec->active_first_x = 0;
196 dr_spec->active_first_y = 8;
197 dr_spec->active_last_x = 3*orig_x - 1;
198 dr_spec->active_last_y = 3*orig_y - 9;
199
200 dr_spec->x_step = 16;
201 dr_spec->y_step = 32;
202
203 dr_spec->pitch = 3*orig_x;
204
205 dr_spec->bord_first_x = 0;
206 dr_spec->bord_first_y = 0;
207 dr_spec->bord_last_x = 3*orig_x - 1;
208 dr_spec->bord_last_y = 3*orig_y - 1;
209
210 return pvt;
211 }
212
gfx_prescaler_scale3x(const uint8_t * RESTRICT src,uint8_t * RESTRICT dst,void * RESTRICT opaque)213 LOCAL void gfx_prescaler_scale3x(const uint8_t *RESTRICT src,
214 uint8_t *RESTRICT dst,
215 void *RESTRICT opaque)
216 {
217 gfx_prescaler_typ_pvt_t *pvt = (gfx_prescaler_typ_pvt_t *)opaque;
218 int orig_x = pvt->orig_x,
219 orig_y = pvt->orig_y,
220 src_pitch = orig_x,
221 dst_pitch = orig_x * 3;
222 const uint8_t *src_prev = src;
223 const uint8_t *src_curr = src;
224 const uint8_t *src_next = src + src_pitch;
225 int y;
226
227 scale3x_8_def((scale3x_uint8 *)(dst ),
228 (scale3x_uint8 *)(dst + dst_pitch * 2),
229 (scale3x_uint8 *)(dst + dst_pitch * 3),
230 (const scale3x_uint8 *)src_prev,
231 (const scale3x_uint8 *)src_curr,
232 (const scale3x_uint8 *)src_next, src_pitch);
233
234 for (y = 3 ; y < orig_y; y++)
235 {
236 dst += dst_pitch * 3;
237 src_prev = src_curr;
238 src_curr = src_next;
239 src_next += src_pitch;
240
241 scale3x_8_def((scale3x_uint8 *)(dst ),
242 (scale3x_uint8 *)(dst + dst_pitch ),
243 (scale3x_uint8 *)(dst + dst_pitch * 2),
244 (const scale3x_uint8 *)src_prev,
245 (const scale3x_uint8 *)src_curr,
246 (const scale3x_uint8 *)src_next, src_pitch);
247 }
248
249 dst += dst_pitch * 3;
250 src_prev = src_curr;
251 src_curr = src_next;
252
253 scale3x_8_def((scale3x_uint8 *)(dst ),
254 (scale3x_uint8 *)(dst + dst_pitch * 2),
255 (scale3x_uint8 *)(dst + dst_pitch * 3),
256 (const scale3x_uint8 *)src_prev,
257 (const scale3x_uint8 *)src_curr,
258 (const scale3x_uint8 *)src_next, src_pitch);
259
260 return;
261 }
262
263 /* ------------------------------------------------------------------------ */
264 /* SCALE4X */
265 /* ------------------------------------------------------------------------ */
gfx_prescaler_scale4x_init(int orig_x,int orig_y,int * RESTRICT new_x,int * RESTRICT new_y,int * RESTRICT need_inter_vid,gfx_dirtyrect_spec * RESTRICT dr_spec)266 LOCAL void *gfx_prescaler_scale4x_init(int orig_x, int orig_y,
267 int *RESTRICT new_x,
268 int *RESTRICT new_y,
269 int *RESTRICT need_inter_vid,
270 gfx_dirtyrect_spec *RESTRICT dr_spec)
271 {
272 gfx_prescaler_typ_pvt_t *pvt = CALLOC(gfx_prescaler_typ_pvt_t, 1);
273 uint8_t *intermediate = CALLOC(uint8_t, orig_x * 2 * orig_y * 2);
274
275 if (!pvt || !intermediate)
276 {
277 fprintf(stderr, "Out of memory in gfx_prescale\n");
278 exit(1);
279 }
280
281 pvt->orig_x = orig_x;
282 pvt->orig_y = orig_y;
283 pvt->intermediate = intermediate;
284
285 *new_x = orig_x * 4;
286 *new_y = orig_y * 4;
287 *need_inter_vid = 1;
288
289 dr_spec->active_first_x = 0;
290 dr_spec->active_first_y = 8;
291 dr_spec->active_last_x = 4*orig_x - 1;
292 dr_spec->active_last_y = 4*orig_y - 9;
293
294 dr_spec->x_step = 16;
295 dr_spec->y_step = 32;
296
297 dr_spec->pitch = 4*orig_x;
298
299 dr_spec->bord_first_x = 0;
300 dr_spec->bord_first_y = 0;
301 dr_spec->bord_last_x = 4*orig_x - 1;
302 dr_spec->bord_last_y = 4*orig_y - 1;
303
304 return pvt;
305 }
306
gfx_prescaler_scale4x(const uint8_t * RESTRICT src,uint8_t * RESTRICT dst,void * RESTRICT opaque)307 LOCAL void gfx_prescaler_scale4x(const uint8_t *RESTRICT src,
308 uint8_t *RESTRICT dst,
309 void *RESTRICT opaque)
310 {
311 gfx_prescaler_typ_pvt_t *pvt = (gfx_prescaler_typ_pvt_t *)opaque;
312 int orig_x = pvt->orig_x, orig_y = pvt->orig_y;
313 uint8_t *mid = pvt->intermediate;
314
315 perform_scale2x_8(orig_x, orig_y, src, mid);
316 perform_scale2x_8(orig_x * 2, orig_y * 2, mid, dst);
317 }
318
319 /* ------------------------------------------------------------------------ */
320 /* SCALEXX destructor */
321 /* ------------------------------------------------------------------------ */
322
gfx_prescaler_scalexx_dtor(void * opaque)323 LOCAL void gfx_prescaler_scalexx_dtor(void *opaque)
324 {
325 gfx_prescaler_typ_pvt_t *pvt = (gfx_prescaler_typ_pvt_t *)opaque;
326
327 if (pvt)
328 {
329 CONDFREE(pvt->intermediate);
330 free(pvt);
331 }
332
333 return;
334 }
335
336 /* ------------------------------------------------------------------------ */
337 /* Rotate-180 Prescaler */
338 /* ------------------------------------------------------------------------ */
gfx_prescaler_rot180_init(int orig_x,int orig_y,int * RESTRICT new_x,int * RESTRICT new_y,int * RESTRICT need_inter_vid,gfx_dirtyrect_spec * RESTRICT dr_spec)339 LOCAL void *gfx_prescaler_rot180_init(int orig_x, int orig_y,
340 int *RESTRICT new_x,
341 int *RESTRICT new_y,
342 int *RESTRICT need_inter_vid,
343 gfx_dirtyrect_spec *RESTRICT dr_spec)
344 {
345 gfx_prescaler_typ_pvt_t *pvt = CALLOC(gfx_prescaler_typ_pvt_t, 1);
346
347 if (!pvt)
348 {
349 fprintf(stderr, "Out of memory in gfx_prescale\n");
350 exit(1);
351 }
352
353 pvt->orig_x = orig_x;
354 pvt->orig_y = orig_y;
355 pvt->intermediate = NULL;
356
357 *new_x = orig_x;
358 *new_y = orig_y;
359 *need_inter_vid = 1;
360
361 dr_spec->active_first_x = 0;
362 dr_spec->active_first_y = 4;
363 dr_spec->active_last_x = orig_x - 1;
364 dr_spec->active_last_y = orig_y - 5;
365
366 dr_spec->x_step = 8;
367 dr_spec->y_step = 16;
368
369 dr_spec->pitch = orig_x;
370
371 dr_spec->bord_first_x = 0;
372 dr_spec->bord_first_y = 0;
373 dr_spec->bord_last_x = orig_x - 1;
374 dr_spec->bord_last_y = orig_y - 1;
375
376 return pvt;
377 }
378
gfx_prescaler_rot180(const uint8_t * RESTRICT src,uint8_t * RESTRICT dst,void * RESTRICT opaque)379 LOCAL void gfx_prescaler_rot180(const uint8_t *RESTRICT src,
380 uint8_t *RESTRICT dst,
381 void *RESTRICT opaque)
382 {
383 gfx_prescaler_typ_pvt_t *pvt = (gfx_prescaler_typ_pvt_t *)opaque;
384 const uint8_t *RESTRICT ps = src;
385 uint8_t *RESTRICT pd = dst + pvt->orig_x * pvt->orig_y - 1;
386 int i = pvt->orig_x * pvt->orig_y;
387
388 while (i-- > 0)
389 *pd-- = *ps++;
390
391 return;
392 }
393
gfx_prescaler_rot180_dtor(void * u)394 LOCAL void gfx_prescaler_rot180_dtor(void *u)
395 {
396 UNUSED(u);
397 return;
398 }
399
400 /* ======================================================================== */
401 /* Prescaler Registry */
402 /* ======================================================================== */
403 gfx_prescaler_registry_t gfx_prescaler_registry[] =
404 {
405 { "None", gfx_prescaler_null,
406 gfx_prescaler_null_init,
407 gfx_prescaler_null_dtor
408 },
409
410 { "Scale2x", gfx_prescaler_scale2x,
411 gfx_prescaler_scale2x_init,
412 gfx_prescaler_scalexx_dtor
413 },
414
415 { "Scale3x", gfx_prescaler_scale3x,
416 gfx_prescaler_scale3x_init,
417 gfx_prescaler_scalexx_dtor
418 },
419
420 { "Scale4x", gfx_prescaler_scale4x,
421 gfx_prescaler_scale4x_init,
422 gfx_prescaler_scalexx_dtor
423 },
424
425 { "Rot180", gfx_prescaler_rot180,
426 gfx_prescaler_rot180_init,
427 gfx_prescaler_rot180_dtor
428 },
429 };
430
431
432 int gfx_prescaler_registry_size = sizeof(gfx_prescaler_registry) /
433 sizeof(gfx_prescaler_registry_t);
434
435