1 | ␊ |
2 | /* Graphic utility functions and data types␊ |
3 | * Prashant Vaibhav (C) 12/12/2008␊ |
4 | * Chameleon␊ |
5 | */␊ |
6 | #include "libsaio.h"␊ |
7 | #include "bootstruct.h"␊ |
8 | #include "graphic_utils.h"␊ |
9 | #include "appleClut8.h"␊ |
10 | #include "vbe.h"␊ |
11 | #include "gui.h"␊ |
12 | #include "platform.h"␊ |
13 | ␊ |
14 | #define VIDEO(x) (((boot_args*)getBootArgs())->Video.v_ ## x)␊ |
15 | ␊ |
16 | #define MIN(x, y) ((x) < (y) ? (x) : (y))␊ |
17 | static unsigned long lookUpCLUTIndex( unsigned char index,␊ |
18 | unsigned char depth );␊ |
19 | ␊ |
20 | static int␊ |
21 | setVESATextMode( unsigned short cols,␊ |
22 | ␉␉␉␉unsigned short rows,␊ |
23 | ␉␉␉␉unsigned char bitsPerPixel );␊ |
24 | ␊ |
25 | static void setupPalette( VBEPalette * p, const unsigned char * g );␊ |
26 | static unsigned long lookUpCLUTIndex( unsigned char index,␊ |
27 | unsigned char depth );␊ |
28 | static unsigned short␊ |
29 | getVESAModeWithProperties( unsigned short width,␊ |
30 | unsigned short height,␊ |
31 | unsigned char bitsPerPixel,␊ |
32 | unsigned short attributesSet,␊ |
33 | unsigned short attributesClear,␊ |
34 | VBEModeInfoBlock * outModeInfo,␊ |
35 | unsigned short * vesaVersion );␊ |
36 | //==========================================================================␊ |
37 | // LookUpCLUTIndex␊ |
38 | ␊ |
39 | static unsigned long lookUpCLUTIndex( unsigned char index,␊ |
40 | unsigned char depth )␊ |
41 | {␊ |
42 | long result, red, green, blue;␊ |
43 | ␉␊ |
44 | red = appleClut8[index * 3 + 0];␊ |
45 | green = appleClut8[index * 3 + 1];␊ |
46 | blue = appleClut8[index * 3 + 2];␊ |
47 | ␉␊ |
48 | switch (depth) {␊ |
49 | case 16 :␊ |
50 | result = ((red & 0xF8) << 7) | ␊ |
51 | ␉␉␉((green & 0xF8) << 2) |␊ |
52 | ␉␉␉((blue & 0xF8) >> 3);␊ |
53 | result |= (result << 16);␊ |
54 | break;␊ |
55 | ␉␉␉␊ |
56 | case 32 :␊ |
57 | result = (red << 16) | (green << 8) | blue;␊ |
58 | break;␊ |
59 | ␉␉␉␊ |
60 | default :␊ |
61 | result = index | (index << 8);␊ |
62 | result |= (result << 16);␊ |
63 | break;␊ |
64 | }␊ |
65 | ␉␊ |
66 | return result;␊ |
67 | }␊ |
68 | ␊ |
69 | int␊ |
70 | convertImage( unsigned short width,␊ |
71 | ␉␉␉ unsigned short height,␊ |
72 | ␉␉␉ const unsigned char *imageData,␊ |
73 | ␉␉␉ unsigned char **newImageData )␊ |
74 | {␊ |
75 | int cnt;␊ |
76 | unsigned char *img;␊ |
77 | unsigned short *img16;␊ |
78 | unsigned long *img32;␊ |
79 | ␉␊ |
80 | switch ( VIDEO(depth) ) {␊ |
81 | ␉␉case 16 :␊ |
82 | {␊ |
83 | ␉␉␉img16 = malloc(width * height * 2);␊ |
84 | ␉␉␉if ( !img16 ) return 1;␊ |
85 | ␉␉␉for (cnt = 0; cnt < (width * height); cnt++)␊ |
86 | ␉␉␉␉img16[cnt] = lookUpCLUTIndex(imageData[cnt], 16);␊ |
87 | ␉␉␉img = (unsigned char *)img16;␊ |
88 | *newImageData = img;␊ |
89 | ␉␉␉break;␊ |
90 | }␊ |
91 | ␉␉case 32 :␊ |
92 | {␊ |
93 | ␉␉␉img32 = malloc(width * height * 4);␊ |
94 | ␉␉␉if ( !img32 ) return 1;␊ |
95 | ␉␉␉for (cnt = 0; cnt < (width * height); cnt++)␊ |
96 | ␉␉␉␉img32[cnt] = lookUpCLUTIndex(imageData[cnt], 32);␊ |
97 | ␉␉␉img = (unsigned char *)img32;␊ |
98 | *newImageData = img;␊ |
99 | ␉␉␉break;␊ |
100 | }␊ |
101 | ␉␉default :␊ |
102 | {␊ |
103 | ␉␉␉img = malloc(width * height);␊ |
104 | if ( !img ) return 1;␊ |
105 | ␉␉␉bcopy(imageData, img, width * height);␊ |
106 | *newImageData = img;␊ |
107 | ␉␉␉break;␊ |
108 | }␊ |
109 | }␊ |
110 | return 0;␊ |
111 | }␊ |
112 | ␊ |
113 | //==========================================================================␊ |
114 | // drawDataRectangle␊ |
115 | ␊ |
116 | void drawDataRectangle( unsigned short x,␊ |
117 | ␉␉␉␉␉ unsigned short y,␊ |
118 | ␉␉␉␉␉ unsigned short width,␊ |
119 | ␉␉␉␉␉ unsigned short height,␊ |
120 | ␉␉␉␉␉ unsigned char * data )␊ |
121 | {␊ |
122 | unsigned short drawWidth;␊ |
123 | long pixelBytes = VIDEO(depth) / 8;␊ |
124 | unsigned char * vram = (unsigned char *) VIDEO(baseAddr) +␊ |
125 | ␉VIDEO(rowBytes) * y + pixelBytes * x;␊ |
126 | ␉␊ |
127 | drawWidth = MIN(width, VIDEO(width) - x);␊ |
128 | height = MIN(height, VIDEO(height) - y);␊ |
129 | while ( height-- ) {␊ |
130 | bcopy( data, vram, drawWidth * pixelBytes );␊ |
131 | vram += VIDEO(rowBytes);␊ |
132 | data += width * pixelBytes;␊ |
133 | }␊ |
134 | }␊ |
135 | ␊ |
136 | //==========================================================================␊ |
137 | //␊ |
138 | void ␊ |
139 | printVBEModeInfo(void)␊ |
140 | {␊ |
141 | VBEInfoBlock vbeInfo;␊ |
142 | unsigned short * modePtr;␊ |
143 | VBEModeInfoBlock modeInfo;␊ |
144 | int err;␊ |
145 | int line;␊ |
146 | ␉␊ |
147 | ␉//bzero( &vbeInfo, sizeof(vbeInfo) );␊ |
148 | bzero( &vbeInfo, sizeof(VBEInfoBlock) );␊ |
149 | ␉␊ |
150 | ␉strlcpy( (char*)&vbeInfo, "VBE2", sizeof(VBEInfoBlock) );␊ |
151 | err = getVBEInfo( &vbeInfo );␊ |
152 | if ( err != errSuccess )␊ |
153 | return;␊ |
154 | ␉␊ |
155 | line = 0;␊ |
156 | ␉␊ |
157 | // Activate and clear page 1␊ |
158 | setActiveDisplayPage(1);␊ |
159 | clearScreenRows(0, 24);␊ |
160 | setCursorPosition( 0, 0, 1 );␊ |
161 | ␉␊ |
162 | ␉printf("Video modes supported:\n", VBEDecodeFP(const char *, vbeInfo.OEMStringPtr));␊ |
163 | ␉␊ |
164 | ␉// Loop through the mode list, and find the matching mode.␊ |
165 | ␉␊ |
166 | for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );␊ |
167 | ␉␉ *modePtr != modeEndOfList; modePtr++ )␊ |
168 | {␊ |
169 | // Get mode information.␊ |
170 | ␉␉␊ |
171 | //bzero( &modeInfo, sizeof(modeInfo) );␊ |
172 | bzero( &modeInfo, sizeof(VBEModeInfoBlock) );␊ |
173 | ␊ |
174 | err = getVBEModeInfo( *modePtr, &modeInfo );␊ |
175 | if ( err != errSuccess )␊ |
176 | {␊ |
177 | continue;␊ |
178 | }␊ |
179 | ␉␉␊ |
180 | printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",␊ |
181 | *modePtr, modeInfo.XResolution, modeInfo.YResolution,␊ |
182 | modeInfo.BitsPerPixel, modeInfo.MemoryModel,␊ |
183 | modeInfo.ModeAttributes);␊ |
184 | ␉␉␊ |
185 | if (line++ >= 20) {␊ |
186 | pause();␊ |
187 | line = 0;␊ |
188 | clearScreenRows(0, 24);␊ |
189 | setCursorPosition( 0, 0, 1 );␊ |
190 | }␊ |
191 | } ␊ |
192 | if (line != 0) {␊ |
193 | pause();␊ |
194 | }␊ |
195 | setActiveDisplayPage(0);␊ |
196 | }␊ |
197 | ␊ |
198 | ␊ |
199 | ␊ |
200 | char *getVBEModeInfoString(void)␊ |
201 | {␊ |
202 | ␉VBEInfoBlock vbeInfo;␊ |
203 | unsigned short * modePtr;␊ |
204 | VBEModeInfoBlock modeInfo;␊ |
205 | int err;␊ |
206 | ␉␊ |
207 | bzero( &vbeInfo, sizeof(VBEInfoBlock) );␊ |
208 | ␉strlcpy( (char*)&vbeInfo, "VBE2", sizeof(VBEInfoBlock) );␊ |
209 | err = getVBEInfo( &vbeInfo );␊ |
210 | if ( err != errSuccess )␊ |
211 | return 0;␊ |
212 | ␉␊ |
213 | ␉char *buff=malloc(sizeof(char)*3072);␊ |
214 | ␉if(!buff) return 0;␊ |
215 | ␉␊ |
216 | ␉// Loop through the mode list, and find the matching mode.␊ |
217 | for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );␊ |
218 | ␉␉ *modePtr != modeEndOfList; modePtr++ )␊ |
219 | {␊ |
220 | // Get mode information.␊ |
221 | ␉␉␊ |
222 | bzero( &modeInfo, sizeof(VBEModeInfoBlock) );␊ |
223 | err = getVBEModeInfo( *modePtr, &modeInfo );␊ |
224 | if ( err != errSuccess )␊ |
225 | {␊ |
226 | continue;␊ |
227 | }␊ |
228 | ␉␉␊ |
229 | sprintf(buff+strlen(buff), "Mode %x: %dx%dx%d mm:%d attr:%x\n",␊ |
230 | ␉␉␉␉*modePtr, modeInfo.XResolution, modeInfo.YResolution,␊ |
231 | ␉␉␉␉modeInfo.BitsPerPixel, modeInfo.MemoryModel,␊ |
232 | ␉␉␉␉modeInfo.ModeAttributes);␊ |
233 | ␉␉␊ |
234 | } ␊ |
235 | ␉return buff;␊ |
236 | }␊ |
237 | ␊ |
238 | ␊ |
239 | void blendImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height,␊ |
240 | ␉␉␉␉uint8_t *data)␊ |
241 | {␊ |
242 | uint16_t drawWidth;␊ |
243 | uint8_t *vram = (uint8_t *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + 4 * x;␊ |
244 | ␉␊ |
245 | drawWidth = MIN(width, VIDEO(width) - x);␊ |
246 | height = MIN(height, VIDEO(height) - y);␊ |
247 | while (height--) {␊ |
248 | ␉␉switch (VIDEO (depth))␊ |
249 | ␉␉{␊ |
250 | ␉␉␉case 32: /* Optimized version*/␊ |
251 | ␉␉␉{␊ |
252 | ␉␉␉␉uint32_t s; uint32_t* d; // Source (img) and destination (bkgd) pixels␊ |
253 | ␉␉␉␉uint32_t a; // Alpha␊ |
254 | ␉␉␉␉uint32_t dstrb, dstg, srcrb, srcg, drb, dg, rb, g, tempB; // Intermediate variables␊ |
255 | ␉␉␉␉uint16_t pos;␊ |
256 | ␉␉␉␉␊ |
257 | ␉␉␉␉for (pos = 0; pos < drawWidth * 4; pos += 4) {␊ |
258 | ␉␉␉␉␉// Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html␊ |
259 | ␉␉␉␉␉s = *((uint32_t*) (data + pos));␊ |
260 | ␉␉␉␉␉d = (uint32_t*) (vram + pos);␊ |
261 | ␉␉␉␉␉␊ |
262 | ␉␉␉␉␉// Flip B and R in source␊ |
263 | ␉␉␉␉␉// TODO: use XCHG and inline assembly to do this in a faster, saner way␊ |
264 | ␉␉␉␉␉tempB = (s & 0xFF0000); // save B␊ |
265 | ␉␉␉␉␉s = (s & 0xFF00FFFF) | ((s & 0xFF) << 16); // put R in B␊ |
266 | ␉␉␉␉␉s = (s & 0xFFFFFF00) | (tempB >> 16); // put B in R␊ |
267 | ␉␉␉␉␉␊ |
268 | ␉␉␉␉␉a = (s >> 24) + 1;␊ |
269 | ␉␉␉␉␉␊ |
270 | ␉␉␉␉␉dstrb = *d & 0xFF00FF; dstg = *d & 0xFF00;␊ |
271 | ␉␉␉␉␉srcrb = s & 0xFF00FF; srcg = s & 0xFF00;␊ |
272 | ␉␉␉␉␉␊ |
273 | ␉␉␉␉␉drb = srcrb - dstrb;␊ |
274 | ␉␉␉␉␉dg = srcg - dstg;␊ |
275 | ␉␉␉␉␉drb *= a; dg *= a;␊ |
276 | ␉␉␉␉␉drb >>= 8; dg >>= 8;␊ |
277 | ␉␉␉␉␉␊ |
278 | ␉␉␉␉␉rb = (drb + dstrb) & 0xFF00FF;␊ |
279 | ␉␉␉␉␉g = (dg + dstg) & 0xFF00;␊ |
280 | ␉␉␉␉␉␊ |
281 | ␉␉␉␉␉*d = rb | g;␊ |
282 | ␉␉␉␉}␊ |
283 | ␉␉␉}␊ |
284 | ␉␉␉␉break;␊ |
285 | ␉␉␉␉␊ |
286 | ␉␉␉default: /*Universal version*/␊ |
287 | ␉␉␉{␊ |
288 | ␉␉␉␉uint32_t s; ␊ |
289 | ␉␉␉␉uint32_t a; // Alpha␊ |
290 | ␉␉␉␉uint32_t dr, dg, db, sr, sg, sb; // Intermediate variables␊ |
291 | ␉␉␉␉uint16_t pos;␊ |
292 | ␉␉␉␉int bpp = (VIDEO (depth) + 7)/8;␊ |
293 | ␉␉␉␉␊ |
294 | ␉␉␉␉for (pos = 0; pos < drawWidth; pos ++) {␊ |
295 | ␉␉␉␉␉// Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html␊ |
296 | ␉␉␉␉␉s = *((uint32_t*) (data + 4*pos));␊ |
297 | ␉␉␉␉␉␊ |
298 | ␉␉␉␉␉sb = (s & 0xFF0000) >> 16;␊ |
299 | ␉␉␉␉␉sg = (s & 0xFF00) >> 8;␊ |
300 | ␉␉␉␉␉sr = (s & 0xFF);␊ |
301 | ␉␉␉␉␉␊ |
302 | ␉␉␉␉␉a = (s >> 24) + 1;␊ |
303 | ␉␉␉␉␉␊ |
304 | ␉␉␉␉␉switch (VIDEO (depth))␊ |
305 | ␉␉␉␉␉{␊ |
306 | ␉␉␉␉␉␉case 24:␊ |
307 | ␉␉␉␉␉␉␉db = ((*(uint32_t *)(vram + bpp*pos))&0xff);␊ |
308 | ␉␉␉␉␉␉␉dg = ((*(uint32_t *)(vram + bpp*pos))&0xff00)>>8;␊ |
309 | ␉␉␉␉␉␉␉dr = ((*(uint32_t *)(vram + bpp*pos))&0xff0000)>>16;␊ |
310 | ␉␉␉␉␉␉␉break;␊ |
311 | ␉␉␉␉␉␉case 16://16-bit seems to be 15-bit␊ |
312 | ␉␉␉␉␉␉␉/*␉␉␉␉␉␉␉db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3;␊ |
313 | ␉␉␉␉␉␉␉ dg = ((*(uint16_t *)(vram + bpp*pos))&0x07e0)>>3;␊ |
314 | ␉␉␉␉␉␉␉ dr = ((*(uint16_t *)(vram + bpp*pos))&0xf800)>>8;␊ |
315 | ␉␉␉␉␉␉␉ break;␉␉␉␉␉␉␉*/␊ |
316 | ␉␉␉␉␉␉case 15:␊ |
317 | ␉␉␉␉␉␉␉db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3;␊ |
318 | ␉␉␉␉␉␉␉dg = ((*(uint16_t *)(vram + bpp*pos))&0x03e0)>>2;␊ |
319 | ␉␉␉␉␉␉␉dr = ((*(uint16_t *)(vram + bpp*pos))&0x7c00)>>7;␊ |
320 | ␉␉␉␉␉␉␉break;␉␉␊ |
321 | ␉␉␉␉␉␉default:␊ |
322 | ␉␉␉␉␉␉␉return;␊ |
323 | ␉␉␉␉␉}␊ |
324 | ␉␉␉␉␉␊ |
325 | ␉␉␉␉␉dr = (((sr - dr) * a) >> 8) + dr;␊ |
326 | ␉␉␉␉␉dg = (((sg - dg) * a) >> 8) + dg;␊ |
327 | ␉␉␉␉␉db = (((sb - db) * a) >> 8) + db;␊ |
328 | ␉␉␉␉␉switch (VIDEO (depth))␊ |
329 | ␉␉␉␉␉{␊ |
330 | ␉␉␉␉␉␉case 24:␊ |
331 | ␉␉␉␉␉␉␉*(uint32_t *)(vram + bpp*pos) = (*(uint32_t *)(vram + bpp*pos) &0xff000000)␊ |
332 | ␉␉␉␉␉␉␉| (db&0xff) | ((dg&0xff)<<8) | ((dr&0xff)<<16);␊ |
333 | ␉␉␉␉␉␉␉break;␊ |
334 | ␉␉␉␉␉␉case 16:␊ |
335 | ␉␉␉␉␉␉␉//␉␉␉␉␉␉␉*(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xfc)<<3) | ((dr&0xf8)<<8);␊ |
336 | ␉␉␉␉␉␉␉//␉␉␉␉␉␉␉break;␉␉␉␉␉␉␉␊ |
337 | ␉␉␉␉␉␉case 15:␊ |
338 | ␉␉␉␉␉␉␉*(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xf8)<<2) | ((dr&0xf8)<<7);␊ |
339 | ␉␉␉␉␉␉␉break;␉␊ |
340 | ␉␉␉␉␉␉default:␊ |
341 | ␉␉␉␉␉␉␉break;␊ |
342 | ␉␉␉␉␉}␊ |
343 | ␉␉␉␉␉␊ |
344 | ␉␉␉␉}␉␉␉␉␊ |
345 | ␉␉␉}␊ |
346 | ␉␉␉␉break;␊ |
347 | }␊ |
348 | vram += VIDEO(rowBytes);␊ |
349 | data += width * 4;␊ |
350 | }␊ |
351 | }␊ |
352 | ␊ |
353 | void drawCheckerBoard(void)␊ |
354 | {␊ |
355 | uint32_t *vram = (uint32_t *) VIDEO(baseAddr);␊ |
356 | uint16_t x, y;␊ |
357 | uint8_t color;␊ |
358 | ␉␊ |
359 | for (y = 0; y < VIDEO(height); y++, vram += VIDEO(width)) {␊ |
360 | for (x = 0; x < VIDEO(width); x++) {␊ |
361 | color = 204 + 51 * (((x / 8) % 2) == ((y / 8) % 2));␊ |
362 | vram[x] = (color << 16) | (color << 8) | color;␊ |
363 | }␊ |
364 | }␊ |
365 | }␊ |
366 | ␊ |
367 | //==========================================================================␊ |
368 | // getNumberArrayFromProperty␊ |
369 | ␊ |
370 | int␊ |
371 | getNumberArrayFromProperty( const char * propKey,␊ |
372 | ␉␉␉␉␉␉ unsigned long numbers[],␊ |
373 | ␉␉␉␉␉␉ unsigned long maxArrayCount )␊ |
374 | {␊ |
375 | char * propStr;␊ |
376 | unsigned long count = 0;␊ |
377 | ␉␊ |
378 | propStr = newStringForKey( (char *) propKey , DEFAULT_BOOT_CONFIG );␊ |
379 | if ( propStr )␊ |
380 | {␊ |
381 | char * delimiter = propStr;␊ |
382 | char * p = propStr;␊ |
383 | ␉␉␊ |
384 | while ( count < maxArrayCount && *p != '\0' )␊ |
385 | {␊ |
386 | unsigned long val = strtoul( p, &delimiter, 10 );␊ |
387 | if ( p != delimiter )␊ |
388 | {␊ |
389 | numbers[count++] = val;␊ |
390 | p = delimiter;␊ |
391 | }␊ |
392 | while ( ( *p != '\0' ) && !isdigit(*p) )␊ |
393 | p++;␊ |
394 | }␊ |
395 | ␉␉␊ |
396 | free( propStr );␊ |
397 | }␊ |
398 | ␉␊ |
399 | return count;␊ |
400 | }␊ |
401 | ␊ |
402 | //==========================================================================␊ |
403 | // Simple decompressor for boot images encoded in RLE format.␊ |
404 | ␊ |
405 | char * decodeRLE( const void * rleData, int rleBlocks, int outBytes )␊ |
406 | {␊ |
407 | char *out, *cp;␊ |
408 | ␉␊ |
409 | struct RLEBlock {␊ |
410 | unsigned char count;␊ |
411 | unsigned char value;␊ |
412 | } * bp = (struct RLEBlock *) rleData;␊ |
413 | ␉␊ |
414 | out = cp = malloc( outBytes );␊ |
415 | if ( out == NULL ) return NULL;␊ |
416 | ␉␊ |
417 | while ( rleBlocks-- )␊ |
418 | {␊ |
419 | memset( cp, bp->value, bp->count );␊ |
420 | cp += bp->count;␊ |
421 | bp++;␊ |
422 | }␊ |
423 | ␉␊ |
424 | return out;␊ |
425 | }␊ |
426 | ␊ |
427 | static void * stosl(void * dst, long val, long len)␊ |
428 | {␊ |
429 | asm volatile ( "rep; stosl"␊ |
430 | ␉␉␉␉ : "=c" (len), "=D" (dst)␊ |
431 | ␉␉␉␉ : "0" (len), "1" (dst), "a" (val)␊ |
432 | ␉␉␉␉ : "memory" );␊ |
433 | ␉␊ |
434 | return dst;␊ |
435 | }␊ |
436 | ␊ |
437 | void drawColorRectangle( unsigned short x,␊ |
438 | ␉␉␉␉␉␉unsigned short y,␊ |
439 | ␉␉␉␉␉␉unsigned short width,␊ |
440 | ␉␉␉␉␉␉unsigned short height,␊ |
441 | ␉␉␉␉␉␉unsigned char colorIndex )␊ |
442 | {␊ |
443 | long pixelBytes;␊ |
444 | long color = lookUpCLUTIndex( colorIndex, VIDEO(depth) );␊ |
445 | char * vram;␊ |
446 | ␉␊ |
447 | pixelBytes = VIDEO(depth) / 8;␊ |
448 | vram = (char *) VIDEO(baseAddr) +␊ |
449 | ␉VIDEO(rowBytes) * y + pixelBytes * x;␊ |
450 | ␉␊ |
451 | width = MIN(width, VIDEO(width) - x);␊ |
452 | height = MIN(height, VIDEO(height) - y);␊ |
453 | ␉␊ |
454 | while ( height-- )␊ |
455 | {␊ |
456 | int rem = ( pixelBytes * width ) % 4;␊ |
457 | if ( rem ) bcopy( &color, vram, rem );␊ |
458 | stosl( vram + rem, color, pixelBytes * width / 4 );␊ |
459 | vram += VIDEO(rowBytes);␊ |
460 | }␊ |
461 | }␊ |
462 | ␊ |
463 | ␊ |
464 | ␊ |
465 | //==========================================================================␊ |
466 | // getVESAModeWithProperties␊ |
467 | //␊ |
468 | // Return the VESA mode that matches the properties specified.␊ |
469 | // If a mode is not found, then return the "best" available mode.␊ |
470 | ␊ |
471 | static unsigned short␊ |
472 | getVESAModeWithProperties( unsigned short width,␊ |
473 | ␉␉␉␉␉␉ unsigned short height,␊ |
474 | ␉␉␉␉␉␉ unsigned char bitsPerPixel,␊ |
475 | ␉␉␉␉␉␉ unsigned short attributesSet,␊ |
476 | ␉␉␉␉␉␉ unsigned short attributesClear,␊ |
477 | ␉␉␉␉␉␉ VBEModeInfoBlock * outModeInfo,␊ |
478 | ␉␉␉␉␉␉ unsigned short * vesaVersion )␊ |
479 | {␊ |
480 | VBEInfoBlock vbeInfo;␊ |
481 | unsigned short * modePtr;␊ |
482 | VBEModeInfoBlock modeInfo;␊ |
483 | unsigned char modeBitsPerPixel;␊ |
484 | unsigned short matchedMode = modeEndOfList;␊ |
485 | int err;␊ |
486 | ␉␊ |
487 | // Clear output mode info.␊ |
488 | ␉␊ |
489 | //bzero( outModeInfo, sizeof(*outModeInfo) );␊ |
490 | ␉bzero( outModeInfo, sizeof(VBEModeInfoBlock) );␊ |
491 | ␉␊ |
492 | // Get VBE controller info containing the list of supported modes.␊ |
493 | ␉␊ |
494 | //bzero( &vbeInfo, sizeof(vbeInfo) );␊ |
495 | bzero( &vbeInfo, sizeof(VBEInfoBlock) );␊ |
496 | ␊ |
497 | ␉strlcpy( (char*)&vbeInfo, "VBE2", sizeof(VBEInfoBlock) );␊ |
498 | err = getVBEInfo( &vbeInfo );␊ |
499 | if ( err != errSuccess )␊ |
500 | {␊ |
501 | return modeEndOfList;␊ |
502 | }␊ |
503 | ␉␊ |
504 | // Report the VESA major/minor version number.␊ |
505 | ␉␊ |
506 | if (vesaVersion) *vesaVersion = vbeInfo.VESAVersion;␊ |
507 | ␉␊ |
508 | // Loop through the mode list, and find the matching mode.␊ |
509 | ␉␊ |
510 | for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );␊ |
511 | ␉␉ *modePtr != modeEndOfList; modePtr++ )␊ |
512 | {␊ |
513 | // Get mode information.␊ |
514 | ␉␉␊ |
515 | bzero( &modeInfo, sizeof(VBEModeInfoBlock) );␉␉␊ |
516 | err = getVBEModeInfo( *modePtr, &modeInfo );␊ |
517 | if ( err != errSuccess )␊ |
518 | {␊ |
519 | continue;␊ |
520 | }␊ |
521 | ␉␉␊ |
522 | #if DEBUG␊ |
523 | printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",␊ |
524 | *modePtr, modeInfo.XResolution, modeInfo.YResolution,␊ |
525 | modeInfo.BitsPerPixel, modeInfo.MemoryModel,␊ |
526 | modeInfo.ModeAttributes);␊ |
527 | #endif␊ |
528 | ␉␉␊ |
529 | // Filter out unwanted modes based on mode attributes.␊ |
530 | ␉␉␊ |
531 | if ( ( ( modeInfo.ModeAttributes & attributesSet ) != attributesSet )␊ |
532 | ␉␉␉|| ( ( modeInfo.ModeAttributes & attributesClear ) != 0 ) )␊ |
533 | {␊ |
534 | continue;␊ |
535 | }␊ |
536 | ␉␉␊ |
537 | // Pixel depth in bits.␊ |
538 | ␉␉␊ |
539 | modeBitsPerPixel = modeInfo.BitsPerPixel;␊ |
540 | ␉␉␊ |
541 | if ( ( modeBitsPerPixel == 4 ) && ( modeInfo.MemoryModel == 0 ) )␊ |
542 | {␊ |
543 | // Text mode, 16 colors.␊ |
544 | }␊ |
545 | else if ( ( modeBitsPerPixel == 8 ) && ( modeInfo.MemoryModel == 4 ) )␊ |
546 | {␊ |
547 | // Packed pixel, 256 colors.␊ |
548 | }␊ |
549 | else if ( ( ( modeBitsPerPixel == 16 ) || ( modeBitsPerPixel == 15 ) )␊ |
550 | ␉␉␉␉ && ( modeInfo.MemoryModel == 6 )␊ |
551 | ␉␉␉␉ && ( modeInfo.RedMaskSize == 5 )␊ |
552 | ␉␉␉␉ && ( modeInfo.GreenMaskSize == 5 )␊ |
553 | ␉␉␉␉ && ( modeInfo.BlueMaskSize == 5 ) )␊ |
554 | {␊ |
555 | // Direct color, 16 bpp (1:5:5:5).␊ |
556 | modeInfo.BitsPerPixel = modeBitsPerPixel = 16;␊ |
557 | }␊ |
558 | else if ( ( modeBitsPerPixel == 32 )␊ |
559 | ␉␉␉␉ && ( modeInfo.MemoryModel == 6 )␊ |
560 | ␉␉␉␉ && ( modeInfo.RedMaskSize == 8 )␊ |
561 | ␉␉␉␉ && ( modeInfo.GreenMaskSize == 8 )␊ |
562 | ␉␉␉␉ && ( modeInfo.BlueMaskSize == 8 ) )␊ |
563 | {␊ |
564 | // Direct color, 32 bpp (8:8:8:8).␊ |
565 | }␊ |
566 | else␊ |
567 | {␊ |
568 | continue; // Not a supported mode.␊ |
569 | }␊ |
570 | ␉␉␊ |
571 | // Modes larger than the specified dimensions are skipped.␊ |
572 | ␉␉␊ |
573 | if ( ( modeInfo.XResolution > width ) ||␊ |
574 | ␉␉␉( modeInfo.YResolution > height ) )␊ |
575 | {␊ |
576 | continue;␊ |
577 | }␊ |
578 | ␉␉␊ |
579 | // Perfect match, we're done looking.␊ |
580 | ␉␉␊ |
581 | if ( ( modeInfo.XResolution == width ) &&␊ |
582 | ␉␉␉( modeInfo.YResolution == height ) &&␊ |
583 | ␉␉␉( modeBitsPerPixel == bitsPerPixel ) )␊ |
584 | {␊ |
585 | matchedMode = *modePtr;␊ |
586 | bcopy( &modeInfo, outModeInfo, sizeof(VBEModeInfoBlock) );␊ |
587 | ␉␉␉␊ |
588 | break;␊ |
589 | }␊ |
590 | ␉␉␊ |
591 | // Save the next "best" mode in case a perfect match is not found.␊ |
592 | ␉␉␊ |
593 | if ( modeInfo.XResolution == outModeInfo->XResolution &&␊ |
594 | ␉␉␉modeInfo.YResolution == outModeInfo->YResolution &&␊ |
595 | ␉␉␉modeBitsPerPixel <= outModeInfo->BitsPerPixel )␊ |
596 | {␊ |
597 | continue; // Saved mode has more depth.␊ |
598 | }␊ |
599 | if ( modeInfo.XResolution < outModeInfo->XResolution ||␊ |
600 | ␉␉␉modeInfo.YResolution < outModeInfo->YResolution ||␊ |
601 | ␉␉␉modeBitsPerPixel < outModeInfo->BitsPerPixel )␊ |
602 | {␊ |
603 | continue; // Saved mode has more resolution.␊ |
604 | }␊ |
605 | ␉␉␊ |
606 | matchedMode = *modePtr;␊ |
607 | bcopy( &modeInfo, outModeInfo, sizeof(VBEModeInfoBlock) );␊ |
608 | ␉␉␊ |
609 | }␊ |
610 | ␉␊ |
611 | return matchedMode;␊ |
612 | }␊ |
613 | ␊ |
614 | //==========================================================================␊ |
615 | // setVESATextMode␊ |
616 | ␊ |
617 | static int␊ |
618 | setVESATextMode( unsigned short cols,␊ |
619 | ␉␉␉␉unsigned short rows,␊ |
620 | ␉␉␉␉unsigned char bitsPerPixel )␊ |
621 | {␊ |
622 | VBEModeInfoBlock minfo;␊ |
623 | ␉minfo.XResolution = 0;␊ |
624 | minfo.YResolution = 0;␊ |
625 | unsigned short mode = modeEndOfList;␊ |
626 | ␉␊ |
627 | minfo.XResolution = 0;␊ |
628 | minfo.YResolution = 0;␊ |
629 | ␊ |
630 | if ( (cols != 80) || (rows != 25) ) // not 80x25 mode␊ |
631 | {␊ |
632 | mode = getVESAModeWithProperties( cols, rows, bitsPerPixel,␊ |
633 | ␉␉␉␉␉␉␉␉␉␉ maColorModeBit |␊ |
634 | ␉␉␉␉␉␉␉␉␉␉ maModeIsSupportedBit,␊ |
635 | ␉␉␉␉␉␉␉␉␉␉ maGraphicsModeBit,␊ |
636 | ␉␉␉␉␉␉␉␉␉␉ &minfo, NULL );␊ |
637 | }␊ |
638 | ␉␊ |
639 | if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) )␊ |
640 | {␊ |
641 | video_mode( 2 ); // VGA BIOS, 80x25 text mode.␊ |
642 | minfo.XResolution = 80;␊ |
643 | minfo.YResolution = 25;␊ |
644 | }␊ |
645 | ␉␊ |
646 | // Update KernBootStruct using info provided by the selected␊ |
647 | // VESA mode.␊ |
648 | ␉␊ |
649 | Boot_Video␉Video;␉␉/* Video Information */␊ |
650 | ␊ |
651 | ␊ |
652 | Video.v_display = VGA_TEXT_MODE;␊ |
653 | Video.v_width = 0xb8000;␊ |
654 | Video.v_height = minfo.XResolution;␊ |
655 | Video.v_depth = minfo.YResolution;␊ |
656 | Video.v_rowBytes = 8;␊ |
657 | Video.v_baseAddr = 0x8000; ␊ |
658 | ␊ |
659 | setBootArgsVideoStruct(&Video); ␊ |
660 | ␉␊ |
661 | return errSuccess; // always return success␊ |
662 | }␊ |
663 | ␊ |
664 | //==========================================================================␊ |
665 | // setVideoMode␊ |
666 | //␊ |
667 | // Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE.␊ |
668 | ␊ |
669 | void␊ |
670 | setVideoMode( int mode)␊ |
671 | {␊ |
672 | unsigned long params[4];␊ |
673 | int count;␊ |
674 | int err = errSuccess;␊ |
675 | ␉␊ |
676 | if ( mode == GRAPHICS_MODE )␊ |
677 | {␊ |
678 | ␉␉if ( (err=GUI_initGraphicsMode ()) == errSuccess ) {␊ |
679 | ␉␉␉if (get_env(envgVerboseMode)) {␊ |
680 | ␉␉␉␉// Tell the kernel to use text mode on a linear frame buffer display␊ |
681 | setBootArgsVideoMode(FB_TEXT_MODE);␊ |
682 | ␉␉␉␉␊ |
683 | ␉␉␉} else {␊ |
684 | setBootArgsVideoMode(GRAPHICS_MODE);␊ |
685 | ␉␉␉␉␊ |
686 | ␉␉␉}␊ |
687 | ␉␉}␊ |
688 | }␊ |
689 | ␉␊ |
690 | if ( (mode == VGA_TEXT_MODE) || (err != errSuccess) )␊ |
691 | {␊ |
692 | count = getNumberArrayFromProperty( kTextModeKey, params, 2 );␊ |
693 | if ( count < 2 )␊ |
694 | {␊ |
695 | params[0] = 80; // Default text mode is 80x25.␊ |
696 | params[1] = 25;␊ |
697 | }␊ |
698 | ␉␉␊ |
699 | ␉␉setVESATextMode( params[0], params[1], 4 );␊ |
700 | setBootArgsVideoMode(VGA_TEXT_MODE);␊ |
701 | }␊ |
702 | ␉␊ |
703 | }␊ |
704 | ␊ |
705 | //==========================================================================␊ |
706 | // setupPalette␊ |
707 | ␊ |
708 | static void setupPalette( VBEPalette * p, const unsigned char * g )␊ |
709 | {␊ |
710 | int i;␊ |
711 | unsigned char * source = (unsigned char *) g;␊ |
712 | ␉␊ |
713 | for (i = 0; i < 256; i++)␊ |
714 | {␊ |
715 | (*p)[i] = 0;␊ |
716 | (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red␊ |
717 | (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green␊ |
718 | (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue␊ |
719 | ␉␉␊ |
720 | }␊ |
721 | }␊ |
722 | ␊ |
723 | ␊ |
724 | //==========================================================================␊ |
725 | // setVESAGraphicsMode␊ |
726 | ␊ |
727 | int setVESAGraphicsMode( unsigned short width, unsigned short height, unsigned char bitsPerPixel)␊ |
728 | {␊ |
729 | VBEModeInfoBlock minfo;␊ |
730 | unsigned short mode;␊ |
731 | unsigned short vesaVersion;␊ |
732 | int err = errFuncNotSupported;␊ |
733 | ␉␊ |
734 | do {␊ |
735 | mode = getVESAModeWithProperties( width, height, bitsPerPixel,␊ |
736 | ␉␉␉␉␉␉␉␉␉␉ maColorModeBit |␊ |
737 | ␉␉␉␉␉␉␉␉␉␉ maModeIsSupportedBit |␊ |
738 | ␉␉␉␉␉␉␉␉␉␉ maGraphicsModeBit |␊ |
739 | ␉␉␉␉␉␉␉␉␉␉ maLinearFrameBufferAvailBit,␊ |
740 | ␉␉␉␉␉␉␉␉␉␉ 0,␊ |
741 | ␉␉␉␉␉␉␉␉␉␉ &minfo, &vesaVersion );␊ |
742 | if ( mode == modeEndOfList )␊ |
743 | {␊ |
744 | break;␊ |
745 | }␊ |
746 | #if UNUSED␊ |
747 | ␉␉//␊ |
748 | ␉␉// FIXME : generateCRTCTiming() causes crash.␊ |
749 | ␉␉//␊ |
750 | ␉␉␊ |
751 | ␉␉// if ( (vesaVersion >> 8) >= 3 && refreshRate >= 60 &&␊ |
752 | ␉␉// (gBootMode & kBootModeSafe) == 0 )␊ |
753 | ␉␉// {␊ |
754 | ␉␉// VBECRTCInfoBlock timing;␊ |
755 | ␉␉// ␊ |
756 | ␉␉// // Generate CRTC timing for given refresh rate.␊ |
757 | ␉␉// ␊ |
758 | ␉␉// generateCRTCTiming( minfo.XResolution, minfo.YResolution,␊ |
759 | ␉␉// refreshRate, kCRTCParamRefreshRate,␊ |
760 | ␉␉// &timing );␊ |
761 | ␉␉// ␊ |
762 | ␉␉// // Find the actual pixel clock supported by the hardware.␊ |
763 | ␉␉// ␊ |
764 | ␉␉// getVBEPixelClock( mode, &timing.PixelClock );␊ |
765 | ␉␉// ␊ |
766 | ␉␉// // Re-compute CRTC timing based on actual pixel clock.␊ |
767 | ␉␉// ␊ |
768 | ␉␉// generateCRTCTiming( minfo.XResolution, minfo.YResolution,␊ |
769 | ␉␉// timing.PixelClock, kCRTCParamPixelClock,␊ |
770 | ␉␉// &timing );␊ |
771 | ␉␉// ␊ |
772 | ␉␉// // Set the video mode and use specified CRTC timing.␊ |
773 | ␉␉// ␊ |
774 | ␉␉// err = setVBEMode( mode | kLinearFrameBufferBit |␊ |
775 | ␉␉// kCustomRefreshRateBit, &timing );␊ |
776 | ␉␉// }␊ |
777 | ␉␉// else␊ |
778 | ␉␉// {␊ |
779 | ␉␉// // Set the mode with default refresh rate.␊ |
780 | ␉␉// ␊ |
781 | ␉␉// err = setVBEMode( mode | kLinearFrameBufferBit, NULL );␊ |
782 | ␉␉// }␊ |
783 | #endif␊ |
784 | // Set the mode with default refresh rate.␊ |
785 | ␉␉␊ |
786 | err = setVBEMode( mode | kLinearFrameBufferBit, NULL );␊ |
787 | ␉␉␊ |
788 | if ( err != errSuccess )␊ |
789 | {␊ |
790 | break;␊ |
791 | }␊ |
792 | ␉␉␊ |
793 | // Set 8-bit color palette.␊ |
794 | ␉␉␊ |
795 | if ( minfo.BitsPerPixel == 8 )␊ |
796 | {␊ |
797 | VBEPalette palette;␊ |
798 | setupPalette( &palette, appleClut8 );␊ |
799 | if ((err = setVBEPalette(palette)) != errSuccess)␊ |
800 | {␊ |
801 | break;␊ |
802 | }␊ |
803 | }␊ |
804 | ␉␉␊ |
805 | // Is this required for buggy Video BIOS implementations?␊ |
806 | // On which adapter?␊ |
807 | ␉␉␊ |
808 | if ( minfo.BytesPerScanline == 0 )␊ |
809 | ␉␉␉minfo.BytesPerScanline = ( minfo.XResolution *␊ |
810 | ␉␉␉␉␉␉␉␉␉ minfo.BitsPerPixel ) >> 3;␊ |
811 | ␉␉␊ |
812 | // Update KernBootStruct using info provided by the selected␊ |
813 | // VESA mode.␊ |
814 | ␉␉␊ |
815 | Boot_Video␉Video;␉␉/* Video Information */␊ |
816 | ␉␉␊ |
817 | ␊ |
818 | Video.v_display = GRAPHICS_MODE;␊ |
819 | Video.v_width = minfo.XResolution;␊ |
820 | Video.v_height = minfo.YResolution;␊ |
821 | Video.v_depth = minfo.BitsPerPixel;␊ |
822 | Video.v_rowBytes = minfo.BytesPerScanline;␊ |
823 | Video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr);␊ |
824 | ␊ |
825 | ␊ |
826 | ␉␉setBootArgsVideoStruct(&Video);␊ |
827 | ␉␉␊ |
828 | }␊ |
829 | while ( 0 );␊ |
830 | ␉␊ |
831 | return err;␊ |
832 | }␊ |
833 | ␊ |
834 | void getGraphicModeParams(unsigned long params[]) {␊ |
835 | ␉␊ |
836 | ␉params[3] = 0;␊ |
837 | ␉␊ |
838 | ␉VBEModeInfoBlock minfo;␊ |
839 | ␉␊ |
840 | unsigned short vesaVersion;␊ |
841 | //unsigned short mode = modeEndOfList;␊ |
842 | ␉␊ |
843 | ␉getNumberArrayFromProperty( kGraphicsModeKey, params, 4);␊ |
844 | ␉␊ |
845 | ␉/* mode = */getVESAModeWithProperties( params[0], params[1], params[2],␊ |
846 | ␉␉␉␉␉␉␉␉␉␉ maColorModeBit |␊ |
847 | ␉␉␉␉␉␉␉␉␉␉ maModeIsSupportedBit |␊ |
848 | ␉␉␉␉␉␉␉␉␉␉ maGraphicsModeBit |␊ |
849 | ␉␉␉␉␉␉␉␉␉␉ maLinearFrameBufferAvailBit,␊ |
850 | ␉␉␉␉␉␉␉␉␉␉ 0,␊ |
851 | ␉␉␉␉␉␉␉␉␉␉ &minfo, &vesaVersion );␊ |
852 | ␉␊ |
853 | ␉params[0] = minfo.XResolution;␊ |
854 | ␉params[1] = minfo.YResolution;␊ |
855 | ␉params[2] = 32;␊ |
856 | }␊ |
857 | ␊ |
858 | ␊ |
859 | //==========================================================================␊ |
860 | // getVBEInfoString␊ |
861 | ␊ |
862 | char *getVBEInfoString(void)␊ |
863 | {␊ |
864 | ␉VBEInfoBlock vbeInfo;␊ |
865 | ␉int err, small;␊ |
866 | ␉char *buff = malloc(sizeof(char)*256);␊ |
867 | ␉if(!buff) return 0;␊ |
868 | ␉␊ |
869 | bzero( &vbeInfo, sizeof(VBEInfoBlock) );␊ |
870 | ␉␊ |
871 | ␉strlcpy( (char*)&vbeInfo, "VBE2", sizeof(VBEInfoBlock) );␊ |
872 | ␉err = getVBEInfo( &vbeInfo );␊ |
873 | ␉if (err != errSuccess)␊ |
874 | ␉␉goto error;␊ |
875 | ␉␊ |
876 | ␉if ( strncmp( (char *)vbeInfo.VESASignature, "VESA", 4 ) )␊ |
877 | ␉␉goto error;␊ |
878 | ␉␊ |
879 | ␉small = (vbeInfo.TotalMemory < 16);␊ |
880 | ␉␊ |
881 | ␉snprintf(buff, sizeof(char)*256,"VESA v%d.%d %d%s (%s)\n",␊ |
882 | ␉␉␉ vbeInfo.VESAVersion >> 8,␊ |
883 | ␉␉␉ vbeInfo.VESAVersion & 0xf,␊ |
884 | ␉␉␉ small ? (vbeInfo.TotalMemory * 64) : (vbeInfo.TotalMemory / 16),␊ |
885 | ␉␉␉ small ? "KB" : "MB",␊ |
886 | ␉␉␉ VBEDecodeFP(const char *, vbeInfo.OEMStringPtr) );␊ |
887 | ␉␊ |
888 | ␉return buff;␊ |
889 | error:␊ |
890 | free(buff);␊ |
891 | return 0;␊ |
892 | }␊ |
893 | ␊ |
894 | void blend( const pixmap_t *blendThis, // Source image␊ |
895 | ␉␉ pixmap_t *blendInto, // Dest image␊ |
896 | ␉␉ const position_t position) // Where to place the source image␊ |
897 | {␊ |
898 | uint16_t sx, sy, dx, dy;␊ |
899 | uint32_t dstrb, dstag, srcrb, srcag, drb, dag, rb, ag, alpha;␊ |
900 | ␉␊ |
901 | ␉uint16_t width = (blendThis->width + position.x < blendInto->width) ? blendThis->width: blendInto->width-position.x;␊ |
902 | ␉uint16_t height = (blendThis->height + position.y < blendInto->height) ? blendThis->height: blendInto->height-position.y;␊ |
903 | ␉␊ |
904 | ␉for (dy = position.y, sy = 0; sy < height; dy++, sy++) ␊ |
905 | ␉{␊ |
906 | for (dx = position.x, sx = 0; sx < width; dx++, sx++) ␊ |
907 | ␉␉{␊ |
908 | alpha = (pixel(blendThis, sx, sy).ch.a);␊ |
909 | ␉␉␉␊ |
910 | ␉␉␉/* Skip blending for fully transparent pixel */␊ |
911 | ␉␉␉if (alpha == 0) continue;␊ |
912 | ␉␉␉␊ |
913 | ␉␉␉/* For fully opaque pixel, there is no need to interpolate */␊ |
914 | ␉␉␉if (alpha == 255)␊ |
915 | ␉␉␉{␊ |
916 | ␉␉␉␉pixel(blendInto, dx, dy).value = pixel(blendThis, sx, sy).value;␊ |
917 | ␉␉␉␉continue;␊ |
918 | ␉␉␉}␊ |
919 | ␉␉␉␊ |
920 | ␉␉␉/* For semi-transparent pixels, do a full blend */␊ |
921 | ␉␉␉//alpha++␊ |
922 | ␉␉␉/* This is needed to spread the alpha over [0..256] instead of [0..255]␊ |
923 | ␉␉␉ Boundary conditions were handled above */␊ |
924 | dstrb = pixel(blendInto, dx, dy).value & 0xFF00FF;␊ |
925 | dstag = (pixel(blendInto, dx, dy).value >> 8) & 0xFF00FF;␊ |
926 | srcrb = pixel(blendThis, sx, sy).value & 0xFF00FF;␊ |
927 | srcag = (pixel(blendThis, sx, sy).value >> 8) & 0xFF00FF;␊ |
928 | drb = srcrb - dstrb;␊ |
929 | dag = srcag - dstag;␊ |
930 | drb *= alpha; dag *= alpha;␊ |
931 | drb >>= 8; dag >>= 8;␊ |
932 | rb = (drb + dstrb) & 0x00FF00FF;␊ |
933 | ag = ((dag + dstag) << 8) & 0xFF00FF00;␊ |
934 | pixel(blendInto, dx, dy).value = (rb | ag);␊ |
935 | }␊ |
936 | }␊ |
937 | }␊ |
938 | ␊ |
939 | position_t centeredIn( const pixmap_t *background, const pixmap_t *toCenter )␊ |
940 | {␊ |
941 | position_t centered;␊ |
942 | centered.x = ( background->width - toCenter->width ) / 2;␊ |
943 | centered.y = ( background->height - toCenter->height ) / 2;␊ |
944 | return centered;␊ |
945 | }␊ |
946 | ␊ |
947 | position_t centeredAt( const pixmap_t *pixmap, const position_t center )␊ |
948 | {␊ |
949 | position_t topleft;␊ |
950 | topleft.x = center.x - (pixmap->width / 2);␊ |
951 | topleft.y = center.y - (pixmap->height / 2);␊ |
952 | return topleft;␊ |
953 | }␊ |
954 | ␊ |
955 | position_t pos(const uint16_t x, const uint16_t y) { position_t p; p.x = x; p.y = y; return p; }␊ |
956 | ␊ |
957 | void flipRB(pixmap_t *p)␊ |
958 | {␊ |
959 | ␉//if(testForQemu()) return;␊ |
960 | ␉␊ |
961 | ␉uint32_t x;␊ |
962 | register uint8_t tempB;␊ |
963 | ␉for (x = 0; x < (unsigned long)(p->height) * (p->width) ; x++) {␊ |
964 | ␉␉tempB = (p->pixels[x]).ch.b;␊ |
965 | (p->pixels[x]).ch.b = (p->pixels[x]).ch.r;␊ |
966 | (p->pixels[x]).ch.r = tempB;␊ |
967 | ␉}␊ |
968 | }␊ |
969 | |