summaryrefslogtreecommitdiff
path: root/apps/plugins/lib/grey_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/lib/grey_core.c')
-rw-r--r--apps/plugins/lib/grey_core.c767
1 files changed, 767 insertions, 0 deletions
diff --git a/apps/plugins/lib/grey_core.c b/apps/plugins/lib/grey_core.c
new file mode 100644
index 0000000000..b3ab640602
--- /dev/null
+++ b/apps/plugins/lib/grey_core.c
@@ -0,0 +1,767 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* New greyscale framework
11* Core & miscellaneous functions
12*
13* This is a generic framework to display 129 shades of grey on low-depth
14* bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins.
15*
16* Copyright (C) 2008 Jens Arnold
17*
18* All files in this archive are subject to the GNU General Public License.
19* See the file COPYING in the source tree root for full license agreement.
20*
21* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22* KIND, either express or implied.
23*
24****************************************************************************/
25
26#include "plugin.h"
27#include "grey.h"
28
29#if defined(CPU_PP) && defined(HAVE_ADJUSTABLE_CPU_FREQ)
30#define NEED_BOOST
31#endif
32
33/* Global variables */
34struct plugin_api *_grey_rb = NULL; /* global api struct pointer */
35struct _grey_info _grey_info; /* global info structure */
36
37#ifndef SIMULATOR
38
39#if CONFIG_LCD == LCD_SSD1815 || CONFIG_LCD == LCD_IFP7XX
40/* measured and interpolated curve */
41/* TODO: check for iFP */
42static const unsigned char lcdlinear[256] = {
43 0, 3, 5, 8, 11, 13, 16, 18,
44 21, 23, 26, 28, 31, 33, 36, 38,
45 40, 42, 45, 47, 49, 51, 53, 55,
46 57, 59, 60, 62, 64, 66, 67, 69,
47 70, 72, 73, 74, 76, 77, 78, 79,
48 81, 82, 83, 84, 85, 86, 87, 88,
49 88, 89, 90, 91, 92, 92, 93, 94,
50 95, 95, 96, 97, 97, 98, 99, 99,
51 100, 101, 102, 102, 103, 104, 104, 105,
52 106, 106, 107, 107, 108, 109, 109, 110,
53 111, 111, 112, 113, 113, 114, 114, 115,
54 116, 116, 117, 117, 118, 119, 119, 120,
55 120, 121, 121, 122, 122, 123, 123, 124,
56 124, 125, 125, 126, 126, 127, 127, 128,
57 128, 128, 129, 129, 130, 130, 131, 131,
58 132, 132, 133, 133, 133, 134, 134, 135,
59 135, 136, 136, 137, 137, 138, 138, 138,
60 139, 139, 140, 140, 141, 141, 142, 142,
61 143, 143, 144, 144, 145, 145, 146, 146,
62 147, 147, 148, 148, 148, 149, 149, 150,
63 150, 151, 151, 152, 152, 153, 153, 153,
64 154, 154, 155, 155, 156, 156, 157, 157,
65 158, 158, 158, 159, 159, 160, 160, 161,
66 161, 162, 162, 163, 163, 164, 164, 165,
67 165, 166, 167, 167, 168, 168, 169, 169,
68 170, 171, 171, 172, 173, 173, 174, 175,
69 176, 176, 177, 178, 179, 180, 181, 181,
70 182, 183, 184, 185, 186, 188, 189, 190,
71 191, 192, 194, 195, 196, 198, 199, 201,
72 202, 204, 205, 207, 209, 211, 213, 215,
73 217, 219, 222, 224, 226, 229, 231, 234,
74 236, 239, 242, 244, 247, 250, 252, 255
75};
76#elif CONFIG_LCD == LCD_S1D15E06
77/* measured and interpolated curve */
78static const unsigned char lcdlinear[256] = {
79 0, 5, 11, 16, 21, 27, 32, 37,
80 42, 47, 51, 56, 60, 64, 68, 72,
81 75, 78, 81, 84, 87, 89, 91, 93,
82 95, 96, 98, 99, 101, 102, 103, 104,
83 105, 106, 107, 108, 109, 110, 111, 111,
84 112, 113, 113, 114, 115, 115, 116, 117,
85 117, 118, 118, 119, 119, 120, 120, 121,
86 121, 122, 122, 123, 123, 124, 124, 125,
87 125, 126, 126, 127, 127, 127, 128, 128,
88 129, 129, 130, 130, 131, 131, 132, 132,
89 133, 133, 134, 134, 135, 135, 136, 136,
90 137, 137, 138, 138, 138, 139, 139, 140,
91 140, 141, 141, 141, 142, 142, 143, 143,
92 143, 144, 144, 145, 145, 145, 146, 146,
93 146, 147, 147, 147, 148, 148, 149, 149,
94 149, 150, 150, 150, 151, 151, 151, 152,
95 152, 153, 153, 153, 154, 154, 155, 155,
96 155, 156, 156, 157, 157, 157, 158, 158,
97 159, 159, 159, 160, 160, 161, 161, 162,
98 162, 162, 163, 163, 164, 164, 164, 165,
99 165, 166, 166, 167, 167, 167, 168, 168,
100 169, 169, 170, 170, 170, 171, 171, 172,
101 172, 173, 173, 174, 174, 175, 175, 176,
102 176, 177, 177, 178, 178, 179, 179, 180,
103 180, 181, 182, 182, 183, 184, 184, 185,
104 186, 186, 187, 188, 188, 189, 190, 191,
105 191, 192, 193, 194, 195, 196, 196, 197,
106 198, 199, 200, 201, 202, 203, 204, 205,
107 206, 207, 208, 209, 210, 211, 213, 214,
108 215, 216, 218, 219, 220, 222, 223, 225,
109 227, 228, 230, 232, 233, 235, 237, 239,
110 241, 243, 245, 247, 249, 251, 253, 255
111};
112#elif (CONFIG_LCD == LCD_IPOD2BPP) || (CONFIG_LCD == LCD_IPODMINI)
113/* measured and interpolated curve for mini LCD */
114/* TODO: verify this curve on the fullsize greyscale LCD */
115static const unsigned char lcdlinear[256] = {
116 0, 3, 6, 8, 11, 14, 17, 19,
117 22, 24, 27, 29, 32, 34, 36, 38,
118 40, 42, 44, 45, 47, 48, 50, 51,
119 52, 54, 55, 56, 57, 58, 58, 59,
120 60, 61, 62, 62, 63, 64, 64, 65,
121 66, 66, 67, 67, 68, 68, 69, 69,
122 70, 70, 70, 71, 71, 71, 72, 72,
123 73, 73, 73, 74, 74, 74, 74, 75,
124 75, 75, 76, 76, 76, 77, 77, 77,
125 78, 78, 78, 79, 79, 79, 80, 80,
126 80, 80, 81, 81, 81, 82, 82, 82,
127 83, 83, 83, 84, 84, 84, 85, 85,
128 85, 85, 86, 86, 86, 87, 87, 87,
129 87, 88, 88, 88, 89, 89, 89, 89,
130 90, 90, 90, 91, 91, 91, 92, 92,
131 92, 93, 93, 93, 94, 94, 94, 95,
132 95, 96, 96, 96, 97, 97, 98, 98,
133 99, 99, 99, 100, 100, 101, 101, 102,
134 102, 103, 103, 104, 104, 105, 105, 106,
135 106, 107, 107, 108, 108, 109, 109, 110,
136 110, 111, 111, 112, 113, 113, 114, 114,
137 115, 115, 116, 117, 117, 118, 118, 119,
138 120, 120, 121, 122, 122, 123, 124, 124,
139 125, 126, 126, 127, 128, 128, 129, 130,
140 131, 131, 132, 133, 134, 134, 135, 136,
141 137, 138, 139, 140, 141, 142, 143, 144,
142 145, 146, 147, 148, 149, 150, 152, 153,
143 154, 156, 157, 159, 160, 162, 163, 165,
144 167, 168, 170, 172, 174, 176, 178, 180,
145 182, 184, 187, 189, 192, 194, 197, 200,
146 203, 206, 209, 212, 215, 219, 222, 226,
147 229, 233, 236, 240, 244, 248, 251, 255
148};
149#endif
150#else /* SIMULATOR */
151/* undo a (generic) PC display gamma of 2.0 to simulate target behaviour */
152static const unsigned char lcdlinear[256] = {
153 0, 16, 23, 28, 32, 36, 39, 42,
154 45, 48, 50, 53, 55, 58, 60, 62,
155 64, 66, 68, 70, 71, 73, 75, 77,
156 78, 80, 81, 83, 84, 86, 87, 89,
157 90, 92, 93, 94, 96, 97, 98, 100,
158 101, 102, 103, 105, 106, 107, 108, 109,
159 111, 112, 113, 114, 115, 116, 117, 118,
160 119, 121, 122, 123, 124, 125, 126, 127,
161 128, 129, 130, 131, 132, 133, 134, 135,
162 135, 136, 137, 138, 139, 140, 141, 142,
163 143, 144, 145, 145, 146, 147, 148, 149,
164 150, 151, 151, 152, 153, 154, 155, 156,
165 156, 157, 158, 159, 160, 160, 161, 162,
166 163, 164, 164, 165, 166, 167, 167, 168,
167 169, 170, 170, 171, 172, 173, 173, 174,
168 175, 176, 176, 177, 178, 179, 179, 180,
169 181, 181, 182, 183, 183, 184, 185, 186,
170 186, 187, 188, 188, 189, 190, 190, 191,
171 192, 192, 193, 194, 194, 195, 196, 196,
172 197, 198, 198, 199, 199, 200, 201, 201,
173 202, 203, 203, 204, 204, 205, 206, 206,
174 207, 208, 208, 209, 209, 210, 211, 211,
175 212, 212, 213, 214, 214, 215, 215, 216,
176 217, 217, 218, 218, 219, 220, 220, 221,
177 221, 222, 222, 223, 224, 224, 225, 225,
178 226, 226, 227, 228, 228, 229, 229, 230,
179 230, 231, 231, 232, 233, 233, 234, 234,
180 235, 235, 236, 236, 237, 237, 238, 238,
181 239, 240, 240, 241, 241, 242, 242, 243,
182 243, 244, 244, 245, 245, 246, 246, 247,
183 247, 248, 248, 249, 249, 250, 250, 251,
184 251, 252, 252, 253, 253, 254, 254, 255
185};
186#endif /* SIMULATOR */
187
188/* Prototypes */
189static inline void _deferred_update(void) __attribute__ ((always_inline));
190static int exp_s16p16(int x);
191static int log_s16p16(int x);
192static void grey_screendump_hook(int fd);
193#ifdef SIMULATOR
194static unsigned long _grey_get_pixel(int x, int y);
195#else
196static void _timer_isr(void);
197#endif
198
199/* Update LCD areas not covered by the greyscale overlay */
200static inline void _deferred_update(void)
201{
202 int x1 = MAX(_grey_info.x, 0);
203 int x2 = MIN(_grey_info.x + _grey_info.width, LCD_WIDTH);
204 int y1 = MAX(_grey_info.y, 0);
205 int y2 = MIN(_grey_info.y + _grey_info.height, LCD_HEIGHT);
206
207 if (y1 > 0) /* refresh part above overlay, full width */
208 _grey_rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
209
210 if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
211 _grey_rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
212
213 if (x1 > 0) /* refresh part to the left of overlay */
214 _grey_rb->lcd_update_rect(0, y1, x1, y2 - y1);
215
216 if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */
217 _grey_rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
218}
219
220#ifndef SIMULATOR
221/* Timer interrupt handler: display next frame */
222static void _timer_isr(void)
223{
224#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
225 _grey_rb->lcd_grey_phase_blit(_grey_info.data, _grey_info.bx, _grey_info.y,
226 _grey_info.bwidth, _grey_info.height,
227 _grey_info.width);
228#else
229 _grey_rb->lcd_grey_phase_blit(_grey_info.data, _grey_info.x, _grey_info.by,
230 _grey_info.width, _grey_info.bheight,
231 _grey_info.width);
232#endif
233
234 if (_grey_info.flags & _GREY_DEFERRED_UPDATE) /* lcd_update() requested? */
235 {
236 _deferred_update();
237 _grey_info.flags &= ~_GREY_DEFERRED_UPDATE; /* clear request */
238 }
239}
240#endif /* !SIMULATOR */
241
242/* fixed point exp() */
243static int exp_s16p16(int x)
244{
245 int t;
246 int y = 0x00010000;
247
248 if (x < 0) x += 0xb1721, y >>= 16;
249 t = x - 0x58b91; if (t >= 0) x = t, y <<= 8;
250 t = x - 0x2c5c8; if (t >= 0) x = t, y <<= 4;
251 t = x - 0x162e4; if (t >= 0) x = t, y <<= 2;
252 t = x - 0x0b172; if (t >= 0) x = t, y <<= 1;
253 t = x - 0x067cd; if (t >= 0) x = t, y += y >> 1;
254 t = x - 0x03920; if (t >= 0) x = t, y += y >> 2;
255 t = x - 0x01e27; if (t >= 0) x = t, y += y >> 3;
256 t = x - 0x00f85; if (t >= 0) x = t, y += y >> 4;
257 t = x - 0x007e1; if (t >= 0) x = t, y += y >> 5;
258 t = x - 0x003f8; if (t >= 0) x = t, y += y >> 6;
259 t = x - 0x001fe; if (t >= 0) x = t, y += y >> 7;
260 y += ((y >> 8) * x) >> 8;
261
262 return y;
263}
264
265/* fixed point log() */
266static int log_s16p16(int x)
267{
268 int t;
269 int y = 0xa65af;
270
271 if (x < 0x00008000) x <<=16, y -= 0xb1721;
272 if (x < 0x00800000) x <<= 8, y -= 0x58b91;
273 if (x < 0x08000000) x <<= 4, y -= 0x2c5c8;
274 if (x < 0x20000000) x <<= 2, y -= 0x162e4;
275 if (x < 0x40000000) x <<= 1, y -= 0x0b172;
276 t = x + (x >> 1); if ((t & 0x80000000) == 0) x = t, y -= 0x067cd;
277 t = x + (x >> 2); if ((t & 0x80000000) == 0) x = t, y -= 0x03920;
278 t = x + (x >> 3); if ((t & 0x80000000) == 0) x = t, y -= 0x01e27;
279 t = x + (x >> 4); if ((t & 0x80000000) == 0) x = t, y -= 0x00f85;
280 t = x + (x >> 5); if ((t & 0x80000000) == 0) x = t, y -= 0x007e1;
281 t = x + (x >> 6); if ((t & 0x80000000) == 0) x = t, y -= 0x003f8;
282 t = x + (x >> 7); if ((t & 0x80000000) == 0) x = t, y -= 0x001fe;
283 x = 0x80000000 - x;
284 y -= x >> 15;
285
286 return y;
287}
288
289/* Initialise the framework and prepare the greyscale display buffer
290
291 arguments:
292 newrb = pointer to plugin api
293 gbuf = pointer to the memory area to use (e.g. plugin buffer)
294 gbuf_size = max usable size of the buffer
295 buffered = use chunky pixel buffering?
296 This allows to use all drawing functions, but needs more
297 memory. Unbuffered operation provides only a subset of
298 drawing functions. (only grey_bitmap drawing and scrolling)
299 width = width in pixels (1..LCD_WIDTH)
300 height = height in pixels (1..LCD_HEIGHT)
301 Note that depending on the target LCD, either height or
302 width are rounded up to a multiple of 4 or 8.
303
304 result:
305 true on success, false on failure
306
307 If you need info about the memory taken by the greyscale buffer, supply a
308 long* as the last parameter. This long will then contain the number of bytes
309 used. The total memory needed can be calculated as follows:
310 total_mem =
311 width * height * 2 [grey display data]
312 + buffered ? (width * height) : 0 [chunky buffer]
313 + 0..3 [alignment]
314
315 The function is authentic regarding memory usage on the simulator, even
316 if it doesn't use all of the allocated memory. */
317bool grey_init(struct plugin_api* newrb, unsigned char *gbuf, long gbuf_size,
318 bool buffered, int width, int height, long *buf_taken)
319{
320 int bdim, i;
321 long plane_size, buftaken;
322 unsigned data;
323#ifndef SIMULATOR
324 struct grey_data *grey_data, *grey_end;
325#endif
326
327 _grey_rb = newrb;
328
329 if ((unsigned) width > LCD_WIDTH
330 || (unsigned) height > LCD_HEIGHT)
331 return false;
332
333#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
334 bdim = (width + 7) >> 3;
335 width = bdim << 3;
336#else /* vertical packing */
337#if LCD_DEPTH == 1
338 bdim = (height + 7) >> 3;
339 height = bdim << 3;
340#elif LCD_DEPTH == 2
341 bdim = (height + 3) >> 2;
342 height = bdim << 2;
343#endif
344#endif
345
346 /* the buffer has to be long aligned */
347 buftaken = (-(long)gbuf) & 3;
348 gbuf += buftaken;
349
350 plane_size = _GREY_MULUQ(width, height);
351
352 if (buffered) /* chunky buffer */
353 {
354 buftaken += plane_size;
355 _grey_info.buffer = gbuf;
356 gbuf += plane_size;
357 }
358 buftaken += sizeof(struct grey_data) * plane_size;
359 if (buftaken > gbuf_size)
360 return false;
361
362#ifdef SIMULATOR
363 _grey_info.buffer = gbuf;
364#else
365 grey_data = (struct grey_data *)gbuf;
366 grey_end = grey_data + plane_size;
367 _grey_info.data = grey_data;
368
369 while (grey_data < grey_end)
370 {
371 grey_data->phase = _grey_rb->rand() & 0xff;
372 grey_data->value = 128; /* init to white */
373 grey_data++;
374 }
375#endif
376
377 _grey_info.x = 0;
378 _grey_info.y = 0;
379 _grey_info.width = width;
380 _grey_info.height = height;
381#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
382 _grey_info.bx = 0;
383 _grey_info.bwidth = bdim;
384#else
385 _grey_info.by = 0;
386 _grey_info.bheight = bdim;
387#endif
388 _grey_info.flags = 0;
389 _grey_info.fg_val = 0;
390 _grey_info.bg_val = 128;
391 _grey_info.fg_brightness = 0;
392 _grey_info.bg_brightness = 255;
393 _grey_info.drawmode = DRMODE_SOLID;
394 _grey_info.curfont = FONT_SYSFIXED;
395
396
397 /* precalculate the value -> pattern index conversion table, taking
398 linearisation and gamma correction into account */
399 for (i = 0; i < 256; i++)
400 {
401 data = exp_s16p16(((2<<8) * log_s16p16(i * 257 + 1)) >> 8) + 128;
402 data = (data - (data >> 8)) >> 8; /* approx. data /= 257 */
403 data = (lcdlinear[data] << 7) + 127;
404 _grey_info.gvalue[i] = (data + (data >> 8)) >> 8;
405 /* approx. data / 255 */
406 }
407
408 if (buf_taken) /* caller requested info about space taken */
409 *buf_taken = buftaken;
410
411 return true;
412}
413
414/* Release the greyscale display buffer and the library
415 DO CALL either this function or at least grey_show_display(false)
416 before you exit, otherwise nasty things may happen. */
417void grey_release(void)
418{
419 grey_show(false);
420}
421
422/* Switch the greyscale overlay on or off
423 DO NOT call lcd_update() or any other api function that directly accesses
424 the lcd while the greyscale overlay is running! If you need to do
425 lcd_update() to update something outside the greyscale overlay area, use
426 grey_deferred_update() instead.
427
428 Other functions to avoid are:
429 lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(),
430 lcd_set_invert_display(), lcd_set_flip() */
431void grey_show(bool enable)
432{
433 if (enable && !(_grey_info.flags & _GREY_RUNNING))
434 {
435 _grey_info.flags |= _GREY_RUNNING;
436#ifdef SIMULATOR
437 _grey_rb->sim_lcd_ex_init(129, _grey_get_pixel);
438 grey_update();
439#else /* !SIMULATOR */
440#ifdef NEED_BOOST
441 _grey_rb->cpu_boost(true);
442#endif
443#if CONFIG_LCD == LCD_SSD1815
444 _grey_rb->timer_register(1, NULL, TIMER_FREQ / 67, 1, _timer_isr);
445#elif CONFIG_LCD == LCD_S1D15E06
446 _grey_rb->timer_register(1, NULL, TIMER_FREQ / 70, 1, _timer_isr);
447#elif CONFIG_LCD == LCD_IPOD2BPP
448#ifdef IPOD_1G2G
449 _grey_rb->timer_register(1, NULL, TIMER_FREQ / 95, 1, _timer_isr); /* verified */
450#elif defined IPOD_3G
451 _grey_rb->timer_register(1, NULL, TIMER_FREQ / 87, 1, _timer_isr); /* verified */
452#else
453 /* FIXME: verify value */
454 _grey_rb->timer_register(1, NULL, TIMER_FREQ / 80, 1, _timer_isr);
455#endif
456#elif CONFIG_LCD == LCD_IPODMINI
457 _grey_rb->timer_register(1, NULL, TIMER_FREQ / 88, 1, _timer_isr);
458#elif CONFIG_LCD == LCD_IFP7XX
459 _grey_rb->timer_register(1, NULL, TIMER_FREQ / 83, 1, _timer_isr);
460#endif /* CONFIG_LCD */
461#endif /* !SIMULATOR */
462 _grey_rb->screen_dump_set_hook(grey_screendump_hook);
463 }
464 else if (!enable && (_grey_info.flags & _GREY_RUNNING))
465 {
466#ifdef SIMULATOR
467 _grey_rb->sim_lcd_ex_init(0, NULL);
468#else
469 _grey_rb->timer_unregister();
470#ifdef NEED_BOOST
471 _grey_rb->cpu_boost(false);
472#endif
473#endif
474 _grey_info.flags &= ~_GREY_RUNNING;
475 _grey_rb->screen_dump_set_hook(NULL);
476 _grey_rb->lcd_update(); /* restore whatever there was before */
477 }
478}
479
480#ifdef SIMULATOR
481/* Callback function for grey_update_rect() to read a pixel from the greybuffer.
482 Note that x and y are in LCD coordinates, not greybuffer coordinates! */
483static unsigned long _grey_get_pixel(int x, int y)
484{
485 return _grey_info.buffer[(y - _grey_info.y) * _grey_info.width
486 + x - _grey_info.x] + (1 << LCD_DEPTH);
487}
488
489/* Update a rectangular area of the greyscale overlay */
490void grey_update_rect(int x, int y, int width, int height)
491{
492 if (x + width > _grey_info.width)
493 width = _grey_info.width - x;
494 if (y + height > _grey_info.height)
495 height = _grey_info.height - y;
496
497 x += _grey_info.x;
498 y += _grey_info.y;
499
500 if (x + width > LCD_WIDTH)
501 width = LCD_WIDTH - x;
502 if (y + height > LCD_HEIGHT)
503 height = LCD_HEIGHT - y;
504
505 _grey_rb->sim_lcd_ex_update_rect(x, y, width, height);
506}
507
508#else /* !SIMULATOR */
509
510void grey_update_rect(int x, int y, int width, int height)
511{
512 unsigned char *src;
513
514 if ((width <= 0) || (height <= 0))
515 return; /* nothing to do */
516
517 if (y + height > _grey_info.height)
518 height = _grey_info.height - y;
519 if (x + width > _grey_info.width)
520 width = _grey_info.width - x;
521
522 src = _grey_info.buffer + _GREY_MULUQ(_grey_info.width, y) + x;
523
524 do
525 {
526#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
527 int idx = _GREY_MULUQ(_grey_info.width, y) + x;
528#else
529#if LCD_DEPTH == 1
530 int idx = _GREY_MULUQ(_grey_info.width, y & ~7) + (x << 3) + (~y & 7);
531#elif LCD_DEPTH == 2
532 int idx = _GREY_MULUQ(_grey_info.width, y & ~3) + (x << 2) + (~y & 3);
533#endif
534#endif /* LCD_PIXELFORMAT */
535 unsigned char *dst_row = &_grey_info.data[idx].value;
536 unsigned char *src_row = src;
537 unsigned char *src_end = src + width;
538
539 do
540 {
541 *dst_row = *src_row++;
542 dst_row += _GREY_X_ADVANCE;
543 }
544 while (src_row < src_end);
545
546 y++;
547 src += _grey_info.width;
548 }
549 while (--height > 0);
550}
551
552#endif /* !SIMULATOR */
553
554/* Update the whole greyscale overlay */
555void grey_update(void)
556{
557 grey_update_rect(0, 0, _grey_info.width, _grey_info.height);
558}
559
560/* Do an lcd_update() to show changes done by rb->lcd_xxx() functions
561 (in areas of the screen not covered by the greyscale overlay). */
562void grey_deferred_lcd_update(void)
563{
564 if (_grey_info.flags & _GREY_RUNNING)
565 {
566#ifdef SIMULATOR
567 _deferred_update();
568#else
569 _grey_info.flags |= _GREY_DEFERRED_UPDATE;
570#endif
571 }
572 else
573 _grey_rb->lcd_update();
574}
575
576/*** Screenshot ***/
577
578#define BMP_FIXEDCOLORS (1 << LCD_DEPTH)
579#define BMP_VARCOLORS 129
580#define BMP_NUMCOLORS (BMP_FIXEDCOLORS + BMP_VARCOLORS)
581#define BMP_BPP 8
582#define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
583#define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
584#define BMP_DATASIZE (BMP_LINESIZE * LCD_HEIGHT)
585#define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
586
587#define LE16_CONST(x) (x)&0xff, ((x)>>8)&0xff
588#define LE32_CONST(x) (x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff
589
590static const unsigned char bmpheader[] =
591{
592 0x42, 0x4d, /* 'BM' */
593 LE32_CONST(BMP_TOTALSIZE), /* Total file size */
594 0x00, 0x00, 0x00, 0x00, /* Reserved */
595 LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */
596
597 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
598 LE32_CONST(LCD_WIDTH), /* Width in pixels */
599 LE32_CONST(LCD_HEIGHT), /* Height in pixels */
600 0x01, 0x00, /* Number of planes (always 1) */
601 LE16_CONST(BMP_BPP), /* Bits per pixel 1/4/8/16/24 */
602 0x00, 0x00, 0x00, 0x00, /* Compression mode, 0 = none */
603 LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */
604 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
605 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
606 LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */
607 LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */
608
609 /* Fixed colours */
610#if LCD_DEPTH == 1
611 0x90, 0xee, 0x90, 0x00, /* Colour #0 */
612 0x00, 0x00, 0x00, 0x00 /* Colour #1 */
613#elif LCD_DEPTH == 2
614 0xe6, 0xd8, 0xad, 0x00, /* Colour #0 */
615 0x99, 0x90, 0x73, 0x00, /* Colour #1 */
616 0x4c, 0x48, 0x39, 0x00, /* Colour #2 */
617 0x00, 0x00, 0x00, 0x00 /* Colour #3 */
618#endif
619};
620
621#if LCD_DEPTH == 1
622#define BMP_RED 0x90
623#define BMP_GREEN 0xee
624#define BMP_BLUE 0x90
625#elif LCD_DEPTH == 2
626#define BMP_RED 0xad
627#define BMP_GREEN 0xd8
628#define BMP_BLUE 0xe6
629#endif
630
631/* Hook function for core screen_dump() to save the current display
632 content (b&w and greyscale overlay) to an 8-bit BMP file. */
633static void grey_screendump_hook(int fd)
634{
635 int i;
636 int x, y, gx, gy;
637#if LCD_PIXELFORMAT == VERTICAL_PACKING
638#if LCD_DEPTH == 1
639 unsigned mask;
640#elif LCD_DEPTH == 2
641 int shift;
642#endif
643#endif /* LCD_PIXELFORMAT == VERTICAL_PACKING */
644 unsigned char *lcdptr;
645 unsigned char *clut_entry;
646 unsigned char linebuf[MAX(4*BMP_VARCOLORS,BMP_LINESIZE)];
647
648 _grey_rb->write(fd, bmpheader, sizeof(bmpheader)); /* write header */
649
650 /* build clut */
651 _grey_rb->memset(linebuf, 0, 4*BMP_VARCOLORS);
652 clut_entry = linebuf;
653
654 for (i = 0; i <= 128; i++)
655 {
656 *clut_entry++ = _GREY_MULUQ(BMP_BLUE, i) >> 7;
657 *clut_entry++ = _GREY_MULUQ(BMP_GREEN, i) >> 7;
658 *clut_entry++ = _GREY_MULUQ(BMP_RED, i) >> 7;
659 clut_entry++;
660 }
661 _grey_rb->write(fd, linebuf, 4*BMP_VARCOLORS);
662
663 /* BMP image goes bottom -> top */
664 for (y = LCD_HEIGHT - 1; y >= 0; y--)
665 {
666 _grey_rb->memset(linebuf, 0, BMP_LINESIZE);
667
668 gy = y - _grey_info.y;
669#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
670#if LCD_DEPTH == 2
671 lcdptr = _grey_rb->lcd_framebuffer + _GREY_MULUQ(LCD_FBWIDTH, y);
672
673 for (x = 0; x < LCD_WIDTH; x += 4)
674 {
675 gx = x - _grey_info.x;
676
677 if (((unsigned)gy < (unsigned)_grey_info.height)
678 && ((unsigned)gx < (unsigned)_grey_info.width))
679 {
680#ifdef SIMULATOR
681 unsigned char *src = _grey_info.buffer
682 + _GREY_MULUQ(_grey_info.width, gy) + gx;
683
684 for (i = 0; i < 4; i++)
685 linebuf[x + i] = BMP_FIXEDCOLORS + *src++;
686#else
687 unsigned char *src = &_grey_info.data[_GREY_MULUQ(_grey_info.width,
688 gy) + gx].value;
689 for (i = 0; i < 4; i++)
690 {
691 linebuf[x + i] = BMP_FIXEDCOLORS + *src;
692 src += _GREY_X_ADVANCE;
693 }
694#endif
695 }
696 else
697 {
698 unsigned data = *lcdptr;
699 linebuf[x] = (data >> 6) & 3;
700 linebuf[x + 1] = (data >> 4) & 3;
701 linebuf[x + 2] = (data >> 2) & 3;
702 linebuf[x + 3] = data & 3;
703 }
704 lcdptr++;
705 }
706#endif /* LCD_DEPTH */
707#else /* LCD_PIXELFORMAT == VERTICAL_PACKING */
708#if LCD_DEPTH == 1
709 mask = 1 << (y & 7);
710 lcdptr = _grey_rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3);
711
712 for (x = 0; x < LCD_WIDTH; x++)
713 {
714 gx = x - _grey_info.x;
715
716 if (((unsigned)gy < (unsigned)_grey_info.height)
717 && ((unsigned)gx < (unsigned)_grey_info.width))
718 {
719#ifdef SIMULATOR
720 linebuf[x] = BMP_FIXEDCOLORS
721 + _grey_info.buffer[_GREY_MULUQ(_grey_info.width,
722 gy) + gx];
723#else
724 linebuf[x] = BMP_FIXEDCOLORS
725 + _grey_info.data[_GREY_MULUQ(_grey_info.width,
726 gy & ~7) + (gx << 3) + (~gy & 7)].value;
727#endif
728 }
729 else
730 {
731 linebuf[x] = (*lcdptr & mask) ? 1 : 0;
732 }
733 lcdptr++;
734 }
735#elif LCD_DEPTH == 2
736 shift = 2 * (y & 3);
737 lcdptr = _grey_rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 2);
738
739 for (x = 0; x < LCD_WIDTH; x++)
740 {
741 gx = x - _grey_info.x;
742
743 if (((unsigned)gy < (unsigned)_grey_info.height)
744 && ((unsigned)gx < (unsigned)_grey_info.width))
745 {
746#ifdef SIMULATOR
747 linebuf[x] = BMP_FIXEDCOLORS
748 + _grey_info.buffer[_GREY_MULUQ(_grey_info.width,
749 gy) + gx];
750#else
751 linebuf[x] = BMP_FIXEDCOLORS
752 + _grey_info.data[_GREY_MULUQ(_grey_info.width,
753 gy & ~3) + (gx << 2) + (~gy & 7)].value;
754#endif
755 }
756 else
757 {
758 linebuf[x] = (*lcdptr >> shift) & 3;
759 }
760 lcdptr++;
761 }
762#endif /* LCD_DEPTH */
763#endif /* LCD_PIXELFORMAT */
764
765 _grey_rb->write(fd, linebuf, BMP_LINESIZE);
766 }
767}