Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch/i386/boot2/graphics.c

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

Archive Download this file

Revision: 2740