1 /* ----------------------------------------------------------------------- *
3 * Copyright 2006 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 * ----------------------------------------------------------------------- */
40 static size_t filesize(FILE *fp
)
43 if (fstat(fileno(fp
), &st
))
49 /*** FIX: This really should be alpha-blended with color index 0 */
51 /* For best performance, "start" should be a multiple of 4, to assure
53 static void draw_background_line(int line
, int start
, int npixels
)
55 uint8_t line_buf
[VIDEO_X_SIZE
*4], *lbp
;
56 uint32_t *bgptr
= &__vesacon_background
[line
][start
];
57 unsigned int bytes_per_pixel
= __vesacon_bytes_per_pixel
;
58 enum vesa_pixel_format pixel_format
= __vesacon_pixel_format
;
59 uint8_t *fbptr
= (uint8_t *)__vesa_info
.mi
.lfb_ptr
+
60 (line
*VIDEO_X_SIZE
+start
)*bytes_per_pixel
;
64 lbp
= format_pixel(lbp
, *bgptr
++, pixel_format
);
66 memcpy(fbptr
, line_buf
, lbp
-line_buf
);
69 /* This draws the border, then redraws the text area */
70 static void draw_background(void)
73 const int bottom_border
= VIDEO_BORDER
+
74 (TEXT_PIXEL_ROWS
% __vesacon_font_height
);
75 const int right_border
= VIDEO_BORDER
+ (TEXT_PIXEL_COLS
% FONT_WIDTH
);
77 for (i
= 0; i
< VIDEO_BORDER
; i
++)
78 draw_background_line(i
, 0, VIDEO_X_SIZE
);
80 for (i
= VIDEO_BORDER
; i
< VIDEO_Y_SIZE
-bottom_border
; i
++) {
81 draw_background_line(i
, 0, VIDEO_BORDER
);
82 draw_background_line(i
, VIDEO_X_SIZE
-right_border
, right_border
);
85 for (i
= VIDEO_Y_SIZE
-bottom_border
; i
< VIDEO_Y_SIZE
; i
++)
86 draw_background_line(i
, 0, VIDEO_X_SIZE
);
88 __vesacon_redraw_text();
91 static int read_png_file(FILE *fp
)
93 png_structp png_ptr
= NULL
;
94 png_infop info_ptr
= NULL
;
95 png_infop end_ptr
= NULL
;
97 png_color_16p image_background
;
98 static const png_color_16 my_background
= {0,0,0,0,0};
100 png_bytep row_pointers
[VIDEO_Y_SIZE
];
105 png_ptr
= png_create_read_struct(PNG_LIBPNG_VER_STRING
,
108 info_ptr
= png_create_info_struct(png_ptr
);
109 end_ptr
= png_create_info_struct(png_ptr
);
111 if (!png_ptr
|| !info_ptr
|| !end_ptr
||
112 setjmp(png_jmpbuf(png_ptr
)))
115 png_init_io(png_ptr
, fp
);
116 png_set_sig_bytes(png_ptr
, 8);
118 png_set_user_limits(png_ptr
, VIDEO_X_SIZE
, VIDEO_Y_SIZE
);
120 png_read_info(png_ptr
, info_ptr
);
122 /* Set the appropriate set of transformations. We need to end up
123 with 32-bit BGRA format, no more, no less. */
125 /* Expand to RGB first... */
127 switch (info_ptr
->color_type
) {
128 case PNG_COLOR_TYPE_GRAY
:
129 case PNG_COLOR_TYPE_GRAY_ALPHA
:
130 png_set_gray_to_rgb(png_ptr
);
133 case PNG_COLOR_TYPE_RGB
:
134 case PNG_COLOR_TYPE_RGB_ALPHA
:
137 case PNG_COLOR_TYPE_PALETTE
:
138 png_set_palette_to_rgb(png_ptr
);
146 /* ... then add an alpha channel ... */
147 switch (info_ptr
->color_type
) {
148 case PNG_COLOR_TYPE_GRAY_ALPHA
:
149 case PNG_COLOR_TYPE_RGB_ALPHA
:
153 if (png_get_valid(png_ptr
, info_ptr
, PNG_INFO_tRNS
))
154 png_set_tRNS_to_alpha(png_ptr
);
156 png_set_add_alpha(png_ptr
, ~0, PNG_FILLER_AFTER
);
160 png_set_bgr(png_ptr
);
162 if (info_ptr
->bit_depth
== 16)
163 png_set_strip_16(png_ptr
);
164 else if (info_ptr
->bit_depth
< 8)
165 png_set_packing(png_ptr
);
168 if (png_get_bKGD(png_ptr
, info_ptr
, &image_background
))
169 png_set_background(png_ptr
, image_background
,
170 PNG_BACKGROUND_GAMMA_FILE
, 1, 1.0);
172 png_set_background(png_ptr
, &my_background
,
173 PNG_BACKGROUND_GAMMA_SCREEN
, 0, 1.0);
176 /* Whew! Now we should get the stuff we want... */
177 for (i
= 0; i
< (int)info_ptr
->height
; i
++)
178 row_pointers
[i
] = (void *)__vesacon_background
[i
];
180 passes
= png_set_interlace_handling(png_ptr
);
182 for (i
= 0; i
< passes
; i
++)
183 png_read_rows(png_ptr
, row_pointers
, NULL
, info_ptr
->height
);
189 png_destroy_read_struct(&png_ptr
, (png_infopp
)NULL
, (png_infopp
)NULL
);
193 static int jpeg_sig_cmp(uint8_t *bytes
, int len
)
196 return (bytes
[0] == 0xff && bytes
[1] == 0xd8) ? 0 : -1;
199 static int read_jpeg_file(FILE *fp
, uint8_t *header
, int len
)
201 struct jdec_private
*jdec
= NULL
;
202 unsigned char *jpeg_file
= NULL
;
203 size_t length_of_file
= filesize(fp
);
204 unsigned int width
, height
;
206 unsigned char *components
[1];
207 unsigned int bytes_per_row
[1];
209 jpeg_file
= malloc(length_of_file
);
213 memcpy(jpeg_file
, header
, len
);
214 if (fread(jpeg_file
+len
, 1, length_of_file
-len
, fp
) != length_of_file
-len
)
217 jdec
= tinyjpeg_init();
221 if (tinyjpeg_parse_header(jdec
, jpeg_file
, length_of_file
) < 0)
224 tinyjpeg_get_size(jdec
, &width
, &height
);
225 if (width
> VIDEO_X_SIZE
|| height
> VIDEO_Y_SIZE
)
228 components
[0] = (void *)&__vesacon_background
[0];
229 tinyjpeg_set_components(jdec
, components
, 1);
230 bytes_per_row
[0] = VIDEO_X_SIZE
<< 2;
231 tinyjpeg_set_bytes_per_row(jdec
, bytes_per_row
, 1);
233 tinyjpeg_decode(jdec
, TINYJPEG_FMT_BGRA32
);
238 /* Don't use tinyjpeg_free() here, since we didn't allow tinyjpeg
239 to allocate the frame buffer */
249 /* Simple grey Gaussian hole, enough to look interesting */
250 static void default_background(void)
252 int x
, y
, dx
, dy
, dy2
;
253 uint8_t *bgptr
= (uint8_t *)&__vesacon_background
;
256 for (y
= 0, dy
= -VIDEO_Y_SIZE
/2; y
< VIDEO_Y_SIZE
; y
++, dy
++) {
258 for (x
= 0, dx
= -VIDEO_X_SIZE
/2; x
< VIDEO_X_SIZE
; x
++, dx
++) {
259 k
= __vesacon_linear_to_srgb
[500+((dx
*dx
+dy2
) >> 6)];
260 bgptr
[0] = k
; /* Blue */
261 bgptr
[1] = k
; /* Green */
262 bgptr
[2] = k
; /* Red */
263 bgptr
+= 4; /* Dummy alpha */
268 int vesacon_load_background(const char *filename
)
274 if (__vesacon_pixel_format
== PXF_NONE
)
275 return 0; /* Not in graphics mode */
278 default_background();
280 fp
= fopen(filename
, "r");
285 if (fread(header
, 1, 8, fp
) != 8)
288 if (!png_sig_cmp(header
, 0, 8)) {
289 rv
= read_png_file(fp
);
290 } else if (!jpeg_sig_cmp(header
, 8)) {
291 rv
= read_jpeg_file(fp
, header
, 8);
295 /* This actually displays the stuff */
305 int __vesacon_init_background(void)
307 /* The BSS clearing has already cleared __vesacon_background */
309 /* The VESA BIOS has already cleared the screen */