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

Archive Download this file

Revision: 2341