Chameleon

Chameleon Svn Source Tree

Root/branches/Bungo/i386/boot2/graphics.c

1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Copyright 1993 NeXT, Inc.
26 * All rights reserved.
27 */
28
29#include "boot.h"
30#include "vbe.h"
31#include "appleClut8.h"
32#include "gui.h"
33#include "IOHibernatePrivate.h"
34
35/*
36 * for spinning disk
37 */
38static int currentIndicator = 0;
39
40int previewTotalSectors = 0;
41int previewLoadedSectors = 0;
42uint8_t *previewSaveunder = 0;
43
44#define VIDEO(x) (bootArgs->Video.v_ ## x)
45
46//==========================================================================
47// getVBEVideoRam
48
49uint32_t getVBEVideoRam()
50{
51VBEInfoBlock vbeInfo;
52int err, small;
53
54bzero( &vbeInfo, sizeof(vbeInfo) );
55strcpy( (char*)&vbeInfo, "VBE2" );
56err = getVBEInfo( &vbeInfo );
57if (err != errSuccess)
58return 0;
59
60if ( strncmp( (char *)vbeInfo.VESASignature, "VESA", 4 ) )
61return 0;
62
63small = (vbeInfo.TotalMemory < 16);
64
65return vbeInfo.TotalMemory * 64 * 1024;
66}
67
68//==========================================================================
69// getVBEInfoString
70
71char *getVBEInfoString()
72{
73VBEInfoBlock vbeInfo;
74int err, small;
75char* buff = NULL;
76
77bzero( &vbeInfo, sizeof(vbeInfo) );
78strcpy( (char*)&vbeInfo, "VBE2" );
79err = getVBEInfo( &vbeInfo );
80if (err != errSuccess)
81return 0;
82
83if ( strncmp( (char *)vbeInfo.VESASignature, "VESA", 4 ) )
84return 0;
85
86buff = malloc(sizeof(char) * 256);
87if (!buff) {
88return 0;
89}
90small = (vbeInfo.TotalMemory < 16);
91
92snprintf(buff, 256,
93 "VESA v%d.%d %d%s (%s)\n",
94 vbeInfo.VESAVersion >> 8,
95 vbeInfo.VESAVersion & 0xf,
96 small ? (vbeInfo.TotalMemory * 64) : (vbeInfo.TotalMemory / 16),
97 small ? "KB" : "MB",
98 VBEDecodeFP(const char *, vbeInfo.OEMStringPtr) );
99
100return buff;
101}
102
103//==========================================================================
104//
105
106void
107printVBEModeInfo()
108{
109VBEInfoBlock vbeInfo;
110unsigned short * modePtr;
111VBEModeInfoBlock modeInfo;
112int err;
113int line;
114char* vbeInfoString = NULL;
115
116 bzero( &vbeInfo, sizeof(vbeInfo) );
117strcpy( (char*)&vbeInfo, "VBE2" );
118err = getVBEInfo( &vbeInfo );
119if ( err != errSuccess ) {
120return;
121}
122
123line = 0;
124
125// Activate and clear page 1
126setActiveDisplayPage(1);
127clearScreenRows(0, 24);
128setCursorPosition( 0, 0, 1 );
129
130vbeInfoString = getVBEInfoString();
131if (!vbeInfoString) {
132printf("Error: getVBEInfoString failed\n");
133return;
134}
135printf("%s", vbeInfoString);
136free(vbeInfoString);
137vbeInfoString = NULL;
138
139printf("Video modes supported:\n", VBEDecodeFP(const char *, vbeInfo.OEMStringPtr));
140
141// Loop through the mode list, and find the matching mode.
142
143for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
144 *modePtr != modeEndOfList; modePtr++ )
145{
146// Get mode information.
147
148bzero( &modeInfo, sizeof(modeInfo) );
149err = getVBEModeInfo( *modePtr, &modeInfo );
150if ( err != errSuccess )
151{
152continue;
153}
154
155printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
156*modePtr, modeInfo.XResolution, modeInfo.YResolution,
157modeInfo.BitsPerPixel, modeInfo.MemoryModel,
158modeInfo.ModeAttributes);
159
160if (line++ >= 20) {
161pause();
162line = 0;
163clearScreenRows(0, 24);
164setCursorPosition( 0, 0, 1 );
165}
166}
167if (line != 0) {
168pause();
169}
170setActiveDisplayPage(0);
171}
172
173char *getVBEModeInfoString()
174{
175VBEInfoBlock vbeInfo;
176unsigned short * modePtr;
177VBEModeInfoBlock modeInfo;
178int err;
179
180 bzero( &vbeInfo, sizeof(vbeInfo) );
181strcpy( (char*)&vbeInfo, "VBE2" );
182err = getVBEInfo( &vbeInfo );
183if ( err != errSuccess ) {
184return 0;
185}
186char *buff=malloc(sizeof(char)*3072);
187if(!buff) {
188return 0;
189}
190
191int bufflen = 0;
192
193// Loop through the mode list, and find the matching mode.
194for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
195(*modePtr != modeEndOfList) && (bufflen < 3072); /* prevent buffer overrun */
196modePtr++ )
197{
198// Get mode information.
199
200bzero( &modeInfo, sizeof(modeInfo) );
201err = getVBEModeInfo( *modePtr, &modeInfo );
202if ( err != errSuccess ) {
203continue;
204}
205
206bufflen +=
207snprintf(buff+bufflen, 3072-bufflen, "Mode %x: %dx%dx%d mm:%d attr:%x\n",
208*modePtr, modeInfo.XResolution, modeInfo.YResolution,
209modeInfo.BitsPerPixel, modeInfo.MemoryModel,
210modeInfo.ModeAttributes);
211}
212return buff;
213}
214
215//==========================================================================
216// getVESAModeWithProperties
217//
218// Return the VESA mode that matches the properties specified.
219// If a mode is not found, then return the "best" available mode.
220
221static unsigned short
222getVESAModeWithProperties( unsigned short width,
223 unsigned short height,
224 unsigned char bitsPerPixel,
225 unsigned short attributesSet,
226 unsigned short attributesClear,
227 VBEModeInfoBlock * outModeInfo,
228 unsigned short * vesaVersion )
229{
230 VBEInfoBlock vbeInfo;
231 unsigned short * modePtr;
232 VBEModeInfoBlock modeInfo;
233 unsigned char modeBitsPerPixel;
234 unsigned short matchedMode = modeEndOfList;
235 int err;
236
237 // Clear output mode info.
238
239 bzero( outModeInfo, sizeof(*outModeInfo) );
240
241 // Get VBE controller info containing the list of supported modes.
242
243 bzero( &vbeInfo, sizeof(vbeInfo) );
244 strcpy( (char*)&vbeInfo, "VBE2" );
245 err = getVBEInfo( &vbeInfo );
246 if ( err != errSuccess )
247 {
248 return modeEndOfList;
249 }
250
251 // Report the VESA major/minor version number.
252
253 if (vesaVersion) *vesaVersion = vbeInfo.VESAVersion;
254
255 // Loop through the mode list, and find the matching mode.
256
257 for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
258 *modePtr != modeEndOfList; modePtr++ )
259 {
260 // Get mode information.
261
262 bzero( &modeInfo, sizeof(modeInfo) );
263 err = getVBEModeInfo( *modePtr, &modeInfo );
264 if ( err != errSuccess )
265 {
266 continue;
267 }
268
269#if DEBUG
270 printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
271 *modePtr, modeInfo.XResolution, modeInfo.YResolution,
272 modeInfo.BitsPerPixel, modeInfo.MemoryModel,
273 modeInfo.ModeAttributes);
274#endif
275
276 // Filter out unwanted modes based on mode attributes.
277
278 if ( ( ( modeInfo.ModeAttributes & attributesSet ) != attributesSet )
279 || ( ( modeInfo.ModeAttributes & attributesClear ) != 0 ) )
280 {
281 continue;
282 }
283
284 // Pixel depth in bits.
285
286 modeBitsPerPixel = modeInfo.BitsPerPixel;
287
288 if ( ( modeBitsPerPixel == 4 ) && ( modeInfo.MemoryModel == 0 ) )
289 {
290 // Text mode, 16 colors.
291 }
292 else if ( ( modeBitsPerPixel == 8 ) && ( modeInfo.MemoryModel == 4 ) )
293 {
294 // Packed pixel, 256 colors.
295 }
296 else if ( ( ( modeBitsPerPixel == 16 ) || ( modeBitsPerPixel == 15 ) )
297 && ( modeInfo.MemoryModel == 6 )
298 && ( modeInfo.RedMaskSize == 5 )
299 && ( modeInfo.GreenMaskSize == 5 )
300 && ( modeInfo.BlueMaskSize == 5 ) )
301 {
302 // Direct color, 16 bpp (1:5:5:5).
303 modeInfo.BitsPerPixel = modeBitsPerPixel = 16;
304 }
305 else if ( ( modeBitsPerPixel == 32 )
306 && ( modeInfo.MemoryModel == 6 )
307 && ( modeInfo.RedMaskSize == 8 )
308 && ( modeInfo.GreenMaskSize == 8 )
309 && ( modeInfo.BlueMaskSize == 8 ) )
310 {
311 // Direct color, 32 bpp (8:8:8:8).
312 }
313 else
314 {
315 continue; // Not a supported mode.
316 }
317
318 // Modes larger than the specified dimensions are skipped.
319
320 if ( ( modeInfo.XResolution > width ) ||
321 ( modeInfo.YResolution > height ) )
322 {
323 continue;
324 }
325
326 // Perfect match, we're done looking.
327
328 if ( ( modeInfo.XResolution == width ) &&
329 ( modeInfo.YResolution == height ) &&
330 ( modeBitsPerPixel == bitsPerPixel ) )
331 {
332 matchedMode = *modePtr;
333 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
334 break;
335 }
336
337 // Save the next "best" mode in case a perfect match is not found.
338
339 if ( modeInfo.XResolution == outModeInfo->XResolution &&
340 modeInfo.YResolution == outModeInfo->YResolution &&
341 modeBitsPerPixel <= outModeInfo->BitsPerPixel )
342 {
343 continue; // Saved mode has more depth.
344 }
345 if ( modeInfo.XResolution < outModeInfo->XResolution ||
346 modeInfo.YResolution < outModeInfo->YResolution ||
347 modeBitsPerPixel < outModeInfo->BitsPerPixel )
348 {
349 continue; // Saved mode has more resolution.
350 }
351
352 matchedMode = *modePtr;
353 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
354 }
355
356 return matchedMode;
357}
358
359//==========================================================================
360// setupPalette
361
362static void setupPalette( VBEPalette * p, const unsigned char * g )
363{
364 int i;
365 unsigned char * source = (unsigned char *) g;
366
367 for (i = 0; i < 256; i++)
368 {
369 (*p)[i] = 0;
370 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red
371 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green
372 (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue
373 }
374}
375
376//==========================================================================
377// Simple decompressor for boot images encoded in RLE format.
378
379char * decodeRLE( const void * rleData, int rleBlocks, int outBytes )
380{
381 char *out, *cp;
382
383 struct RLEBlock {
384 unsigned char count;
385 unsigned char value;
386 } * bp = (struct RLEBlock *) rleData;
387
388 out = cp = malloc( outBytes );
389 if ( out == NULL ) return NULL;
390
391 while ( rleBlocks-- )
392 {
393 memset( cp, bp->value, bp->count );
394 cp += bp->count;
395 bp++;
396 }
397
398 return out;
399}
400
401//==========================================================================
402// setVESAGraphicsMode
403
404static int
405setVESAGraphicsMode( unsigned short width,
406 unsigned short height,
407 unsigned char bitsPerPixel,
408 unsigned short refreshRate )
409{
410 VBEModeInfoBlock minfo;
411 unsigned short mode;
412 unsigned short vesaVersion;
413 int err = errFuncNotSupported;
414
415 do {
416 mode = getVESAModeWithProperties( width, height, bitsPerPixel,
417 maColorModeBit |
418 maModeIsSupportedBit |
419 maGraphicsModeBit |
420 maLinearFrameBufferAvailBit,
421 0,
422 &minfo, &vesaVersion );
423 if ( mode == modeEndOfList )
424 {
425 break;
426 }
427
428//
429// FIXME : generateCRTCTiming() causes crash.
430//
431
432// if ( (vesaVersion >> 8) >= 3 && refreshRate >= 60 &&
433// (gBootMode & kBootModeSafe) == 0 )
434// {
435// VBECRTCInfoBlock timing;
436//
437// // Generate CRTC timing for given refresh rate.
438//
439// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
440// refreshRate, kCRTCParamRefreshRate,
441// &timing );
442//
443// // Find the actual pixel clock supported by the hardware.
444//
445// getVBEPixelClock( mode, &timing.PixelClock );
446//
447// // Re-compute CRTC timing based on actual pixel clock.
448//
449// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
450// timing.PixelClock, kCRTCParamPixelClock,
451// &timing );
452//
453// // Set the video mode and use specified CRTC timing.
454//
455// err = setVBEMode( mode | kLinearFrameBufferBit |
456// kCustomRefreshRateBit, &timing );
457// }
458// else
459// {
460// // Set the mode with default refresh rate.
461//
462// err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
463// }
464
465 // Set the mode with default refresh rate.
466
467 err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
468
469 if ( err != errSuccess )
470 {
471 break;
472 }
473
474 // Set 8-bit color palette.
475
476 if ( minfo.BitsPerPixel == 8 )
477 {
478 VBEPalette palette;
479 setupPalette( &palette, appleClut8 );
480 if ((err = setVBEPalette(palette)) != errSuccess)
481 {
482 break;
483 }
484 }
485
486 // Is this required for buggy Video BIOS implementations?
487 // On which adapter?
488
489 if ( minfo.BytesPerScanline == 0 )
490 minfo.BytesPerScanline = ( minfo.XResolution *
491 minfo.BitsPerPixel ) >> 3;
492
493 // Update KernBootStruct using info provided by the selected
494 // VESA mode.
495
496 bootArgs->Video.v_display = GRAPHICS_MODE;
497 bootArgs->Video.v_width = minfo.XResolution;
498 bootArgs->Video.v_height = minfo.YResolution;
499 bootArgs->Video.v_depth = minfo.BitsPerPixel;
500 bootArgs->Video.v_rowBytes = minfo.BytesPerScanline;
501 bootArgs->Video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr);
502
503 }
504 while ( 0 );
505
506 return err;
507}
508
509int
510convertImage( unsigned short width,
511 unsigned short height,
512 const unsigned char *imageData,
513 unsigned char **newImageData )
514{
515 int cnt;
516 unsigned char *img = 0;
517 unsigned short *img16;
518 unsigned long *img32;
519
520 switch ( VIDEO(depth) ) {
521 case 16 :
522 img16 = malloc(width * height * 2);
523 if ( !img16 ) break;
524 for (cnt = 0; cnt < (width * height); cnt++)
525 img16[cnt] = lookUpCLUTIndex(imageData[cnt], 16);
526 img = (unsigned char *)img16;
527 break;
528
529 case 32 :
530 img32 = malloc(width * height * 4);
531 if ( !img32 ) break;
532 for (cnt = 0; cnt < (width * height); cnt++)
533 img32[cnt] = lookUpCLUTIndex(imageData[cnt], 32);
534 img = (unsigned char *)img32;
535 break;
536
537 default :
538 img = malloc(width * height);
539 bcopy(imageData, img, width * height);
540 break;
541 }
542 *newImageData = img;
543 return 0;
544}
545
546int loadPngImage(const char *filename, uint16_t *width, uint16_t *height,
547 uint8_t **imageData)
548{
549 uint8_t *pngData = NULL;
550 int pngFile = 0, pngSize;
551 PNG_info_t *info;
552 int error = 0;
553
554 pngFile = open_bvdev("bt(0,0)", filename, 0);
555 if (pngFile == -1) {
556 error = -1;
557 goto failed;
558 }
559 pngSize = file_size(pngFile);
560 if (!pngSize) {
561 error = -1;
562 goto failed;
563 }
564 pngData = malloc(pngSize);
565 if (read(pngFile, (char *) pngData, pngSize) != pngSize) {
566 error = -1;
567 goto failed;
568 }
569
570 PNG_error = -1;
571 info = PNG_decode(pngData, pngSize);
572 if (PNG_error != 0) {
573 error = PNG_error;
574 goto failed;
575 } else if ((info->width > 0xffff) || (info->height > 0xffff)) {
576 error = -1;
577 goto failed;
578 } else if ((info->width * info->height * 4) != info->image->size) {
579 error = -1;
580 goto failed;
581 }
582uint8_t *result = malloc(info->width*4*info->height);
583 *width = info->width;
584 *height = info->height;
585memcpy(result, info->image->data, info->width*4*info->height);
586*imageData = result;
587
588failed:
589png_alloc_free_all();
590 if (pngData)
591 free(pngData);
592 if (pngFile != -1)
593 close(pngFile);
594
595 return error;
596}
597
598int loadEmbeddedPngImage(uint8_t *pngData, int pngSize, uint16_t *width, uint16_t *height, uint8_t **imageData) {
599 PNG_info_t *info;
600 int error = 0;
601
602 PNG_error = -1;
603 info = PNG_decode(pngData, pngSize);
604if (PNG_error != 0) {
605 error = PNG_error;
606 goto failed;
607 } else if ((info->width > 0xffff) || (info->height > 0xffff)) {
608 error = -1;
609 goto failed;
610 } else if ((info->width * info->height * 4) != info->image->size) {
611 error = -1;
612 goto failed;
613 }
614uint8_t *result = malloc(info->width*4*info->height);
615*width = info->width;
616 *height = info->height;
617memcpy(result, info->image->data, info->width*4*info->height);
618*imageData = result;
619
620failed:
621png_alloc_free_all();
622
623 return error;
624}
625
626void blendImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height,
627 uint8_t *data)
628{
629 uint16_t drawWidth;
630 uint8_t *vram = (uint8_t *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + 4 * x;
631
632 drawWidth = MIN(width, VIDEO(width) - x);
633 height = MIN(height, VIDEO(height) - y);
634 while (height--) {
635switch (VIDEO (depth))
636{
637case 32: /* Optimized version*/
638{
639uint32_t s; uint32_t* d; // Source (img) and destination (bkgd) pixels
640uint32_t a; // Alpha
641uint32_t dstrb, dstg, srcrb, srcg, drb, dg, rb, g, tempB; // Intermediate variables
642uint16_t pos;
643
644for (pos = 0; pos < drawWidth * 4; pos += 4) {
645// Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html
646s = *((uint32_t*) (data + pos));
647d = (uint32_t*) (vram + pos);
648
649// Flip B and R in source
650// TODO: use XCHG and inline assembly to do this in a faster, saner way
651tempB = (s & 0xFF0000); // save B
652s = (s & 0xFF00FFFF) | ((s & 0xFF) << 16); // put R in B
653s = (s & 0xFFFFFF00) | (tempB >> 16); // put B in R
654
655a = (s >> 24) + 1;
656
657dstrb = *d & 0xFF00FF; dstg = *d & 0xFF00;
658srcrb = s & 0xFF00FF; srcg = s & 0xFF00;
659
660drb = srcrb - dstrb;
661dg = srcg - dstg;
662drb *= a; dg *= a;
663drb >>= 8; dg >>= 8;
664
665rb = (drb + dstrb) & 0xFF00FF;
666g = (dg + dstg) & 0xFF00;
667
668*d = rb | g;
669}
670}
671break;
672
673default: /*Universal version*/
674{
675uint32_t s;
676uint32_t a; // Alpha
677uint32_t dr, dg, db, sr, sg, sb; // Intermediate variables
678uint16_t pos;
679int bpp = (VIDEO (depth) + 7)/8;
680
681for (pos = 0; pos < drawWidth; pos ++) {
682// Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html
683s = *((uint32_t*) (data + 4*pos));
684
685sb = (s & 0xFF0000) >> 16;
686sg = (s & 0xFF00) >> 8;
687sr = (s & 0xFF);
688
689a = (s >> 24) + 1;
690
691switch (VIDEO (depth))
692{
693case 24:
694db = ((*(uint32_t *)(vram + bpp*pos))&0xff);
695dg = ((*(uint32_t *)(vram + bpp*pos))&0xff00)>>8;
696dr = ((*(uint32_t *)(vram + bpp*pos))&0xff0000)>>16;
697break;
698case 16://16-bit seems to be 15-bit
699/*db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3;
700dg = ((*(uint16_t *)(vram + bpp*pos))&0x07e0)>>3;
701dr = ((*(uint16_t *)(vram + bpp*pos))&0xf800)>>8;
702break;*/
703case 15:
704db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3;
705dg = ((*(uint16_t *)(vram + bpp*pos))&0x03e0)>>2;
706dr = ((*(uint16_t *)(vram + bpp*pos))&0x7c00)>>7;
707break;
708default:
709return;
710}
711
712dr = (((sr - dr) * a) >> 8) + dr;
713dg = (((sg - dg) * a) >> 8) + dg;
714db = (((sb - db) * a) >> 8) + db;
715switch (VIDEO (depth))
716{
717case 24:
718*(uint32_t *)(vram + bpp*pos) = (*(uint32_t *)(vram + bpp*pos) &0xff000000)
719| (db&0xff) | ((dg&0xff)<<8) | ((dr&0xff)<<16);
720break;
721case 16:
722//*(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xfc)<<3) | ((dr&0xf8)<<8);
723//break;
724case 15:
725*(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xf8)<<2) | ((dr&0xf8)<<7);
726break;
727}
728
729}
730}
731break;
732 }
733 vram += VIDEO(rowBytes);
734 data += width * 4;
735 }
736}
737
738void drawCheckerBoard()
739{
740 uint32_t *vram = (uint32_t *) VIDEO(baseAddr);
741 uint16_t x, y;
742 uint8_t color;
743
744 for (y = 0; y < VIDEO(height); y++, vram += VIDEO(width)) {
745 for (x = 0; x < VIDEO(width); x++) {
746 color = 204 + 51 * (((x / 8) % 2) == ((y / 8) % 2));
747 vram[x] = (color << 16) | (color << 8) | color;
748 }
749 }
750}
751
752//==========================================================================
753// LookUpCLUTIndex
754
755unsigned long lookUpCLUTIndex( unsigned char index,
756 unsigned char depth )
757{
758 long result, red, green, blue;
759
760 red = appleClut8[index * 3 + 0];
761 green = appleClut8[index * 3 + 1];
762 blue = appleClut8[index * 3 + 2];
763
764 switch (depth) {
765 case 16 :
766 result = ((red & 0xF8) << 7) |
767 ((green & 0xF8) << 2) |
768 ((blue & 0xF8) >> 3);
769 result |= (result << 16);
770 break;
771
772 case 32 :
773 result = (red << 16) | (green << 8) | blue;
774 break;
775
776 default :
777 result = index | (index << 8);
778 result |= (result << 16);
779 break;
780 }
781
782 return result;
783}
784
785//==========================================================================
786// drawColorRectangle
787
788void * stosl(void * dst, long val, long len)
789{
790 asm volatile ( "rep; stosl"
791 : "=c" (len), "=D" (dst)
792 : "0" (len), "1" (dst), "a" (val)
793 : "memory" );
794
795 return dst;
796}
797
798void drawColorRectangle( unsigned short x,
799 unsigned short y,
800 unsigned short width,
801 unsigned short height,
802 unsigned char colorIndex )
803{
804 long pixelBytes;
805 long color = lookUpCLUTIndex( colorIndex, VIDEO(depth) );
806 char * vram;
807
808 pixelBytes = VIDEO(depth) / 8;
809 vram = (char *) VIDEO(baseAddr) +
810 VIDEO(rowBytes) * y + pixelBytes * x;
811
812 width = MIN(width, VIDEO(width) - x);
813 height = MIN(height, VIDEO(height) - y);
814
815 while ( height-- )
816 {
817 int rem = ( pixelBytes * width ) % 4;
818 if ( rem ) bcopy( &color, vram, rem );
819 stosl( vram + rem, color, pixelBytes * width / 4 );
820 vram += VIDEO(rowBytes);
821 }
822}
823
824//==========================================================================
825// drawDataRectangle
826
827void drawDataRectangle( unsigned short x,
828 unsigned short y,
829 unsigned short width,
830 unsigned short height,
831 unsigned char * data )
832{
833 unsigned short drawWidth;
834 long pixelBytes = VIDEO(depth) / 8;
835 unsigned char * vram = (unsigned char *) VIDEO(baseAddr) +
836 VIDEO(rowBytes) * y + pixelBytes * x;
837
838 drawWidth = MIN(width, VIDEO(width) - x);
839 height = MIN(height, VIDEO(height) - y);
840 while ( height-- ) {
841 bcopy( data, vram, drawWidth * pixelBytes );
842 vram += VIDEO(rowBytes);
843 data += width * pixelBytes;
844 }
845}
846
847void
848loadImageScale (void *input, int iw, int ih, int ip, void *output, int ow, int oh, int op, int or)
849{
850int x,y, off;
851int red=0x7f, green=0x7f, blue=0x7f;
852for (x=0;x<ow;x++)
853for (y=0;y<oh;y++)
854{
855off=(x*iw)/ow+((y*ih)/oh)*iw;
856switch (ip)
857{
858case 16:
859{
860uint16_t val;
861val=((uint16_t *)input)[off];
862red=(val>>7)&0xf8;
863green=(val>>2)&0xf8;
864blue=(val<<3)&0xf8;
865break;
866}
867case 32:
868{
869uint32_t val;
870val=((uint32_t *)input)[off];
871red=(val>>16)&0xff;
872green=(val>>8)&0xff;
873blue=(val)&0xff;
874break;
875}
876}
877char *ptr=(char *)output+x*(op/8)+y*or;
878switch (op)
879{
880case 16:
881*((uint16_t *)ptr) = ((red & 0xF8) << 7) |
882((green & 0xF8) << 2) |
883((blue & 0xF8) >> 3);
884break;
885case 32 :
886*((uint32_t *)ptr) = (red << 16) | (green << 8) | blue;
887break;
888}
889}
890}
891
892DECLARE_IOHIBERNATEPROGRESSALPHA
893
894void drawPreview(void *src, uint8_t * saveunder)
895{
896uint8_t * screen;
897uint32_t rowBytes, pixelShift;
898uint32_t x, y;
899int32_t blob;
900uint32_t alpha, in, color, result;
901uint8_t * out;
902void *uncomp;
903int origwidth, origheight, origbpx;
904uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
905
906if (src && (uncomp=DecompressData(src, &origwidth, &origheight, &origbpx)))
907{
908if (!setVESAGraphicsMode(origwidth, origheight, origbpx, 0))
909if (initGraphicsMode () != errSuccess)
910return;
911screen = (uint8_t *) VIDEO (baseAddr);
912rowBytes = VIDEO (rowBytes);
913loadImageScale (uncomp, origwidth, origheight, origbpx, screen, VIDEO(width), VIDEO(height), VIDEO(depth), VIDEO (rowBytes));
914}
915else
916{
917if (initGraphicsMode () != errSuccess)
918return;
919screen = (uint8_t *) VIDEO (baseAddr);
920rowBytes = VIDEO (rowBytes);
921// Set the screen to 75% grey.
922 drawColorRectangle(0, 0, VIDEO(width), VIDEO(height), 0x01 /* color index */);
923}
924
925
926pixelShift = VIDEO (depth) >> 4;
927if (pixelShift < 1) return;
928
929screen += ((VIDEO (width)
930- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
931+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
932
933for (y = 0; y < kIOHibernateProgressHeight; y++)
934{
935out = screen + y * rowBytes;
936for (blob = 0; blob < kIOHibernateProgressCount; blob++)
937{
938color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
939for (x = 0; x < kIOHibernateProgressWidth; x++)
940{
941alpha = gIOHibernateProgressAlpha[y][x];
942result = color;
943if (alpha)
944{
945if (0xff != alpha)
946{
947if (1 == pixelShift)
948{
949in = *((uint16_t *)out) & 0x1f;// 16
950in = (in << 3) | (in >> 2);
951}
952else
953in = *((uint32_t *)out) & 0xff;// 32
954saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
955result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
956}
957if (1 == pixelShift)
958{
959result >>= 3;
960*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
961}
962else
963*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
964}
965out += (1 << pixelShift);
966}
967out += (kIOHibernateProgressSpacing << pixelShift);
968}
969}
970}
971
972void updateProgressBar(uint8_t * saveunder, int32_t firstBlob, int32_t select)
973{
974uint8_t * screen;
975uint32_t rowBytes, pixelShift;
976uint32_t x, y;
977int32_t blob, lastBlob;
978uint32_t alpha, in, color, result;
979uint8_t * out;
980uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
981
982pixelShift = VIDEO(depth) >> 4;
983if (pixelShift < 1) return;
984screen = (uint8_t *) VIDEO (baseAddr);
985rowBytes = VIDEO (rowBytes);
986
987screen += ((VIDEO (width)
988- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
989+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
990
991lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
992
993screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
994
995for (y = 0; y < kIOHibernateProgressHeight; y++)
996{
997out = screen + y * rowBytes;
998for (blob = firstBlob; blob <= lastBlob; blob++)
999{
1000color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
1001for (x = 0; x < kIOHibernateProgressWidth; x++)
1002{
1003alpha = gIOHibernateProgressAlpha[y][x];
1004result = color;
1005if (alpha)
1006{
1007if (0xff != alpha)
1008{
1009in = saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++];
1010result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
1011}
1012if (1 == pixelShift)
1013{
1014result >>= 3;
1015*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
1016}
1017else
1018*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
1019}
1020out += (1 << pixelShift);
1021}
1022out += (kIOHibernateProgressSpacing << pixelShift);
1023}
1024}
1025}
1026
1027
1028//==========================================================================
1029// setVESATextMode
1030
1031static int
1032setVESATextMode( unsigned short cols,
1033 unsigned short rows,
1034 unsigned char bitsPerPixel )
1035{
1036 VBEModeInfoBlock minfo;
1037 unsigned short mode = modeEndOfList;
1038
1039 if ( (cols != 80) || (rows != 25) ) // not 80x25 mode
1040 {
1041 mode = getVESAModeWithProperties( cols, rows, bitsPerPixel,
1042 maColorModeBit |
1043 maModeIsSupportedBit,
1044 maGraphicsModeBit,
1045 &minfo, NULL );
1046 }
1047
1048 if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) )
1049 {
1050 video_mode( 2 ); // VGA BIOS, 80x25 text mode.
1051 minfo.XResolution = 80;
1052 minfo.YResolution = 25;
1053 }
1054
1055 // Update KernBootStruct using info provided by the selected
1056 // VESA mode.
1057
1058 bootArgs->Video.v_display = VGA_TEXT_MODE;
1059 bootArgs->Video.v_baseAddr = 0xb8000;
1060 bootArgs->Video.v_width = minfo.XResolution;
1061 bootArgs->Video.v_height = minfo.YResolution;
1062 bootArgs->Video.v_depth = 8;
1063 bootArgs->Video.v_rowBytes = 0x8000;
1064
1065 return errSuccess; // always return success
1066}
1067
1068//==========================================================================
1069// getNumberArrayFromProperty
1070
1071static int
1072getNumberArrayFromProperty( const char * propKey,
1073 unsigned long numbers[],
1074 unsigned long maxArrayCount )
1075{
1076 char * propStr;
1077 unsigned long count = 0;
1078
1079 propStr = newStringForKey( (char *) propKey , &bootInfo->chameleonConfig );
1080 if ( propStr )
1081 {
1082 char * delimiter = propStr;
1083 char * p = propStr;
1084
1085 while ( count < maxArrayCount && *p != '\0' )
1086 {
1087 unsigned long val = strtoul( p, &delimiter, 10 );
1088 if ( p != delimiter )
1089 {
1090 numbers[count++] = val;
1091 p = delimiter;
1092 }
1093 while ( ( *p != '\0' ) && !isdigit(*p) )
1094 p++;
1095 }
1096
1097 free( propStr );
1098 }
1099
1100 return count;
1101}
1102
1103int initGraphicsMode ()
1104{
1105 unsigned long params[4];
1106 int count;
1107
1108 params[3] = 0;
1109 count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 );
1110
1111 // Try to find a resolution if "Graphics Mode" setting is not available.
1112 if ( count < 3 )
1113 {
1114 // Use the default resolution if we don't have an initialized GUI.
1115 if (gui.screen.width == 0 || gui.screen.height == 0)
1116 {
1117 gui.screen.width = DEFAULT_SCREEN_WIDTH;
1118 gui.screen.height = DEFAULT_SCREEN_HEIGHT;
1119 }
1120
1121 params[0] = gui.screen.width;
1122 params[1] = gui.screen.height;
1123 params[2] = 32;
1124 }
1125
1126 // Map from pixel format to bits per pixel.
1127
1128 if ( params[2] == 256 ) params[2] = 8;
1129 if ( params[2] == 555 ) params[2] = 16;
1130 if ( params[2] == 888 ) params[2] = 32;
1131
1132return setVESAGraphicsMode( params[0], params[1], params[2], params[3] );
1133}
1134
1135//==========================================================================
1136// setVideoMode
1137//
1138// Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE.
1139
1140void
1141setVideoMode( int mode, int drawgraphics)
1142{
1143 unsigned long params[4];
1144 int count;
1145 int err = errSuccess;
1146
1147 if ( mode == GRAPHICS_MODE )
1148 {
1149 if ( (err=initGraphicsMode ()) == errSuccess ) {
1150 if (gVerboseMode) {
1151 // Tell the kernel to use text mode on a linear frame buffer display
1152 bootArgs->Video.v_display = FB_TEXT_MODE;
1153 } else {
1154 bootArgs->Video.v_display = GRAPHICS_MODE;
1155 }
1156 }
1157 }
1158
1159 if ( (mode == VGA_TEXT_MODE) || (err != errSuccess) )
1160 {
1161 count = getNumberArrayFromProperty( kTextModeKey, params, 2 );
1162 if ( count < 2 )
1163 {
1164 params[0] = 80; // Default text mode is 80x25.
1165 params[1] = 25;
1166 }
1167
1168setVESATextMode( params[0], params[1], 4 );
1169 bootArgs->Video.v_display = VGA_TEXT_MODE;
1170 }
1171
1172 currentIndicator = 0;
1173}
1174
1175void getGraphicModeParams(unsigned long params[]) {
1176
1177params[3] = 0;
1178
1179VBEModeInfoBlock minfo;
1180
1181 unsigned short vesaVersion;
1182 unsigned short mode = modeEndOfList;
1183
1184getNumberArrayFromProperty( kGraphicsModeKey, params, 4);
1185
1186mode = getVESAModeWithProperties( params[0], params[1], params[2],
1187 maColorModeBit |
1188 maModeIsSupportedBit |
1189 maGraphicsModeBit |
1190 maLinearFrameBufferAvailBit,
1191 0,
1192 &minfo, &vesaVersion );
1193
1194params[0] = minfo.XResolution;
1195params[1] = minfo.YResolution;
1196params[2] = 32;
1197}
1198
1199//==========================================================================
1200// Return the current video mode, VGA_TEXT_MODE or GRAPHICS_MODE.
1201
1202int getVideoMode(void)
1203{
1204 return bootArgs->Video.v_display;
1205}
1206
1207//==========================================================================
1208// Display and clear the activity indicator.
1209
1210static char indicator[] = {'-', '\\', '|', '/', '-', '\\', '|', '/', '\0'};
1211
1212// To prevent a ridiculously fast-spinning indicator,
1213// ensure a minimum of 1/9 sec between animation frames.
1214#define MIN_TICKS 2
1215
1216void
1217spinActivityIndicator(int sectors)
1218{
1219 static unsigned long lastTickTime = 0, currentTickTime;
1220
1221if (previewTotalSectors && previewSaveunder)
1222{
1223int blob, lastBlob;
1224
1225lastBlob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
1226previewLoadedSectors+=sectors;
1227blob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
1228
1229if (blob!=lastBlob)
1230updateProgressBar (previewSaveunder, lastBlob, blob);
1231return;
1232}
1233
1234currentTickTime = time18(); // late binding
1235if (currentTickTime < lastTickTime + MIN_TICKS)
1236{
1237return;
1238}
1239else
1240{
1241lastTickTime = currentTickTime;
1242}
1243
1244if (getVideoMode() == VGA_TEXT_MODE)
1245{
1246if (currentIndicator >= sizeof(indicator))
1247{
1248currentIndicator = 0;
1249}
1250putchar(indicator[currentIndicator++]);
1251putchar('\b');
1252}
1253}
1254
1255void
1256clearActivityIndicator( void )
1257{
1258 if ( getVideoMode() == VGA_TEXT_MODE )
1259 {
1260putchar(' ');
1261putchar('\b');
1262 }
1263}
1264
1265

Archive Download this file

Revision: 2340