1/*
2 * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2008, Stephan Aßmus <superstippi@gmx.de>
4 * Copyright 2008, Philippe Saint-Pierre <stpere@gmail.com>
5 * Distributed under the terms of the MIT License.
6 */
7
8
9#include <arch/cpu.h>
10#include <boot/stage2.h>
11#include <boot/platform.h>
12#include <boot/menu.h>
13#include <boot/kernel_args.h>
14#include <boot/platform/generic/video.h>
15#include <boot/images.h>
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include <zlib.h>
22
23
24//#define TRACE_VIDEO
25#ifdef TRACE_VIDEO
26#	define TRACE(x) dprintf x
27#else
28#	define TRACE(x) ;
29#endif
30
31
32static status_t
33uncompress(const uint8 compressed[], unsigned int compressedSize,
34	uint8* uncompressed, unsigned int uncompressedSize)
35{
36	if (compressedSize == 0 || uncompressedSize == 0)
37		return B_BAD_VALUE;
38
39	// prepare zlib stream
40	z_stream zStream = {
41		(Bytef*)compressed,		// next_in
42		compressedSize,			// avail_in
43		0,						// total_in
44		(Bytef*)uncompressed,	// next_out
45		uncompressedSize,		// avail_out
46		0,						// total_out
47		0,						// msg
48		0,						// state
49		Z_NULL,					// zalloc (kernel_args_malloc?)
50		Z_NULL,					// zfree (kernel_args_free?)
51		Z_NULL,					// opaque
52		0,						// data_type
53		0,						// adler
54		0						// reserved
55	};
56
57	int zlibError = inflateInit(&zStream);
58	if (zlibError != Z_OK)
59		return B_ERROR;	// TODO: translate zlibError
60
61	// inflate
62	status_t status = B_OK;
63	zlibError = inflate(&zStream, Z_FINISH);
64	if (zlibError != Z_STREAM_END) {
65		if (zlibError == Z_OK)
66			status = B_BUFFER_OVERFLOW;
67		else
68			status = B_ERROR;	// TODO: translate zlibError
69	}
70
71	// clean up
72	zlibError = inflateEnd(&zStream);
73	if (zlibError != Z_OK && status == B_OK)
74		status = B_ERROR;	// TODO: translate zlibError
75
76	if (status == B_OK && zStream.total_out != uncompressedSize)
77		status = B_ERROR;
78
79	return status;
80}
81
82
83extern "C" status_t
84video_display_splash(addr_t frameBuffer)
85{
86	if (!gKernelArgs.frame_buffer.enabled)
87		return B_NO_INIT;
88
89	// clear the video memory
90	memset((void*)frameBuffer, 0,
91		gKernelArgs.frame_buffer.physical_buffer.size);
92
93	uint8* uncompressedLogo = NULL;
94	unsigned int uncompressedSize = kSplashLogoWidth * kSplashLogoHeight;
95	switch (gKernelArgs.frame_buffer.depth) {
96		case 8:
97			platform_set_palette(k8BitPalette);
98			uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize);
99			if (uncompressedLogo == NULL)
100				return B_NO_MEMORY;
101
102			uncompress(kSplashLogo8BitCompressedImage,
103				sizeof(kSplashLogo8BitCompressedImage), uncompressedLogo,
104				uncompressedSize);
105		break;
106		default: // 24 bits is assumed here
107			uncompressedSize *= 3;
108			uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize);
109			if (uncompressedLogo == NULL)
110				return B_NO_MEMORY;
111
112			uncompress(kSplashLogo24BitCompressedImage,
113				sizeof(kSplashLogo24BitCompressedImage), uncompressedLogo,
114				uncompressedSize);
115		break;
116	}
117
118	// TODO: support 4-bit indexed version of the images!
119
120	// render splash logo
121	uint16 iconsHalfHeight = kSplashIconsHeight / 2;
122
123	int width = min_c(kSplashLogoWidth, gKernelArgs.frame_buffer.width);
124	int height = min_c(kSplashLogoHeight + iconsHalfHeight,
125		gKernelArgs.frame_buffer.height);
126	int placementX = max_c(0, min_c(100, kSplashLogoPlacementX));
127	int placementY = max_c(0, min_c(100, kSplashLogoPlacementY));
128
129	int x = (gKernelArgs.frame_buffer.width - width) * placementX / 100;
130	int y = (gKernelArgs.frame_buffer.height - height) * placementY / 100;
131
132	height = min_c(kSplashLogoHeight, gKernelArgs.frame_buffer.height);
133	switch (gKernelArgs.frame_buffer.depth) {
134		case 8:
135			break;
136	}
137	video_blit_image(frameBuffer, uncompressedLogo, width, height,
138		kSplashLogoWidth, x, y);
139
140	kernel_args_free(uncompressedLogo);
141
142	const uint8* lowerHalfIconImage;
143	uncompressedSize = kSplashIconsWidth * kSplashIconsHeight;
144	switch (gKernelArgs.frame_buffer.depth) {
145		case 8:
146			// pointer into the lower half of the icons image data
147			gKernelArgs.boot_splash
148				= (uint8*)kernel_args_malloc(uncompressedSize);
149			if (gKernelArgs.boot_splash == NULL)
150				return B_NO_MEMORY;
151			uncompress(kSplashIcons8BitCompressedImage,
152				sizeof(kSplashIcons8BitCompressedImage),
153				gKernelArgs.boot_splash, uncompressedSize);
154			lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash
155				+ (kSplashIconsWidth * iconsHalfHeight);
156		break;
157		default:	// 24bits is assumed here
158			uncompressedSize *= 3;
159			// pointer into the lower half of the icons image data
160			gKernelArgs.boot_splash
161				= (uint8*)kernel_args_malloc(uncompressedSize);
162			if (gKernelArgs.boot_splash == NULL)
163				return B_NO_MEMORY;
164			uncompress(kSplashIcons24BitCompressedImage,
165				sizeof(kSplashIcons24BitCompressedImage),
166				gKernelArgs.boot_splash, uncompressedSize);
167			lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash
168				+ (kSplashIconsWidth * iconsHalfHeight) * 3;
169		break;
170	}
171
172	// render initial (grayed out) icons
173	// the grayed out version is the lower half of the icons image
174
175	width = min_c(kSplashIconsWidth, gKernelArgs.frame_buffer.width);
176	height = min_c(kSplashLogoHeight + iconsHalfHeight,
177		gKernelArgs.frame_buffer.height);
178	placementX = max_c(0, min_c(100, kSplashIconsPlacementX));
179	placementY = max_c(0, min_c(100, kSplashIconsPlacementY));
180
181	x = (gKernelArgs.frame_buffer.width - width) * placementX / 100;
182	y = kSplashLogoHeight + (gKernelArgs.frame_buffer.height - height)
183		* placementY / 100;
184
185	height = min_c(iconsHalfHeight, gKernelArgs.frame_buffer.height);
186	video_blit_image(frameBuffer, lowerHalfIconImage, width, height,
187		kSplashIconsWidth, x, y);
188	return B_OK;
189}
190
191
192
193