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 switch (info_ptr
->color_type
) {
126 case PNG_COLOR_TYPE_GRAY_ALPHA
:
127 png_set_gray_to_rgb(png_ptr
);
130 case PNG_COLOR_TYPE_RGB_ALPHA
:
133 case PNG_COLOR_TYPE_GRAY
:
134 png_set_gray_to_rgb(png_ptr
);
137 case PNG_COLOR_TYPE_RGB
:
138 if (png_get_valid(png_ptr
, info_ptr
, PNG_INFO_tRNS
))
139 png_set_tRNS_to_alpha(png_ptr
);
141 png_set_add_alpha(png_ptr
, ~0, PNG_FILLER_AFTER
);
144 case PNG_COLOR_TYPE_PALETTE
:
145 png_set_palette_to_rgb(png_ptr
);
153 png_set_bgr(png_ptr
);
155 if (info_ptr
->bit_depth
== 16)
156 png_set_strip_16(png_ptr
);
157 else if (info_ptr
->bit_depth
< 8)
158 png_set_packing(png_ptr
);
161 if (png_get_bKGD(png_ptr
, info_ptr
, &image_background
))
162 png_set_background(png_ptr
, image_background
,
163 PNG_BACKGROUND_GAMMA_FILE
, 1, 1.0);
165 png_set_background(png_ptr
, &my_background
,
166 PNG_BACKGROUND_GAMMA_SCREEN
, 0, 1.0);
169 /* Whew! Now we should get the stuff we want... */
170 for (i
= 0; i
< (int)info_ptr
->height
; i
++)
171 row_pointers
[i
] = (void *)__vesacon_background
[i
];
173 passes
= png_set_interlace_handling(png_ptr
);
175 for (i
= 0; i
< passes
; i
++)
176 png_read_rows(png_ptr
, row_pointers
, NULL
, info_ptr
->height
);
182 png_destroy_read_struct(&png_ptr
, (png_infopp
)NULL
, (png_infopp
)NULL
);
186 static int jpeg_sig_cmp(uint8_t *bytes
, int len
)
189 return (bytes
[0] == 0xff && bytes
[1] == 0xd8) ? 0 : -1;
192 static int read_jpeg_file(FILE *fp
, uint8_t *header
, int len
)
194 struct jdec_private
*jdec
= NULL
;
195 unsigned char *jpeg_file
= NULL
;
196 size_t length_of_file
= filesize(fp
);
197 unsigned int width
, height
;
199 unsigned char *components
[1];
200 unsigned int bytes_per_row
[1];
202 jpeg_file
= malloc(length_of_file
);
206 memcpy(jpeg_file
, header
, len
);
207 if (fread(jpeg_file
+len
, 1, length_of_file
-len
, fp
) != length_of_file
-len
)
210 jdec
= tinyjpeg_init();
214 if (tinyjpeg_parse_header(jdec
, jpeg_file
, length_of_file
) < 0)
217 tinyjpeg_get_size(jdec
, &width
, &height
);
218 if (width
> VIDEO_X_SIZE
|| height
> VIDEO_Y_SIZE
)
221 components
[0] = (void *)&__vesacon_background
[0];
222 tinyjpeg_set_components(jdec
, components
, 1);
223 bytes_per_row
[0] = VIDEO_X_SIZE
<< 2;
224 tinyjpeg_set_bytes_per_row(jdec
, bytes_per_row
, 1);
226 tinyjpeg_decode(jdec
, TINYJPEG_FMT_BGRA32
);
231 /* Don't use tinyjpeg_free() here, since we didn't allow tinyjpeg
232 to allocate the frame buffer */
242 /* Simple grey Gaussian hole, enough to look interesting */
243 static void default_background(void)
245 int x
, y
, dx
, dy
, dy2
;
246 uint8_t *bgptr
= (uint8_t *)&__vesacon_background
;
249 for (y
= 0, dy
= -VIDEO_Y_SIZE
/2; y
< VIDEO_Y_SIZE
; y
++, dy
++) {
251 for (x
= 0, dx
= -VIDEO_X_SIZE
/2; x
< VIDEO_X_SIZE
; x
++, dx
++) {
252 k
= __vesacon_linear_to_srgb
[500+((dx
*dx
+dy2
) >> 6)];
253 bgptr
[0] = k
; /* Blue */
254 bgptr
[1] = k
; /* Green */
255 bgptr
[2] = k
; /* Red */
256 bgptr
+= 4; /* Dummy alpha */
261 int vesacon_load_background(const char *filename
)
267 if (__vesacon_pixel_format
== PXF_NONE
)
268 return 0; /* Not in graphics mode */
271 default_background();
273 fp
= fopen(filename
, "r");
278 if (fread(header
, 1, 8, fp
) != 8)
281 if (!png_sig_cmp(header
, 0, 8)) {
282 rv
= read_png_file(fp
);
283 } else if (!jpeg_sig_cmp(header
, 8)) {
284 rv
= read_jpeg_file(fp
, header
, 8);
288 /* This actually displays the stuff */
298 int __vesacon_init_background(void)
300 /* The BSS clearing has already cleared __vesacon_background */
302 /* The VESA BIOS has already cleared the screen */