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

Archive Download this file

Revision: 2385