Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2738