summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/lcd-16bit-common.c574
-rw-r--r--firmware/drivers/lcd-16bit.c12
-rw-r--r--firmware/drivers/lcd-color-common.c605
3 files changed, 616 insertions, 575 deletions
diff --git a/firmware/drivers/lcd-16bit-common.c b/firmware/drivers/lcd-16bit-common.c
index 93e7c2e012..d006b3900a 100644
--- a/firmware/drivers/lcd-16bit-common.c
+++ b/firmware/drivers/lcd-16bit-common.c
@@ -28,44 +28,6 @@
28#error ROW_INC or COL_INC not defined 28#error ROW_INC or COL_INC not defined
29#endif 29#endif
30 30
31enum fill_opt {
32 OPT_NONE = 0,
33 OPT_SET,
34 OPT_COPY
35};
36
37/*** globals ***/
38fb_data lcd_static_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH]
39 IRAM_LCDFRAMEBUFFER CACHEALIGN_AT_LEAST_ATTR(16);
40fb_data *lcd_framebuffer = &lcd_static_framebuffer[0][0];
41
42static fb_data* lcd_backdrop = NULL;
43static long lcd_backdrop_offset IDATA_ATTR = 0;
44
45static struct viewport default_vp =
46{
47 .x = 0,
48 .y = 0,
49 .width = LCD_WIDTH,
50 .height = LCD_HEIGHT,
51 .font = FONT_SYSFIXED,
52 .drawmode = DRMODE_SOLID,
53 .fg_pattern = LCD_DEFAULT_FG,
54 .bg_pattern = LCD_DEFAULT_BG,
55};
56
57static struct viewport* current_vp IDATA_ATTR = &default_vp;
58
59/* LCD init */
60void lcd_init(void)
61{
62 lcd_clear_display();
63
64 /* Call device specific init */
65 lcd_init_device();
66 scroll_init();
67}
68
69/* Clear the current viewport */ 31/* Clear the current viewport */
70void lcd_clear_viewport(void) 32void lcd_clear_viewport(void)
71{ 33{
@@ -146,70 +108,6 @@ void lcd_clear_viewport(void)
146 lcd_scroll_stop_viewport(current_vp); 108 lcd_scroll_stop_viewport(current_vp);
147} 109}
148 110
149/*** parameter handling ***/
150
151void lcd_set_drawmode(int mode)
152{
153 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
154}
155
156int lcd_get_drawmode(void)
157{
158 return current_vp->drawmode;
159}
160
161void lcd_set_foreground(unsigned color)
162{
163 current_vp->fg_pattern = color;
164}
165
166unsigned lcd_get_foreground(void)
167{
168 return current_vp->fg_pattern;
169}
170
171void lcd_set_background(unsigned color)
172{
173 current_vp->bg_pattern = color;
174}
175
176unsigned lcd_get_background(void)
177{
178 return current_vp->bg_pattern;
179}
180
181void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color)
182{
183 lcd_set_drawmode(mode);
184 current_vp->fg_pattern = fg_color;
185 current_vp->bg_pattern = bg_color;
186}
187
188int lcd_getwidth(void)
189{
190 return current_vp->width;
191}
192
193int lcd_getheight(void)
194{
195 return current_vp->height;
196}
197
198void lcd_setfont(int newfont)
199{
200 current_vp->font = newfont;
201}
202
203int lcd_getfont(void)
204{
205 return current_vp->font;
206}
207
208int lcd_getstringsize(const unsigned char *str, int *w, int *h)
209{
210 return font_getstringsize(str, w, h, current_vp->font);
211}
212
213/*** low-level drawing functions ***/ 111/*** low-level drawing functions ***/
214 112
215static void ICODE_ATTR setpixel(fb_data *address) 113static void ICODE_ATTR setpixel(fb_data *address)
@@ -249,155 +147,6 @@ lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[8] = {
249 147
250lcd_fastpixelfunc_type* const * lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor; 148lcd_fastpixelfunc_type* const * lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor;
251 149
252void lcd_set_backdrop(fb_data* backdrop)
253{
254 lcd_backdrop = backdrop;
255 if (backdrop)
256 {
257 lcd_backdrop_offset = (long)backdrop - (long)lcd_framebuffer;
258 lcd_fastpixelfuncs = lcd_fastpixelfuncs_backdrop;
259 }
260 else
261 {
262 lcd_backdrop_offset = 0;
263 lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor;
264 }
265}
266
267fb_data* lcd_get_backdrop(void)
268{
269 return lcd_backdrop;
270}
271
272/* Clear the whole display */
273void lcd_clear_display(void)
274{
275 struct viewport* old_vp = current_vp;
276
277 current_vp = &default_vp;
278
279 lcd_clear_viewport();
280
281 current_vp = old_vp;
282}
283
284/* Set a single pixel */
285void lcd_drawpixel(int x, int y)
286{
287 if ( ((unsigned)x < (unsigned)current_vp->width)
288 && ((unsigned)y < (unsigned)current_vp->height)
289#if defined(HAVE_VIEWPORT_CLIP)
290 && ((unsigned)x < (unsigned)LCD_WIDTH)
291 && ((unsigned)y < (unsigned)LCD_HEIGHT)
292#endif
293 )
294 lcd_fastpixelfuncs[current_vp->drawmode](FBADDR(current_vp->x+x, current_vp->y+y));
295}
296
297/* Draw a line */
298void lcd_drawline(int x1, int y1, int x2, int y2)
299{
300 int numpixels;
301 int i;
302 int deltax, deltay;
303 int d, dinc1, dinc2;
304 int x, xinc1, xinc2;
305 int y, yinc1, yinc2;
306 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
307
308 deltay = abs(y2 - y1);
309 if (deltay == 0)
310 {
311 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
312 lcd_hline(x1, x2, y1);
313 return;
314 }
315 deltax = abs(x2 - x1);
316 if (deltax == 0)
317 {
318 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
319 lcd_vline(x1, y1, y2);
320 return;
321 }
322 xinc2 = 1;
323 yinc2 = 1;
324
325 if (deltax >= deltay)
326 {
327 numpixels = deltax;
328 d = 2 * deltay - deltax;
329 dinc1 = deltay * 2;
330 dinc2 = (deltay - deltax) * 2;
331 xinc1 = 1;
332 yinc1 = 0;
333 }
334 else
335 {
336 numpixels = deltay;
337 d = 2 * deltax - deltay;
338 dinc1 = deltax * 2;
339 dinc2 = (deltax - deltay) * 2;
340 xinc1 = 0;
341 yinc1 = 1;
342 }
343 numpixels++; /* include endpoints */
344
345 if (x1 > x2)
346 {
347 xinc1 = -xinc1;
348 xinc2 = -xinc2;
349 }
350
351 if (y1 > y2)
352 {
353 yinc1 = -yinc1;
354 yinc2 = -yinc2;
355 }
356
357 x = x1;
358 y = y1;
359
360 for (i = 0; i < numpixels; i++)
361 {
362 if ( ((unsigned)x < (unsigned)current_vp->width)
363 && ((unsigned)y < (unsigned)current_vp->height)
364#if defined(HAVE_VIEWPORT_CLIP)
365 && ((unsigned)x < (unsigned)LCD_WIDTH)
366 && ((unsigned)y < (unsigned)LCD_HEIGHT)
367#endif
368 )
369 pfunc(FBADDR(x + current_vp->x, y + current_vp->y));
370
371 if (d < 0)
372 {
373 d += dinc1;
374 x += xinc1;
375 y += yinc1;
376 }
377 else
378 {
379 d += dinc2;
380 x += xinc2;
381 y += yinc2;
382 }
383 }
384}
385
386/* Draw a rectangular box */
387void lcd_drawrect(int x, int y, int width, int height)
388{
389 if ((width <= 0) || (height <= 0))
390 return;
391
392 int x2 = x + width - 1;
393 int y2 = y + height - 1;
394
395 lcd_vline(x, y, y2);
396 lcd_vline(x2, y, y2);
397 lcd_hline(x, x2, y);
398 lcd_hline(x, x2, y2);
399}
400
401/* Fill a rectangular area */ 150/* Fill a rectangular area */
402void lcd_fillrect(int x, int y, int width, int height) 151void lcd_fillrect(int x, int y, int width, int height)
403{ 152{
@@ -1087,326 +836,3 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
1087 836
1088 BLEND_FINISH; 837 BLEND_FINISH;
1089} 838}
1090
1091/* Draw a full native bitmap */
1092void lcd_bitmap(const fb_data *src, int x, int y, int width, int height)
1093{
1094 lcd_bitmap_part(src, 0, 0, STRIDE(SCREEN_MAIN, width, height), x, y, width, height);
1095}
1096
1097/* Draw a full native bitmap with a transparent color */
1098void lcd_bitmap_transparent(const fb_data *src, int x, int y,
1099 int width, int height)
1100{
1101 lcd_bitmap_transparent_part(src, 0, 0,
1102 STRIDE(SCREEN_MAIN, width, height), x, y, width, height);
1103}
1104
1105/* draw alpha bitmap for anti-alias font */
1106void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x,
1107 int src_y, int stride, int x, int y,
1108 int width, int height)
1109{
1110 lcd_alpha_bitmap_part_mix(NULL, src, src_x, src_y, x, y, width, height, 0, stride);
1111}
1112
1113/* Draw a partial bitmap (mono or native) including alpha channel */
1114void ICODE_ATTR lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y,
1115 int x, int y, int width, int height)
1116{
1117 int bitmap_stride = STRIDE_MAIN(bm->width, bm->height);
1118 if (bm->format == FORMAT_MONO)
1119 lcd_mono_bitmap_part(bm->data, src_x, src_y, bitmap_stride, x, y, width, height);
1120 else if (bm->alpha_offset > 0)
1121 lcd_alpha_bitmap_part_mix((fb_data*)bm->data, bm->data+bm->alpha_offset,
1122 src_x, src_y, x, y, width, height,
1123 bitmap_stride, ALIGN_UP(bm->width, 2));
1124 else
1125 lcd_bitmap_transparent_part((fb_data*)bm->data,
1126 src_x, src_y, bitmap_stride, x, y, width, height);
1127}
1128
1129/* Draw a native bitmap with alpha channel */
1130void ICODE_ATTR lcd_bmp(const struct bitmap *bmp, int x, int y)
1131{
1132 lcd_bmp_part(bmp, 0, 0, x, y, bmp->width, bmp->height);
1133}
1134
1135/**
1136 * |R| |1.000000 -0.000001 1.402000| |Y'|
1137 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
1138 * |B| |1.000000 1.772000 0.000000| |Pr|
1139 * Scaled, normalized, rounded and tweaked to yield RGB 565:
1140 * |R| |74 0 101| |Y' - 16| >> 9
1141 * |G| = |74 -24 -51| |Cb - 128| >> 8
1142 * |B| |74 128 0| |Cr - 128| >> 9
1143 */
1144#define YFAC (74)
1145#define RVFAC (101)
1146#define GUFAC (-24)
1147#define GVFAC (-51)
1148#define BUFAC (128)
1149
1150static inline int clamp(int val, int min, int max)
1151{
1152 if (val < min)
1153 val = min;
1154 else if (val > max)
1155 val = max;
1156 return val;
1157}
1158
1159#ifndef _WIN32
1160/*
1161 * weak attribute doesn't work for win32 as of gcc 4.6.2 and binutils 2.21.52
1162 * When building win32 simulators, we won't be using an optimized version of
1163 * lcd_blit_yuv(), so just don't use the weak attribute.
1164 */
1165__attribute__((weak))
1166#endif
1167void lcd_yuv_set_options(unsigned options)
1168{
1169 (void)options;
1170}
1171
1172/* Draw a partial YUV colour bitmap */
1173#ifndef _WIN32
1174__attribute__((weak))
1175#endif
1176void lcd_blit_yuv(unsigned char * const src[3],
1177 int src_x, int src_y, int stride,
1178 int x, int y, int width, int height)
1179{
1180 const unsigned char *ysrc, *usrc, *vsrc;
1181 int linecounter;
1182 fb_data *dst, *row_end;
1183 long z;
1184
1185 /* width and height must be >= 2 and an even number */
1186 width &= ~1;
1187 linecounter = height >> 1;
1188
1189#if LCD_WIDTH >= LCD_HEIGHT
1190 dst = FBADDR(x, y);
1191 row_end = dst + width;
1192#else
1193 dst = FBADDR(LCD_WIDTH - y - 1, x);
1194 row_end = dst + LCD_WIDTH * width;
1195#endif
1196
1197 z = stride * src_y;
1198 ysrc = src[0] + z + src_x;
1199 usrc = src[1] + (z >> 2) + (src_x >> 1);
1200 vsrc = src[2] + (usrc - src[1]);
1201
1202 /* stride => amount to jump from end of last row to start of next */
1203 stride -= width;
1204
1205 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
1206
1207 do
1208 {
1209 do
1210 {
1211 int y, cb, cr, rv, guv, bu, r, g, b;
1212
1213 y = YFAC*(*ysrc++ - 16);
1214 cb = *usrc++ - 128;
1215 cr = *vsrc++ - 128;
1216
1217 rv = RVFAC*cr;
1218 guv = GUFAC*cb + GVFAC*cr;
1219 bu = BUFAC*cb;
1220
1221 r = y + rv;
1222 g = y + guv;
1223 b = y + bu;
1224
1225 if ((unsigned)(r | g | b) > 64*256-1)
1226 {
1227 r = clamp(r, 0, 64*256-1);
1228 g = clamp(g, 0, 64*256-1);
1229 b = clamp(b, 0, 64*256-1);
1230 }
1231
1232 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
1233
1234#if LCD_WIDTH >= LCD_HEIGHT
1235 dst++;
1236#else
1237 dst += LCD_WIDTH;
1238#endif
1239
1240 y = YFAC*(*ysrc++ - 16);
1241 r = y + rv;
1242 g = y + guv;
1243 b = y + bu;
1244
1245 if ((unsigned)(r | g | b) > 64*256-1)
1246 {
1247 r = clamp(r, 0, 64*256-1);
1248 g = clamp(g, 0, 64*256-1);
1249 b = clamp(b, 0, 64*256-1);
1250 }
1251
1252 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
1253
1254#if LCD_WIDTH >= LCD_HEIGHT
1255 dst++;
1256#else
1257 dst += LCD_WIDTH;
1258#endif
1259 }
1260 while (dst < row_end);
1261
1262 ysrc += stride;
1263 usrc -= width >> 1;
1264 vsrc -= width >> 1;
1265
1266#if LCD_WIDTH >= LCD_HEIGHT
1267 row_end += LCD_WIDTH;
1268 dst += LCD_WIDTH - width;
1269#else
1270 row_end -= 1;
1271 dst -= LCD_WIDTH*width + 1;
1272#endif
1273
1274 do
1275 {
1276 int y, cb, cr, rv, guv, bu, r, g, b;
1277
1278 y = YFAC*(*ysrc++ - 16);
1279 cb = *usrc++ - 128;
1280 cr = *vsrc++ - 128;
1281
1282 rv = RVFAC*cr;
1283 guv = GUFAC*cb + GVFAC*cr;
1284 bu = BUFAC*cb;
1285
1286 r = y + rv;
1287 g = y + guv;
1288 b = y + bu;
1289
1290 if ((unsigned)(r | g | b) > 64*256-1)
1291 {
1292 r = clamp(r, 0, 64*256-1);
1293 g = clamp(g, 0, 64*256-1);
1294 b = clamp(b, 0, 64*256-1);
1295 }
1296
1297 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
1298
1299#if LCD_WIDTH >= LCD_HEIGHT
1300 dst++;
1301#else
1302 dst += LCD_WIDTH;
1303#endif
1304
1305 y = YFAC*(*ysrc++ - 16);
1306 r = y + rv;
1307 g = y + guv;
1308 b = y + bu;
1309
1310 if ((unsigned)(r | g | b) > 64*256-1)
1311 {
1312 r = clamp(r, 0, 64*256-1);
1313 g = clamp(g, 0, 64*256-1);
1314 b = clamp(b, 0, 64*256-1);
1315 }
1316
1317 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
1318
1319#if LCD_WIDTH >= LCD_HEIGHT
1320 dst++;
1321#else
1322 dst += LCD_WIDTH;
1323#endif
1324 }
1325 while (dst < row_end);
1326
1327 ysrc += stride;
1328 usrc += stride >> 1;
1329 vsrc += stride >> 1;
1330
1331#if LCD_WIDTH >= LCD_HEIGHT
1332 row_end += LCD_WIDTH;
1333 dst += LCD_WIDTH - width;
1334#else
1335 row_end -= 1;
1336 dst -= LCD_WIDTH*width + 1;
1337#endif
1338 }
1339 while (--linecounter > 0);
1340
1341#if LCD_WIDTH >= LCD_HEIGHT
1342 lcd_update_rect(x, y, width, height);
1343#else
1344 lcd_update_rect(LCD_WIDTH - y - height, x, height, width);
1345#endif
1346}
1347
1348/* Fill a rectangle with a gradient. This function draws only the partial
1349 * gradient. It assumes the original gradient is src_height high and skips
1350 * the first few rows. This is useful for drawing only the bottom half of
1351 * a full gradient.
1352 *
1353 * height == src_height and row_skip == 0 will draw the full gradient
1354 *
1355 * x, y, width, height - dimensions describing the rectangle
1356 * start_rgb - beginning color of the gradient
1357 * end_rgb - end color of the gradient
1358 * src_height - assumed original height (only height rows will be drawn)
1359 * row_skip - how many rows of the original gradient to skip
1360 */
1361void lcd_gradient_fillrect_part(int x, int y, int width, int height,
1362 unsigned start_rgb, unsigned end_rgb, int src_height, int row_skip)
1363{
1364 int old_pattern = current_vp->fg_pattern;
1365 int step_mul, i;
1366 int x1, x2;
1367 x1 = x;
1368 x2 = x + width;
1369
1370 if (height == 0) return;
1371
1372 step_mul = (1 << 16) / src_height;
1373 int h_r = RGB_UNPACK_RED(start_rgb);
1374 int h_g = RGB_UNPACK_GREEN(start_rgb);
1375 int h_b = RGB_UNPACK_BLUE(start_rgb);
1376 int rstep = (h_r - RGB_UNPACK_RED(end_rgb)) * step_mul;
1377 int gstep = (h_g - RGB_UNPACK_GREEN(end_rgb)) * step_mul;
1378 int bstep = (h_b - RGB_UNPACK_BLUE(end_rgb)) * step_mul;
1379 h_r = (h_r << 16) + (1 << 15);
1380 h_g = (h_g << 16) + (1 << 15);
1381 h_b = (h_b << 16) + (1 << 15);
1382
1383 if (row_skip > 0)
1384 {
1385 h_r -= rstep * row_skip;
1386 h_g -= gstep * row_skip;
1387 h_b -= bstep * row_skip;
1388 }
1389
1390 for(i = y; i < y + height; i++) {
1391 current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16);
1392 lcd_hline(x1, x2, i);
1393 h_r -= rstep;
1394 h_g -= gstep;
1395 h_b -= bstep;
1396 }
1397
1398 current_vp->fg_pattern = old_pattern;
1399}
1400
1401/* Fill a rectangle with a gradient. The gradient's color will fade from
1402 * start_rgb to end_rgb over the height of the rectangle
1403 *
1404 * x, y, width, height - dimensions describing the rectangle
1405 * start_rgb - beginning color of the gradient
1406 * end_rgb - end color of the gradient
1407 */
1408void lcd_gradient_fillrect(int x, int y, int width, int height,
1409 unsigned start_rgb, unsigned end_rgb)
1410{
1411 lcd_gradient_fillrect_part(x, y, width, height, start_rgb, end_rgb, height, 0);
1412}
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index 4d4166a384..3c99560b6d 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -41,8 +41,18 @@
41#define ROW_INC LCD_WIDTH 41#define ROW_INC LCD_WIDTH
42#define COL_INC 1 42#define COL_INC 1
43 43
44#include "lcd-16bit-common.c" 44extern lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[];
45extern lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_bgcolor[];
46
47static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
48 const unsigned char *src, int src_x,
49 int src_y, int x, int y,
50 int width, int height,
51 int stride_image, int stride_src);
52
53#include "lcd-color-common.c"
45#include "lcd-bitmap-common.c" 54#include "lcd-bitmap-common.c"
55#include "lcd-16bit-common.c"
46 56
47/*** drawing functions ***/ 57/*** drawing functions ***/
48 58
diff --git a/firmware/drivers/lcd-color-common.c b/firmware/drivers/lcd-color-common.c
new file mode 100644
index 0000000000..e171f08465
--- /dev/null
+++ b/firmware/drivers/lcd-color-common.c
@@ -0,0 +1,605 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Dave Chapman
11 * Copyright (C) 2009 by Karl Kurbjun
12 *
13 * Rockbox driver for 16-bit colour LCDs
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25
26/* to be #included by lcd-16bit*.c */
27
28#if !defined(ROW_INC) || !defined(COL_INC)
29#error ROW_INC or COL_INC not defined
30#endif
31
32enum fill_opt {
33 OPT_NONE = 0,
34 OPT_SET,
35 OPT_COPY
36};
37
38/*** globals ***/
39fb_data lcd_static_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH]
40 IRAM_LCDFRAMEBUFFER CACHEALIGN_AT_LEAST_ATTR(16);
41fb_data *lcd_framebuffer = &lcd_static_framebuffer[0][0];
42
43static fb_data* lcd_backdrop = NULL;
44static long lcd_backdrop_offset IDATA_ATTR = 0;
45
46static struct viewport default_vp =
47{
48 .x = 0,
49 .y = 0,
50 .width = LCD_WIDTH,
51 .height = LCD_HEIGHT,
52 .font = FONT_SYSFIXED,
53 .drawmode = DRMODE_SOLID,
54 .fg_pattern = LCD_DEFAULT_FG,
55 .bg_pattern = LCD_DEFAULT_BG,
56};
57
58static struct viewport* current_vp IDATA_ATTR = &default_vp;
59
60/* LCD init */
61void lcd_init(void)
62{
63 lcd_clear_display();
64
65 /* Call device specific init */
66 lcd_init_device();
67 scroll_init();
68}
69
70/* Clear the whole display */
71void lcd_clear_display(void)
72{
73 struct viewport* old_vp = current_vp;
74
75 current_vp = &default_vp;
76
77 lcd_clear_viewport();
78
79 current_vp = old_vp;
80}
81
82/*** parameter handling ***/
83
84void lcd_set_drawmode(int mode)
85{
86 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
87}
88
89int lcd_get_drawmode(void)
90{
91 return current_vp->drawmode;
92}
93
94void lcd_set_foreground(unsigned color)
95{
96 current_vp->fg_pattern = color;
97}
98
99unsigned lcd_get_foreground(void)
100{
101 return current_vp->fg_pattern;
102}
103
104void lcd_set_background(unsigned color)
105{
106 current_vp->bg_pattern = color;
107}
108
109unsigned lcd_get_background(void)
110{
111 return current_vp->bg_pattern;
112}
113
114void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color)
115{
116 lcd_set_drawmode(mode);
117 current_vp->fg_pattern = fg_color;
118 current_vp->bg_pattern = bg_color;
119}
120
121int lcd_getwidth(void)
122{
123 return current_vp->width;
124}
125
126int lcd_getheight(void)
127{
128 return current_vp->height;
129}
130
131void lcd_setfont(int newfont)
132{
133 current_vp->font = newfont;
134}
135
136int lcd_getfont(void)
137{
138 return current_vp->font;
139}
140
141int lcd_getstringsize(const unsigned char *str, int *w, int *h)
142{
143 return font_getstringsize(str, w, h, current_vp->font);
144}
145
146void lcd_set_backdrop(fb_data* backdrop)
147{
148 lcd_backdrop = backdrop;
149 if (backdrop)
150 {
151 lcd_backdrop_offset = (long)backdrop - (long)lcd_framebuffer;
152 lcd_fastpixelfuncs = lcd_fastpixelfuncs_backdrop;
153 }
154 else
155 {
156 lcd_backdrop_offset = 0;
157 lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor;
158 }
159}
160
161fb_data* lcd_get_backdrop(void)
162{
163 return lcd_backdrop;
164}
165
166/* Set a single pixel */
167void lcd_drawpixel(int x, int y)
168{
169 if ( ((unsigned)x < (unsigned)current_vp->width)
170 && ((unsigned)y < (unsigned)current_vp->height)
171#if defined(HAVE_VIEWPORT_CLIP)
172 && ((unsigned)x < (unsigned)LCD_WIDTH)
173 && ((unsigned)y < (unsigned)LCD_HEIGHT)
174#endif
175 )
176 lcd_fastpixelfuncs[current_vp->drawmode](FBADDR(current_vp->x+x, current_vp->y+y));
177}
178
179/* Draw a line */
180void lcd_drawline(int x1, int y1, int x2, int y2)
181{
182 int numpixels;
183 int i;
184 int deltax, deltay;
185 int d, dinc1, dinc2;
186 int x, xinc1, xinc2;
187 int y, yinc1, yinc2;
188 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
189
190 deltay = abs(y2 - y1);
191 if (deltay == 0)
192 {
193 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
194 lcd_hline(x1, x2, y1);
195 return;
196 }
197 deltax = abs(x2 - x1);
198 if (deltax == 0)
199 {
200 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
201 lcd_vline(x1, y1, y2);
202 return;
203 }
204 xinc2 = 1;
205 yinc2 = 1;
206
207 if (deltax >= deltay)
208 {
209 numpixels = deltax;
210 d = 2 * deltay - deltax;
211 dinc1 = deltay * 2;
212 dinc2 = (deltay - deltax) * 2;
213 xinc1 = 1;
214 yinc1 = 0;
215 }
216 else
217 {
218 numpixels = deltay;
219 d = 2 * deltax - deltay;
220 dinc1 = deltax * 2;
221 dinc2 = (deltax - deltay) * 2;
222 xinc1 = 0;
223 yinc1 = 1;
224 }
225 numpixels++; /* include endpoints */
226
227 if (x1 > x2)
228 {
229 xinc1 = -xinc1;
230 xinc2 = -xinc2;
231 }
232
233 if (y1 > y2)
234 {
235 yinc1 = -yinc1;
236 yinc2 = -yinc2;
237 }
238
239 x = x1;
240 y = y1;
241
242 for (i = 0; i < numpixels; i++)
243 {
244 if ( ((unsigned)x < (unsigned)current_vp->width)
245 && ((unsigned)y < (unsigned)current_vp->height)
246#if defined(HAVE_VIEWPORT_CLIP)
247 && ((unsigned)x < (unsigned)LCD_WIDTH)
248 && ((unsigned)y < (unsigned)LCD_HEIGHT)
249#endif
250 )
251 pfunc(FBADDR(x + current_vp->x, y + current_vp->y));
252
253 if (d < 0)
254 {
255 d += dinc1;
256 x += xinc1;
257 y += yinc1;
258 }
259 else
260 {
261 d += dinc2;
262 x += xinc2;
263 y += yinc2;
264 }
265 }
266}
267
268/* Draw a rectangular box */
269void lcd_drawrect(int x, int y, int width, int height)
270{
271 if ((width <= 0) || (height <= 0))
272 return;
273
274 int x2 = x + width - 1;
275 int y2 = y + height - 1;
276
277 lcd_vline(x, y, y2);
278 lcd_vline(x2, y, y2);
279 lcd_hline(x, x2, y);
280 lcd_hline(x, x2, y2);
281}
282
283
284/* Draw a full native bitmap */
285void lcd_bitmap(const fb_data *src, int x, int y, int width, int height)
286{
287 lcd_bitmap_part(src, 0, 0, STRIDE(SCREEN_MAIN, width, height), x, y, width, height);
288}
289
290/* Draw a full native bitmap with a transparent color */
291void lcd_bitmap_transparent(const fb_data *src, int x, int y,
292 int width, int height)
293{
294 lcd_bitmap_transparent_part(src, 0, 0,
295 STRIDE(SCREEN_MAIN, width, height), x, y, width, height);
296}
297
298/* draw alpha bitmap for anti-alias font */
299void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x,
300 int src_y, int stride, int x, int y,
301 int width, int height)
302{
303 lcd_alpha_bitmap_part_mix(NULL, src, src_x, src_y, x, y, width, height, 0, stride);
304}
305
306/* Draw a partial bitmap (mono or native) including alpha channel */
307void ICODE_ATTR lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y,
308 int x, int y, int width, int height)
309{
310 int bitmap_stride = STRIDE_MAIN(bm->width, bm->height);
311 if (bm->format == FORMAT_MONO)
312 lcd_mono_bitmap_part(bm->data, src_x, src_y, bitmap_stride, x, y, width, height);
313 else if (bm->alpha_offset > 0)
314 lcd_alpha_bitmap_part_mix((fb_data*)bm->data, bm->data+bm->alpha_offset,
315 src_x, src_y, x, y, width, height,
316 bitmap_stride, ALIGN_UP(bm->width, 2));
317 else
318 lcd_bitmap_transparent_part((fb_data*)bm->data,
319 src_x, src_y, bitmap_stride, x, y, width, height);
320}
321
322/* Draw a native bitmap with alpha channel */
323void ICODE_ATTR lcd_bmp(const struct bitmap *bmp, int x, int y)
324{
325 lcd_bmp_part(bmp, 0, 0, x, y, bmp->width, bmp->height);
326}
327
328/**
329 * |R| |1.000000 -0.000001 1.402000| |Y'|
330 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
331 * |B| |1.000000 1.772000 0.000000| |Pr|
332 * Scaled, normalized, rounded and tweaked to yield RGB 565:
333 * |R| |74 0 101| |Y' - 16| >> 9
334 * |G| = |74 -24 -51| |Cb - 128| >> 8
335 * |B| |74 128 0| |Cr - 128| >> 9
336 */
337#define YFAC (74)
338#define RVFAC (101)
339#define GUFAC (-24)
340#define GVFAC (-51)
341#define BUFAC (128)
342
343static inline int clamp(int val, int min, int max)
344{
345 if (val < min)
346 val = min;
347 else if (val > max)
348 val = max;
349 return val;
350}
351
352#ifndef _WIN32
353/*
354 * weak attribute doesn't work for win32 as of gcc 4.6.2 and binutils 2.21.52
355 * When building win32 simulators, we won't be using an optimized version of
356 * lcd_blit_yuv(), so just don't use the weak attribute.
357 */
358__attribute__((weak))
359#endif
360void lcd_yuv_set_options(unsigned options)
361{
362 (void)options;
363}
364
365/* Draw a partial YUV colour bitmap */
366#ifndef _WIN32
367__attribute__((weak))
368#endif
369void lcd_blit_yuv(unsigned char * const src[3],
370 int src_x, int src_y, int stride,
371 int x, int y, int width, int height)
372{
373 const unsigned char *ysrc, *usrc, *vsrc;
374 int linecounter;
375 fb_data *dst, *row_end;
376 long z;
377
378 /* width and height must be >= 2 and an even number */
379 width &= ~1;
380 linecounter = height >> 1;
381
382#if LCD_WIDTH >= LCD_HEIGHT
383 dst = FBADDR(x, y);
384 row_end = dst + width;
385#else
386 dst = FBADDR(LCD_WIDTH - y - 1, x);
387 row_end = dst + LCD_WIDTH * width;
388#endif
389
390 z = stride * src_y;
391 ysrc = src[0] + z + src_x;
392 usrc = src[1] + (z >> 2) + (src_x >> 1);
393 vsrc = src[2] + (usrc - src[1]);
394
395 /* stride => amount to jump from end of last row to start of next */
396 stride -= width;
397
398 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
399
400 do
401 {
402 do
403 {
404 int y, cb, cr, rv, guv, bu, r, g, b;
405
406 y = YFAC*(*ysrc++ - 16);
407 cb = *usrc++ - 128;
408 cr = *vsrc++ - 128;
409
410 rv = RVFAC*cr;
411 guv = GUFAC*cb + GVFAC*cr;
412 bu = BUFAC*cb;
413
414 r = y + rv;
415 g = y + guv;
416 b = y + bu;
417
418 if ((unsigned)(r | g | b) > 64*256-1)
419 {
420 r = clamp(r, 0, 64*256-1);
421 g = clamp(g, 0, 64*256-1);
422 b = clamp(b, 0, 64*256-1);
423 }
424
425 *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
426
427#if LCD_WIDTH >= LCD_HEIGHT
428 dst++;
429#else
430 dst += LCD_WIDTH;
431#endif
432
433 y = YFAC*(*ysrc++ - 16);
434 r = y + rv;
435 g = y + guv;
436 b = y + bu;
437
438 if ((unsigned)(r | g | b) > 64*256-1)
439 {
440 r = clamp(r, 0, 64*256-1);
441 g = clamp(g, 0, 64*256-1);
442 b = clamp(b, 0, 64*256-1);
443 }
444
445 *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
446
447#if LCD_WIDTH >= LCD_HEIGHT
448 dst++;
449#else
450 dst += LCD_WIDTH;
451#endif
452 }
453 while (dst < row_end);
454
455 ysrc += stride;
456 usrc -= width >> 1;
457 vsrc -= width >> 1;
458
459#if LCD_WIDTH >= LCD_HEIGHT
460 row_end += LCD_WIDTH;
461 dst += LCD_WIDTH - width;
462#else
463 row_end -= 1;
464 dst -= LCD_WIDTH*width + 1;
465#endif
466
467 do
468 {
469 int y, cb, cr, rv, guv, bu, r, g, b;
470
471 y = YFAC*(*ysrc++ - 16);
472 cb = *usrc++ - 128;
473 cr = *vsrc++ - 128;
474
475 rv = RVFAC*cr;
476 guv = GUFAC*cb + GVFAC*cr;
477 bu = BUFAC*cb;
478
479 r = y + rv;
480 g = y + guv;
481 b = y + bu;
482
483 if ((unsigned)(r | g | b) > 64*256-1)
484 {
485 r = clamp(r, 0, 64*256-1);
486 g = clamp(g, 0, 64*256-1);
487 b = clamp(b, 0, 64*256-1);
488 }
489
490 *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
491
492#if LCD_WIDTH >= LCD_HEIGHT
493 dst++;
494#else
495 dst += LCD_WIDTH;
496#endif
497
498 y = YFAC*(*ysrc++ - 16);
499 r = y + rv;
500 g = y + guv;
501 b = y + bu;
502
503 if ((unsigned)(r | g | b) > 64*256-1)
504 {
505 r = clamp(r, 0, 64*256-1);
506 g = clamp(g, 0, 64*256-1);
507 b = clamp(b, 0, 64*256-1);
508 }
509
510 *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
511
512#if LCD_WIDTH >= LCD_HEIGHT
513 dst++;
514#else
515 dst += LCD_WIDTH;
516#endif
517 }
518 while (dst < row_end);
519
520 ysrc += stride;
521 usrc += stride >> 1;
522 vsrc += stride >> 1;
523
524#if LCD_WIDTH >= LCD_HEIGHT
525 row_end += LCD_WIDTH;
526 dst += LCD_WIDTH - width;
527#else
528 row_end -= 1;
529 dst -= LCD_WIDTH*width + 1;
530#endif
531 }
532 while (--linecounter > 0);
533
534#if LCD_WIDTH >= LCD_HEIGHT
535 lcd_update_rect(x, y, width, height);
536#else
537 lcd_update_rect(LCD_WIDTH - y - height, x, height, width);
538#endif
539}
540
541/* Fill a rectangle with a gradient. This function draws only the partial
542 * gradient. It assumes the original gradient is src_height high and skips
543 * the first few rows. This is useful for drawing only the bottom half of
544 * a full gradient.
545 *
546 * height == src_height and row_skip == 0 will draw the full gradient
547 *
548 * x, y, width, height - dimensions describing the rectangle
549 * start_rgb - beginning color of the gradient
550 * end_rgb - end color of the gradient
551 * src_height - assumed original height (only height rows will be drawn)
552 * row_skip - how many rows of the original gradient to skip
553 */
554void lcd_gradient_fillrect_part(int x, int y, int width, int height,
555 unsigned start_rgb, unsigned end_rgb, int src_height, int row_skip)
556{
557 int old_pattern = current_vp->fg_pattern;
558 int step_mul, i;
559 int x1, x2;
560 x1 = x;
561 x2 = x + width;
562
563 if (height == 0) return;
564
565 step_mul = (1 << 16) / src_height;
566 int h_r = RGB_UNPACK_RED(start_rgb);
567 int h_g = RGB_UNPACK_GREEN(start_rgb);
568 int h_b = RGB_UNPACK_BLUE(start_rgb);
569 int rstep = (h_r - RGB_UNPACK_RED(end_rgb)) * step_mul;
570 int gstep = (h_g - RGB_UNPACK_GREEN(end_rgb)) * step_mul;
571 int bstep = (h_b - RGB_UNPACK_BLUE(end_rgb)) * step_mul;
572 h_r = (h_r << 16) + (1 << 15);
573 h_g = (h_g << 16) + (1 << 15);
574 h_b = (h_b << 16) + (1 << 15);
575
576 if (row_skip > 0)
577 {
578 h_r -= rstep * row_skip;
579 h_g -= gstep * row_skip;
580 h_b -= bstep * row_skip;
581 }
582
583 for(i = y; i < y + height; i++) {
584 current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16);
585 lcd_hline(x1, x2, i);
586 h_r -= rstep;
587 h_g -= gstep;
588 h_b -= bstep;
589 }
590
591 current_vp->fg_pattern = old_pattern;
592}
593
594/* Fill a rectangle with a gradient. The gradient's color will fade from
595 * start_rgb to end_rgb over the height of the rectangle
596 *
597 * x, y, width, height - dimensions describing the rectangle
598 * start_rgb - beginning color of the gradient
599 * end_rgb - end color of the gradient
600 */
601void lcd_gradient_fillrect(int x, int y, int width, int height,
602 unsigned start_rgb, unsigned end_rgb)
603{
604 lcd_gradient_fillrect_part(x, y, width, height, start_rgb, end_rgb, height, 0);
605}