1 /* ----------------------------------------------------------------------- *
3 * Copyright 2006-2008 H. Peter Anvin - All Rights Reserved
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
26 * ----------------------------------------------------------------------- */
38 #include <syslinux/loadfile.h>
42 /*** FIX: This really should be alpha-blended with color index 0 ***/
44 /* For best performance, "start" should be a multiple of 4, to assure
46 static void draw_background_line(int line
, int start
, int npixels
)
48 uint32_t *bgptr
= &__vesacon_background
[line
*__vesa_info
.mi
.h_res
+start
];
49 unsigned int bytes_per_pixel
= __vesacon_bytes_per_pixel
;
50 size_t fbptr
= line
* __vesa_info
.mi
.logical_scan
+ start
*bytes_per_pixel
;
52 __vesacon_copy_to_screen(fbptr
, bgptr
, npixels
);
55 /* This draws the border, then redraws the text area */
56 static void draw_background(void)
59 const int bottom_border
= VIDEO_BORDER
+
60 (TEXT_PIXEL_ROWS
% __vesacon_font_height
);
61 const int right_border
= VIDEO_BORDER
+ (TEXT_PIXEL_COLS
% FONT_WIDTH
);
63 for (i
= 0; i
< VIDEO_BORDER
; i
++)
64 draw_background_line(i
, 0, __vesa_info
.mi
.h_res
);
66 for (i
= VIDEO_BORDER
; i
< __vesa_info
.mi
.v_res
- bottom_border
; i
++) {
67 draw_background_line(i
, 0, VIDEO_BORDER
);
68 draw_background_line(i
, __vesa_info
.mi
.h_res
- right_border
,
72 for (i
= __vesa_info
.mi
.v_res
- bottom_border
;
73 i
< __vesa_info
.mi
.v_res
; i
++)
74 draw_background_line(i
, 0, __vesa_info
.mi
.h_res
);
76 __vesacon_redraw_text();
80 * Tile an image in the UL corner across the entire screen
82 static void tile_image(int width
, int height
)
84 int xsize
= __vesa_info
.mi
.h_res
;
85 int ysize
= __vesa_info
.mi
.v_res
;
88 uint32_t *sp
, *dp
, *drp
, *dtp
;
90 drp
= __vesacon_background
;
91 for (y
= 0 ; y
< ysize
; y
+= height
) {
92 yl
= min(height
, ysize
-y
);
94 for (x
= 0 ; x
< xsize
; x
+= width
) {
95 xl
= min(width
, xsize
-x
);
97 sp
= __vesacon_background
;
99 for (yr
= 0 ; yr
< yl
; yr
++) {
100 memcpy(dp
, sp
, xl
*sizeof(uint32_t));
111 static int read_png_file(FILE * fp
)
113 png_structp png_ptr
= NULL
;
114 png_infop info_ptr
= NULL
;
116 png_color_16p image_background
;
117 static const png_color_16 my_background
= { 0, 0, 0, 0, 0 };
119 png_bytep row_pointers
[__vesa_info
.mi
.v_res
], rp
;
123 png_ptr
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
124 info_ptr
= png_create_info_struct(png_ptr
);
126 if (!png_ptr
|| !info_ptr
|| setjmp(png_jmpbuf(png_ptr
)))
129 png_init_io(png_ptr
, fp
);
130 png_set_sig_bytes(png_ptr
, 8);
132 png_set_user_limits(png_ptr
, __vesa_info
.mi
.h_res
, __vesa_info
.mi
.v_res
);
134 png_read_info(png_ptr
, info_ptr
);
136 /* Set the appropriate set of transformations. We need to end up
137 with 32-bit BGRA format, no more, no less. */
139 /* Expand to RGB first... */
140 if (info_ptr
->color_type
& PNG_COLOR_MASK_PALETTE
)
141 png_set_palette_to_rgb(png_ptr
);
142 else if (!(info_ptr
->color_type
& PNG_COLOR_MASK_COLOR
))
143 png_set_gray_to_rgb(png_ptr
);
145 /* Add alpha channel, if need be */
146 if (!(png_ptr
->color_type
& PNG_COLOR_MASK_ALPHA
)) {
147 if (png_get_valid(png_ptr
, info_ptr
, PNG_INFO_tRNS
))
148 png_set_tRNS_to_alpha(png_ptr
);
150 png_set_add_alpha(png_ptr
, ~0, PNG_FILLER_AFTER
);
153 /* Adjust the byte order, if necessary */
154 png_set_bgr(png_ptr
);
156 /* Make sure we end up with 8-bit data */
157 if (info_ptr
->bit_depth
== 16)
158 png_set_strip_16(png_ptr
);
159 else if (info_ptr
->bit_depth
< 8)
160 png_set_packing(png_ptr
);
163 if (png_get_bKGD(png_ptr
, info_ptr
, &image_background
))
164 png_set_background(png_ptr
, image_background
,
165 PNG_BACKGROUND_GAMMA_FILE
, 1, 1.0);
167 png_set_background(png_ptr
, &my_background
,
168 PNG_BACKGROUND_GAMMA_SCREEN
, 0, 1.0);
171 /* Whew! Now we should get the stuff we want... */
172 rp
= (png_bytep
)__vesacon_background
;
173 for (i
= 0; i
< (int)info_ptr
->height
; i
++) {
174 row_pointers
[i
] = rp
;
175 rp
+= __vesa_info
.mi
.h_res
<< 2;
178 png_read_image(png_ptr
, row_pointers
);
180 tile_image(info_ptr
->width
, info_ptr
->height
);
186 png_destroy_read_struct(&png_ptr
, &info_ptr
, (png_infopp
) NULL
);
190 static int jpeg_sig_cmp(uint8_t * bytes
, int len
)
194 return (bytes
[0] == 0xff && bytes
[1] == 0xd8) ? 0 : -1;
197 static int read_jpeg_file(FILE * fp
, uint8_t * header
, int len
)
199 struct jdec_private
*jdec
= NULL
;
200 void *jpeg_file
= NULL
;
201 size_t length_of_file
;
202 unsigned int width
, height
;
204 unsigned char *components
[1];
205 unsigned int bytes_per_row
[1];
207 rv
= floadfile(fp
, &jpeg_file
, &length_of_file
, header
, len
);
211 jdec
= tinyjpeg_init();
215 if (tinyjpeg_parse_header(jdec
, jpeg_file
, length_of_file
) < 0)
218 tinyjpeg_get_size(jdec
, &width
, &height
);
219 if (width
> __vesa_info
.mi
.h_res
|| height
> __vesa_info
.mi
.v_res
)
222 components
[0] = (void *)__vesacon_background
;
223 tinyjpeg_set_components(jdec
, components
, 1);
224 bytes_per_row
[0] = __vesa_info
.mi
.h_res
<< 2;
225 tinyjpeg_set_bytes_per_row(jdec
, bytes_per_row
, 1);
227 tinyjpeg_decode(jdec
, TINYJPEG_FMT_BGRA32
);
228 tile_image(width
, height
);
233 /* Don't use tinyjpeg_free() here, since we didn't allow tinyjpeg
234 to allocate the frame buffer */
244 /* Simple grey Gaussian hole, enough to look interesting */
245 int vesacon_default_background(void)
247 int x
, y
, dx
, dy
, dy2
;
250 uint8_t *bgptr
= (uint8_t *)__vesacon_background
;
253 if (__vesacon_pixel_format
== PXF_NONE
)
254 return 0; /* Not in graphics mode */
256 z
= max(__vesa_info
.mi
.v_res
, __vesa_info
.mi
.h_res
) >> 1;
257 z
= ((z
*z
) >> 11) - 1;
260 for (y
= 0, dy
= -(__vesa_info
.mi
.v_res
>> 1);
261 y
< __vesa_info
.mi
.v_res
; y
++, dy
++) {
263 for (x
= 0, dx
= -(__vesa_info
.mi
.h_res
>> 1);
264 x
< __vesa_info
.mi
.h_res
; x
++, dx
++) {
265 k
= __vesacon_linear_to_srgb
[500 + ((dx
*dx
+ dy2
) >> shft
)];
266 bgptr
[0] = k
; /* Blue */
267 bgptr
[1] = k
; /* Green */
268 bgptr
[2] = k
; /* Red */
269 bgptr
+= 4; /* Dummy alpha */
277 /* Set the background to a single flat color */
278 int vesacon_set_background(unsigned int rgb
)
280 void *bgptr
= __vesacon_background
;
281 unsigned int count
= __vesa_info
.mi
.h_res
* __vesa_info
.mi
.v_res
;
283 if (__vesacon_pixel_format
== PXF_NONE
)
284 return 0; /* Not in graphics mode */
286 asm volatile ("rep; stosl":"+D" (bgptr
), "+c"(count
)
294 struct lss16_header
{
300 #define LSS16_MAGIC 0x1413f33d
302 static inline int lss16_sig_cmp(const void *header
, int len
)
304 const struct lss16_header
*h
= header
;
309 return !(h
->magic
== LSS16_MAGIC
&&
310 h
->xsize
<= __vesa_info
.mi
.h_res
&&
311 h
->ysize
<= __vesa_info
.mi
.v_res
);
314 static int read_lss16_file(FILE * fp
, const void *header
, int header_len
)
316 const struct lss16_header
*h
= header
;
317 uint32_t colors
[16], color
;
329 uint32_t *bgptr
= __vesacon_background
;
331 /* Assume the header, 8 bytes, has already been loaded. */
335 for (i
= 0; i
< 16; i
++) {
337 if (fread(rgb
, 1, 3, fp
) != 3)
340 colors
[i
] = (((rgb
[0] & 63) * 255 / 63) << 16) +
341 (((rgb
[1] & 63) * 255 / 63) << 8) +
342 ((rgb
[2] & 63) * 255 / 63);
345 /* By spec, the state machine is per row */
346 for (y
= 0; y
< h
->ysize
; y
++) {
349 color
= colors
[prev
= 0]; /* By specification */
353 while (x
< h
->xsize
) {
355 if (fread(&byte
, 1, 1, fp
) != 1)
366 if (nybble
!= prev
) {
367 *bgptr
++ = color
= colors
[prev
= nybble
];
389 count
+= nybble
<< 4;
393 count
= min(count
, h
->xsize
- x
);
395 asm volatile ("rep; stosl":"+D" (bgptr
),
396 "+c"(count
):"a"(color
));
402 /* Zero-fill rest of row */
403 i
= __vesa_info
.mi
.h_res
- x
;
404 asm volatile ("rep; stosl":"+D" (bgptr
), "+c"(i
):"a"(0):"memory");
407 /* Zero-fill rest of screen */
408 i
= (__vesa_info
.mi
.v_res
- y
) * __vesa_info
.mi
.h_res
;
409 asm volatile ("rep; stosl":"+D" (bgptr
), "+c"(i
):"a"(0):"memory");
414 int vesacon_load_background(const char *filename
)
420 if (__vesacon_pixel_format
== PXF_NONE
)
421 return 0; /* Not in graphics mode */
423 fp
= fopen(filename
, "r");
428 if (fread(header
, 1, 8, fp
) != 8)
431 if (!png_sig_cmp(header
, 0, 8)) {
432 rv
= read_png_file(fp
);
433 } else if (!jpeg_sig_cmp(header
, 8)) {
434 rv
= read_jpeg_file(fp
, header
, 8);
435 } else if (!lss16_sig_cmp(header
, 8)) {
436 rv
= read_lss16_file(fp
, header
, 8);
439 /* This actually displays the stuff */
449 int __vesacon_init_background(void)
451 /* __vesacon_background was cleared by calloc() */
453 /* The VESA BIOS has already cleared the screen */