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) );
282err = getVBEModeInfo( *modePtr, &modeInfo );
283if ( err != errSuccess )
284{
285continue;
286}
287
288#if DEBUG
289printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
290 *modePtr, modeInfo.XResolution, modeInfo.YResolution,
291 modeInfo.BitsPerPixel, modeInfo.MemoryModel,
292 modeInfo.ModeAttributes);
293#endif
294
295// Filter out unwanted modes based on mode attributes.
296
297if ( ( ( modeInfo.ModeAttributes & attributesSet ) != attributesSet )
298 || ( ( modeInfo.ModeAttributes & attributesClear ) != 0 ) )
299{
300continue;
301}
302
303// Pixel depth in bits.
304
305modeBitsPerPixel = modeInfo.BitsPerPixel;
306
307if ( ( modeBitsPerPixel == 4 ) && ( modeInfo.MemoryModel == 0 ) )
308{
309// Text mode, 16 colors.
310}
311else if ( ( modeBitsPerPixel == 8 ) && ( modeInfo.MemoryModel == 4 ) )
312{
313// Packed pixel, 256 colors.
314}
315else if ( ( ( modeBitsPerPixel == 16 ) || ( modeBitsPerPixel == 15 ) )
316&& ( modeInfo.MemoryModel == 6 )
317&& ( modeInfo.RedMaskSize == 5 )
318&& ( modeInfo.GreenMaskSize == 5 )
319&& ( modeInfo.BlueMaskSize == 5 ) )
320{
321// Direct color, 16 bpp (1:5:5:5).
322modeInfo.BitsPerPixel = modeBitsPerPixel = 16;
323}
324else if ( ( modeBitsPerPixel == 32 )
325&& ( modeInfo.MemoryModel == 6 )
326&& ( modeInfo.RedMaskSize == 8 )
327&& ( modeInfo.GreenMaskSize == 8 )
328&& ( modeInfo.BlueMaskSize == 8 ) )
329{
330// Direct color, 32 bpp (8:8:8:8).
331}
332else
333{
334continue; // Not a supported mode.
335}
336
337// Modes larger than the specified dimensions are skipped.
338
339if ( ( modeInfo.XResolution > width ) ||
340( modeInfo.YResolution > height ) )
341{
342continue;
343}
344
345// Perfect match, we're done looking.
346
347if ( ( modeInfo.XResolution == width ) &&
348( modeInfo.YResolution == height ) &&
349( modeBitsPerPixel == bitsPerPixel ) )
350{
351matchedMode = *modePtr;
352bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
353break;
354}
355
356// Save the next "best" mode in case a perfect match is not found.
357
358if ( modeInfo.XResolution == outModeInfo->XResolution &&
359modeInfo.YResolution == outModeInfo->YResolution &&
360modeBitsPerPixel <= outModeInfo->BitsPerPixel )
361{
362continue; // Saved mode has more depth.
363}
364
365if ( modeInfo.XResolution < outModeInfo->XResolution ||
366modeInfo.YResolution < outModeInfo->YResolution ||
367modeBitsPerPixel < outModeInfo->BitsPerPixel )
368{
369continue; // Saved mode has more resolution.
370}
371
372matchedMode = *modePtr;
373bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
374}
375
376return matchedMode;
377}
378
379//==========================================================================
380// setupPalette
381
382static void setupPalette( VBEPalette * p, const unsigned char * g )
383{
384 int i;
385 unsigned char * source = (unsigned char *) g;
386
387 for (i = 0; i < 256; i++)
388 {
389 (*p)[i] = 0;
390 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red
391 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green
392 (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue
393 }
394}
395
396//==========================================================================
397// Simple decompressor for boot images encoded in RLE format.
398
399char * decodeRLE( const void * rleData, int rleBlocks, int outBytes )
400{
401 char *out, *cp;
402
403 struct RLEBlock {
404 unsigned char count;
405 unsigned char value;
406 } * bp = (struct RLEBlock *) rleData;
407
408 out = cp = malloc( outBytes );
409 if ( out == NULL ) return NULL;
410
411 while ( rleBlocks-- )
412 {
413 memset( cp, bp->value, bp->count );
414 cp += bp->count;
415 bp++;
416 }
417
418 return out;
419}
420
421//==========================================================================
422// setVESAGraphicsMode
423
424static int
425setVESAGraphicsMode( unsigned short width,
426 unsigned short height,
427 unsigned char bitsPerPixel,
428 unsigned short refreshRate )
429{
430 VBEModeInfoBlock minfo;
431 unsigned short mode;
432 unsigned short vesaVersion;
433 int err = errFuncNotSupported;
434
435 do {
436 mode = getVESAModeWithProperties( width, height, bitsPerPixel,
437 maColorModeBit |
438 maModeIsSupportedBit |
439 maGraphicsModeBit |
440 maLinearFrameBufferAvailBit,
441 0,
442 &minfo, &vesaVersion );
443 if ( mode == modeEndOfList )
444 {
445 break;
446 }
447
448//
449// FIXME : generateCRTCTiming() causes crash.
450//
451
452// if ( (vesaVersion >> 8) >= 3 && refreshRate >= 60 &&
453// (gBootMode & kBootModeSafe) == 0 )
454// {
455// VBECRTCInfoBlock timing;
456//
457// // Generate CRTC timing for given refresh rate.
458//
459// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
460// refreshRate, kCRTCParamRefreshRate,
461// &timing );
462//
463// // Find the actual pixel clock supported by the hardware.
464//
465// getVBEPixelClock( mode, &timing.PixelClock );
466//
467// // Re-compute CRTC timing based on actual pixel clock.
468//
469// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
470// timing.PixelClock, kCRTCParamPixelClock,
471// &timing );
472//
473// // Set the video mode and use specified CRTC timing.
474//
475// err = setVBEMode( mode | kLinearFrameBufferBit |
476// kCustomRefreshRateBit, &timing );
477// }
478// else
479// {
480// // Set the mode with default refresh rate.
481//
482// err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
483// }
484
485 // Set the mode with default refresh rate.
486
487 err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
488
489 if ( err != errSuccess )
490 {
491 break;
492 }
493
494 // Set 8-bit color palette.
495
496 if ( minfo.BitsPerPixel == 8 )
497 {
498 VBEPalette palette;
499 setupPalette( &palette, appleClut8 );
500 if ((err = setVBEPalette(palette)) != errSuccess)
501 {
502 break;
503 }
504 }
505
506 // Is this required for buggy Video BIOS implementations?
507 // On which adapter?
508
509 if ( minfo.BytesPerScanline == 0 )
510 minfo.BytesPerScanline = ( minfo.XResolution *
511 minfo.BitsPerPixel ) >> 3;
512
513 // Update KernBootStruct using info provided by the selected
514 // VESA mode.
515
516 bootArgs->Video.v_display = GRAPHICS_MODE;
517 bootArgs->Video.v_width = minfo.XResolution;
518 bootArgs->Video.v_height = minfo.YResolution;
519 bootArgs->Video.v_depth = minfo.BitsPerPixel;
520 bootArgs->Video.v_rowBytes = minfo.BytesPerScanline;
521 bootArgs->Video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr);
522
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, red, green, blue;
784
785 red = appleClut8[index * 3 + 0];
786 green = appleClut8[index * 3 + 1];
787 blue = appleClut8[index * 3 + 2];
788
789 switch (depth) {
790 case 16 :
791 result = ((red & 0xF8) << 7) |
792 ((green & 0xF8) << 2) |
793 ((blue & 0xF8) >> 3);
794 result |= (result << 16);
795 break;
796
797 case 32 :
798 result = (red << 16) | (green << 8) | blue;
799 break;
800
801 default :
802 result = index | (index << 8);
803 result |= (result << 16);
804 break;
805 }
806
807 return result;
808}
809
810//==========================================================================
811// drawColorRectangle
812
813void * stosl(void * dst, long val, long len)
814{
815asm volatile ( "rep; stosl"
816 : "=c" (len), "=D" (dst)
817 : "0" (len), "1" (dst), "a" (val)
818 : "memory" );
819
820return dst;
821}
822
823//==============================================================================
824
825void drawColorRectangle( unsigned short x,
826 unsigned short y,
827 unsigned short width,
828 unsigned short height,
829 unsigned char colorIndex )
830{
831long pixelBytes;
832long color = lookUpCLUTIndex( colorIndex, VIDEO(depth) );
833char * vram;
834
835pixelBytes = VIDEO(depth) / 8;
836vram = (char *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + pixelBytes * x;
837
838width = MIN(width, VIDEO(width) - x);
839height = MIN(height, VIDEO(height) - y);
840
841while ( height-- )
842{
843int rem = ( pixelBytes * width ) % 4;
844if ( rem )
845{
846bcopy( &color, vram, rem );
847}
848
849stosl( vram + rem, color, pixelBytes * width / 4 );
850vram += VIDEO(rowBytes);
851}
852}
853
854//==========================================================================
855// drawDataRectangle
856
857void drawDataRectangle( unsigned short x,
858 unsigned short y,
859 unsigned short width,
860 unsigned short height,
861 unsigned char * data )
862{
863unsigned short drawWidth;
864long pixelBytes = VIDEO(depth) / 8;
865unsigned char * vram = (unsigned char *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + pixelBytes * x;
866
867drawWidth = MIN(width, VIDEO(width) - x);
868height = MIN(height, VIDEO(height) - y);
869while ( height-- )
870{
871bcopy( data, vram, drawWidth * pixelBytes );
872vram += VIDEO(rowBytes);
873data += width * pixelBytes;
874}
875}
876
877//==============================================================================
878
879void loadImageScale (void *input, int iw, int ih, int ip, void *output, int ow, int oh, int op, int or)
880{
881int x,y, off;
882int red=0x7f, green=0x7f, blue=0x7f;
883for (x=0;x<ow;x++)
884for (y=0;y<oh;y++)
885{
886off=(x*iw)/ow+((y*ih)/oh)*iw;
887switch (ip)
888{
889case 16:
890{
891uint16_t val;
892val=((uint16_t *)input)[off];
893red=(val>>7)&0xf8;
894green=(val>>2)&0xf8;
895blue=(val<<3)&0xf8;
896break;
897}
898case 32:
899{
900uint32_t val;
901val=((uint32_t *)input)[off];
902red=(val>>16)&0xff;
903green=(val>>8)&0xff;
904blue=(val)&0xff;
905break;
906}
907}
908char *ptr=(char *)output+x*(op/8)+y*or;
909switch (op)
910{
911case 16:
912*((uint16_t *)ptr) = ((red & 0xF8) << 7) |
913((green & 0xF8) << 2) |
914((blue & 0xF8) >> 3);
915break;
916case 32 :
917*((uint32_t *)ptr) = (red << 16) | (green << 8) | blue;
918break;
919}
920}
921}
922
923//==============================================================================
924
925DECLARE_IOHIBERNATEPROGRESSALPHA
926
927void drawPreview(void *src, uint8_t * saveunder)
928{
929uint8_t * screen;
930uint32_t rowBytes, pixelShift;
931uint32_t x, y;
932int32_t blob;
933uint32_t alpha, in, color, result;
934uint8_t * out;
935void *uncomp;
936int origwidth, origheight, origbpx;
937uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
938
939if (src && (uncomp=DecompressData(src, &origwidth, &origheight, &origbpx)))
940{
941if (!setVESAGraphicsMode(origwidth, origheight, origbpx, 0))
942if (initGraphicsMode () != errSuccess)
943{
944return;
945}
946
947screen = (uint8_t *) VIDEO (baseAddr);
948rowBytes = VIDEO (rowBytes);
949loadImageScale (uncomp, origwidth, origheight, origbpx, screen, VIDEO(width), VIDEO(height), VIDEO(depth), VIDEO (rowBytes));
950}
951else
952{
953if (initGraphicsMode () != errSuccess)
954{
955return;
956}
957
958screen = (uint8_t *) VIDEO (baseAddr);
959rowBytes = VIDEO (rowBytes);
960// Set the screen to 75% grey.
961drawColorRectangle(0, 0, VIDEO(width), VIDEO(height), 0x01 /* color index */);
962}
963
964pixelShift = VIDEO (depth) >> 4;
965if (pixelShift < 1)
966{
967return;
968}
969
970screen += ((VIDEO (width)
971- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
972+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
973
974for (y = 0; y < kIOHibernateProgressHeight; y++)
975{
976out = screen + y * rowBytes;
977for (blob = 0; blob < kIOHibernateProgressCount; blob++)
978{
979color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
980for (x = 0; x < kIOHibernateProgressWidth; x++)
981{
982alpha = gIOHibernateProgressAlpha[y][x];
983result = color;
984if (alpha)
985{
986if (0xff != alpha)
987{
988if (1 == pixelShift)
989{
990in = *((uint16_t *)out) & 0x1f;// 16
991in = (in << 3) | (in >> 2);
992}
993else
994{
995in = *((uint32_t *)out) & 0xff;// 32
996}
997
998saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
999result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
1000}
1001if (1 == pixelShift)
1002{
1003result >>= 3;
1004*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
1005}
1006else
1007{
1008*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
1009}
1010
1011}
1012out += (1 << pixelShift);
1013}
1014out += (kIOHibernateProgressSpacing << pixelShift);
1015}
1016}
1017}
1018
1019//==============================================================================
1020
1021void updateProgressBar(uint8_t * saveunder, int32_t firstBlob, int32_t select)
1022{
1023uint8_t * screen;
1024uint32_t rowBytes, pixelShift;
1025uint32_t x, y;
1026int32_t blob, lastBlob;
1027uint32_t alpha, in, color, result;
1028uint8_t * out;
1029uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
1030
1031pixelShift = VIDEO(depth) >> 4;
1032if (pixelShift < 1) return;
1033screen = (uint8_t *) VIDEO (baseAddr);
1034rowBytes = VIDEO (rowBytes);
1035
1036screen += ((VIDEO (width)
1037- kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1038+ (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1039
1040lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
1041
1042screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
1043
1044for (y = 0; y < kIOHibernateProgressHeight; y++)
1045{
1046out = screen + y * rowBytes;
1047for (blob = firstBlob; blob <= lastBlob; blob++)
1048{
1049color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
1050for (x = 0; x < kIOHibernateProgressWidth; x++)
1051{
1052alpha = gIOHibernateProgressAlpha[y][x];
1053result = color;
1054if (alpha)
1055{
1056if (0xff != alpha)
1057{
1058in = saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++];
1059result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
1060}
1061
1062if (1 == pixelShift)
1063{
1064result >>= 3;
1065*((uint16_t *)out) = (result << 10) | (result << 5) | result;// 16
1066}
1067else
1068{
1069*((uint32_t *)out) = (result << 16) | (result << 8) | result;// 32
1070}
1071}
1072out += (1 << pixelShift);
1073}
1074out += (kIOHibernateProgressSpacing << pixelShift);
1075}
1076}
1077}
1078
1079//==========================================================================
1080// setVESATextMode
1081
1082static int setVESATextMode( unsigned short cols, unsigned short rows, unsigned char bitsPerPixel )
1083{
1084VBEModeInfoBlock minfo;
1085unsigned short mode = modeEndOfList;
1086
1087if ( (cols != 80) || (rows != 25) ) // not 80x25 mode
1088{
1089mode = getVESAModeWithProperties( cols, rows, bitsPerPixel,
1090 maColorModeBit |
1091 maModeIsSupportedBit,
1092 maGraphicsModeBit,
1093 &minfo, NULL );
1094}
1095
1096if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) )
1097{
1098video_mode( 2 ); // VGA BIOS, 80x25 text mode.
1099minfo.XResolution = 80;
1100minfo.YResolution = 25;
1101}
1102
1103// Update KernBootStruct using info provided by the selected
1104// VESA mode.
1105
1106bootArgs->Video.v_display = VGA_TEXT_MODE;
1107bootArgs->Video.v_baseAddr = 0xb8000;
1108bootArgs->Video.v_width = minfo.XResolution;
1109bootArgs->Video.v_height = minfo.YResolution;
1110bootArgs->Video.v_depth = 8;
1111bootArgs->Video.v_rowBytes = 0x8000;
1112
1113return errSuccess; // always return success
1114}
1115
1116//==========================================================================
1117// getNumberArrayFromProperty
1118
1119static int getNumberArrayFromProperty( const char * propKey,
1120 unsigned long numbers[],
1121 unsigned long maxArrayCount )
1122{
1123char * propStr;
1124unsigned long count = 0;
1125
1126propStr = newStringForKey( (char *) propKey , &bootInfo->chameleonConfig );
1127if ( propStr )
1128{
1129char * delimiter = propStr;
1130char * p = propStr;
1131
1132while ( count < maxArrayCount && *p != '\0' )
1133{
1134unsigned long val = strtoul( p, &delimiter, 10 );
1135if ( p != delimiter )
1136{
1137numbers[count++] = val;
1138p = delimiter;
1139}
1140while ( ( *p != '\0' ) && !isdigit(*p) )
1141p++;
1142}
1143
1144free( propStr );
1145}
1146
1147return count;
1148}
1149
1150//==============================================================================
1151
1152int initGraphicsMode ()
1153{
1154unsigned long params[4];
1155int count;
1156
1157params[3] = 0;
1158count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 );
1159
1160// Try to find a resolution if "Graphics Mode" setting is not available.
1161if ( count < 3 )
1162{
1163// Use the default resolution if we don't have an initialized GUI.
1164if (gui.screen.width == 0 || gui.screen.height == 0)
1165{
1166gui.screen.width = DEFAULT_SCREEN_WIDTH;
1167gui.screen.height = DEFAULT_SCREEN_HEIGHT;
1168}
1169
1170params[0] = gui.screen.width;
1171params[1] = gui.screen.height;
1172params[2] = 32;
1173}
1174
1175// Map from pixel format to bits per pixel.
1176
1177if ( params[2] == 256 )
1178params[2] = 8;
1179
1180if ( params[2] == 555 )
1181params[2] = 16;
1182
1183if ( params[2] == 888 )
1184params[2] = 32;
1185
1186return setVESAGraphicsMode( params[0], params[1], params[2], params[3] );
1187}
1188
1189//==========================================================================
1190// setVideoMode
1191//
1192// Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE.
1193
1194void setVideoMode( int mode, int drawgraphics)
1195{
1196unsigned long params[4];
1197int count;
1198int err = errSuccess;
1199
1200if ( mode == GRAPHICS_MODE )
1201{
1202 if ( (err=initGraphicsMode ()) == errSuccess )
1203{
1204if (gVerboseMode)
1205{
1206// Tell the kernel to use text mode on a linear frame buffer display
1207bootArgs->Video.v_display = FB_TEXT_MODE;
1208}
1209else
1210{
1211bootArgs->Video.v_display = GRAPHICS_MODE;
1212}
1213}
1214}
1215
1216if ( (mode == VGA_TEXT_MODE) || (err != errSuccess) )
1217{
1218count = getNumberArrayFromProperty( kTextModeKey, params, 2 );
1219if ( count < 2 )
1220{
1221params[0] = 80; // Default text mode is 80x25.
1222params[1] = 25;
1223}
1224
1225setVESATextMode( params[0], params[1], 4 );
1226bootArgs->Video.v_display = VGA_TEXT_MODE;
1227}
1228
1229currentIndicator = 0;
1230}
1231
1232//==============================================================================
1233void getGraphicModeParams(unsigned long params[])
1234{
1235params[3] = 0;
1236
1237VBEModeInfoBlock minfo;
1238
1239unsigned short vesaVersion;
1240unsigned short mode = modeEndOfList;
1241
1242getNumberArrayFromProperty( kGraphicsModeKey, params, 4);
1243
1244mode = getVESAModeWithProperties( params[0], params[1], params[2],
1245 maColorModeBit |
1246 maModeIsSupportedBit |
1247 maGraphicsModeBit |
1248 maLinearFrameBufferAvailBit,
1249 0,
1250 &minfo, &vesaVersion );
1251
1252params[0] = minfo.XResolution;
1253params[1] = minfo.YResolution;
1254params[2] = 32;
1255}
1256
1257//==========================================================================
1258// Return the current video mode, VGA_TEXT_MODE or GRAPHICS_MODE.
1259
1260int getVideoMode(void)
1261{
1262 return bootArgs->Video.v_display;
1263}
1264
1265//==========================================================================
1266// Display and clear the activity indicator.
1267
1268// BASIC Indicator
1269static char indicator[] = {'-', '\\', '|', '/', '-', '\\', '|', '/', '\0'};
1270
1271// To prevent a ridiculously fast-spinning indicator,
1272// ensure a minimum of 1/9 sec between animation frames.
1273#define MIN_TICKS 2
1274
1275//==============================================================================
1276
1277void spinActivityIndicator(int sectors)
1278{
1279 static unsigned long lastTickTime = 0, currentTickTime;
1280
1281if (previewTotalSectors && previewSaveunder)
1282{
1283int blob, lastBlob;
1284
1285lastBlob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
1286previewLoadedSectors+=sectors;
1287blob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors;
1288
1289if (blob!=lastBlob)
1290{
1291updateProgressBar (previewSaveunder, lastBlob, blob);
1292}
1293return;
1294}
1295
1296currentTickTime = time18(); // late binding
1297if (currentTickTime < lastTickTime + MIN_TICKS)
1298{
1299return;
1300}
1301else
1302{
1303lastTickTime = currentTickTime;
1304}
1305
1306if (getVideoMode() == VGA_TEXT_MODE)
1307{
1308if (currentIndicator >= sizeof(indicator))
1309{
1310currentIndicator = 0;
1311}
1312putchar(indicator[currentIndicator++]);
1313putchar('\b');
1314}
1315}
1316
1317//==============================================================================
1318
1319void clearActivityIndicator( void )
1320{
1321if ( getVideoMode() == VGA_TEXT_MODE )
1322{
1323putchar(' ');
1324putchar('\b');
1325}
1326}
1327
1328//==============================================================================
1329

Archive Download this file

Revision: 2527