Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2745