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

Archive Download this file

Revision: 2323