1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
11 * (This is a real mess if it has to be coded in one single C file)
13 * File scrolling addition (C) 2005 Alexander Spyridakis
14 * Copyright (C) 2004 Jörg Hohensohn aka [IDC]Dragon
15 * Heavily borrowed from the IJG implementation (C) Thomas G. Lane
16 * Small & fast downscaling IDCT (C) 2002 by Guido Vollbeding JPEGclub.org
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
26 ****************************************************************************/
32 * Conversion of full 0-255 range YCrCb to RGB:
33 * |R| |1.000000 -0.000001 1.402000| |Y'|
34 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
35 * |B| |1.000000 1.772000 0.000000| |Pr|
36 * Scaled (yields s15-bit output):
37 * |R| |128 0 179| |Y |
38 * |G| = |128 -43 -91| |Cb - 128|
39 * |B| |128 227 0| |Cr - 128|
46 #define YUV_WHITE (255*YFAC)
47 #define NODITHER_DELTA (127*YFAC)
48 #define COMPONENT_SHIFT 15
49 #define MATRIX_SHIFT 7
51 static inline int clamp_component_bits(int x
, int bits
)
53 if ((unsigned)x
> (1u << bits
) - 1)
54 x
= x
< 0 ? 0 : (1 << bits
) - 1;
58 static inline int component_to_lcd(int x
, int bits
, int delta
)
60 /* Formula used in core bitmap loader. */
61 return (((1 << bits
) - 1)*x
+ (x
>> (8 - bits
)) + delta
) >> COMPONENT_SHIFT
;
64 static inline int lcd_to_component(int x
, int bits
, int delta
)
66 /* Reasonable, approximate reversal to get a full range back from the
68 return YUV_WHITE
*x
/ ((1 << bits
) - 1);
78 int16_t errbuf
[LCD_WIDTH
+2]; /* Error record for line below */
83 int r
, g
, b
; /* Current pixel components in s16.0 */
84 int inc
; /* Current line increment (-1 or 1) */
85 int row
; /* Current row in source image */
86 int col
; /* Current column in source image */
87 int ce
[3]; /* Errors to apply to current pixel */
88 struct rgb_err
*e
; /* RED, GRN, BLU */
89 int epos
; /* Current position in error record */
92 struct rgb_pixel
*pixel
;
94 /** round and truncate to lcd depth **/
95 static fb_data
pixel_to_lcd_colour(void)
97 struct rgb_pixel
*p
= pixel
;
100 r
= component_to_lcd(p
->r
, LCD_RED_BITS
, NODITHER_DELTA
);
101 r
= clamp_component_bits(r
, LCD_RED_BITS
);
103 g
= component_to_lcd(p
->g
, LCD_GREEN_BITS
, NODITHER_DELTA
);
104 g
= clamp_component_bits(g
, LCD_GREEN_BITS
);
106 b
= component_to_lcd(p
->b
, LCD_BLUE_BITS
, NODITHER_DELTA
);
107 b
= clamp_component_bits(b
, LCD_BLUE_BITS
);
109 return LCD_RGBPACK_LCD(r
, g
, b
);
112 /** write a monochrome pixel to the colour LCD **/
113 static fb_data
pixel_to_lcd_gray(void)
117 g
= clamp_component(pixel
->g
);
118 r
= component_to_lcd(g
, LCD_RED_BITS
, NODITHER_DELTA
);
119 b
= component_to_lcd(g
, LCD_BLUE_BITS
, NODITHER_DELTA
);
120 g
= component_to_lcd(g
, LCD_GREEN_BITS
, NODITHER_DELTA
);
122 return LCD_RGBPACK_LCD(r
, g
, b
);
126 * Bayer ordered dithering - swiped from the core bitmap loader.
128 static fb_data
pixel_odither_to_lcd(void)
130 /* canonical ordered dither matrix */
131 static const unsigned char dither_matrix
[16][16] = {
132 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
133 { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
134 { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
135 { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
136 { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
137 { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
138 { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
139 { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
140 { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
141 { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
142 { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
143 { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
144 { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
145 { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
146 { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
147 { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
150 struct rgb_pixel
*p
= pixel
;
153 delta
= dither_matrix
[p
->col
& 15][p
->row
& 15] << MATRIX_SHIFT
;
155 r
= component_to_lcd(p
->r
, LCD_RED_BITS
, delta
);
156 r
= clamp_component_bits(r
, LCD_RED_BITS
);
158 g
= component_to_lcd(p
->g
, LCD_GREEN_BITS
, delta
);
159 g
= clamp_component_bits(g
, LCD_GREEN_BITS
);
161 b
= component_to_lcd(p
->b
, LCD_BLUE_BITS
, delta
);
162 b
= clamp_component_bits(b
, LCD_BLUE_BITS
);
166 return LCD_RGBPACK_LCD(r
, g
, b
);
170 * Floyd/Steinberg dither to lcd depth.
172 * Apply filter to each component in serpentine pattern. Kernel shown for
173 * L->R scan. Kernel is reversed for R->L.
177 static inline void distribute_error(int *ce
, struct rgb_err
*e
,
178 int err
, int epos
, int inc
)
180 *ce
= (7*err
>> 4) + e
->errbuf
[epos
+inc
];
181 e
->errbuf
[epos
+inc
] = err
>> 4;
182 e
->errbuf
[epos
] += 5*err
>> 4;
183 e
->errbuf
[epos
-inc
] += 3*err
>> 4;
186 static fb_data
pixel_fsdither_to_lcd(void)
188 struct rgb_pixel
*p
= pixel
;
189 int rc
, gc
, bc
, r
, g
, b
;
192 /* Full components with error terms */
193 rc
= p
->r
+ p
->ce
[RED
];
194 r
= component_to_lcd(rc
, LCD_RED_BITS
, 0);
195 r
= clamp_component_bits(r
, LCD_RED_BITS
);
197 gc
= p
->g
+ p
->ce
[GRN
];
198 g
= component_to_lcd(gc
, LCD_GREEN_BITS
, 0);
199 g
= clamp_component_bits(g
, LCD_GREEN_BITS
);
201 bc
= p
->b
+ p
->ce
[BLU
];
202 b
= component_to_lcd(bc
, LCD_BLUE_BITS
, 0);
203 b
= clamp_component_bits(b
, LCD_BLUE_BITS
);
205 /* Get pixel errors */
206 rc
-= lcd_to_component(r
, LCD_RED_BITS
, 0);
207 gc
-= lcd_to_component(g
, LCD_GREEN_BITS
, 0);
208 bc
-= lcd_to_component(b
, LCD_BLUE_BITS
, 0);
210 /* Spead error to surrounding pixels. */
215 distribute_error(&p
->ce
[RED
], &p
->e
[RED
], rc
, epos
, inc
);
216 distribute_error(&p
->ce
[GRN
], &p
->e
[GRN
], gc
, epos
, inc
);
217 distribute_error(&p
->ce
[BLU
], &p
->e
[BLU
], bc
, epos
, inc
);
219 /* Pack and return pixel */
220 return LCD_RGBPACK_LCD(r
, g
, b
);
223 /* Functions for each output mode, colour then grayscale. */
224 static fb_data (* const pixel_funcs
[COLOUR_NUM_MODES
][DITHER_NUM_MODES
])(void) =
226 [COLOURMODE_COLOUR
] =
228 [DITHER_NONE
] = pixel_to_lcd_colour
,
229 [DITHER_ORDERED
] = pixel_odither_to_lcd
,
230 [DITHER_DIFFUSION
] = pixel_fsdither_to_lcd
,
234 [DITHER_NONE
] = pixel_to_lcd_gray
,
235 [DITHER_ORDERED
] = pixel_odither_to_lcd
,
236 [DITHER_DIFFUSION
] = pixel_fsdither_to_lcd
,
241 * Draw a partial YUV colour bitmap
243 * Runs serpentine pattern when dithering is DITHER_DIFFUSION, else scan is
246 void yuv_bitmap_part(unsigned char *src
[3], int csub_x
, int csub_y
,
247 int src_x
, int src_y
, int stride
,
248 int x
, int y
, int width
, int height
,
249 int colour_mode
, int dither_mode
)
251 fb_data
*dst
, *dst_end
;
252 fb_data (*pixel_func
)(void);
255 if (x
+ width
> LCD_WIDTH
)
256 width
= LCD_WIDTH
- x
; /* Clip right */
258 width
+= x
, x
= 0; /* Clip left */
260 return; /* nothing left to do */
262 if (y
+ height
> LCD_HEIGHT
)
263 height
= LCD_HEIGHT
- y
; /* Clip bottom */
265 height
+= y
, y
= 0; /* Clip top */
267 return; /* nothing left to do */
271 dst
= rb
->lcd_framebuffer
+ LCD_WIDTH
* y
+ x
;
272 dst_end
= dst
+ LCD_WIDTH
* height
;
274 if (colour_mode
== COLOURMODE_GRAY
)
275 csub_y
= 0; /* Ignore Cb, Cr */
277 pixel_func
= pixel_funcs
[colour_mode
]
280 if (dither_mode
== DITHER_DIFFUSION
)
282 /* Reset error terms. */
283 px
.e
= rgb_err_buffers
;
284 px
.ce
[RED
] = px
.ce
[GRN
] = px
.ce
[BLU
] = 0;
285 rb
->memset(px
.e
, 0, 3*sizeof (struct rgb_err
));
290 fb_data
*dst_row
, *row_end
;
291 const unsigned char *ysrc
;
294 if (dither_mode
== DITHER_DIFFUSION
)
296 /* Use R->L scan on odd lines */
297 px
.inc
-= (src_y
& 1) << 1;
301 px
.epos
+= width
- 1;
308 row_end
= dst_row
+ width
;
315 dst_row
= row_end
+ width
;
316 px
.col
= src_x
+ width
- 1;
319 ysrc
= src
[0] + stride
* src_y
+ px
.col
;
322 /* Do one row of pixels */
323 if (csub_y
) /* colour */
325 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
326 const unsigned char *usrc
, *vsrc
;
328 usrc
= src
[1] + (stride
/csub_x
) * (src_y
/csub_y
)
330 vsrc
= src
[2] + (stride
/csub_x
) * (src_y
/csub_y
)
332 int xphase
= px
.col
% csub_x
;
333 int xphase_reset
= px
.inc
* csub_x
;
334 int y
, v
, u
, rv
, guv
, bu
;
341 guv
= GUFAC
*u
+ GVFAC
*v
;
352 *dst_row
= pixel_func();
355 if (dst_row
== row_end
)
359 if ((unsigned)xphase
< (unsigned)csub_x
)
362 /* fetch new chromas */
368 guv
= GUFAC
*u
+ GVFAC
*v
;
371 xphase
-= xphase_reset
;
374 else /* monochrome */
378 /* Set all components the same for dithering purposes */
379 px
.g
= px
.r
= px
.b
= YFAC
*(*ysrc
);
380 *dst_row
= pixel_func();
384 while (dst_row
!= row_end
);
390 while (dst
< dst_end
);