home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sys.mac.programmer
- Path: sparky!uunet!decwrl!adobe!jholt@adobe.com
- From: jholt@adobe.com (joe holt)
- Subject: Game Techniques (was: NON-QUICKDRAW GAMES)
- Message-ID: <1992Sep8.004821.11323@adobe.com>
- Sender: usenet@adobe.com (USENET NEWS)
- Organization: Adobe Systems Inc.
- Date: Tue, 8 Sep 1992 00:48:21 GMT
- Lines: 184
-
- Whoa! Slow down. All this talk of palettes is way ahead of schedule. First
- we've got to talk about sync'ing to monitor retrace, opening windows and
- positioning them on long word boundaries, and--and... Oh, what the heck.
-
-
- PALETTES
-
- I must be honest and say I didn't know that much about the Palette Manager
- until this morning, when I read all of these palette questions and I asked
- myself, "Yeah, so how does one do that?" You see, my last serious, for
- profit, game endeavor was several years ago when the word on the street was
- that the current implementation of the Palette Manager was best avoided.
-
- So like any good engineer, I combed the documentation for the lowest-level
- access to the video card's clut and used it. This information was available
- in the first edition of "Designing Cards and Drivers for the Macintosh
- Family (Starring Delta Burke)". Along with the clut calls one could find the
- calls for changing a monitor's depth without the pesky Monitors control
- panel. Of course this useful information has been removed from subsequent
- editions of "Designing Cards" in the interest of public safety (just like
- Delta Burke).
-
- But now everything works, we've been given SetDepth(), and we should use
- what the system provides. And here's what I came up with this morning:
-
- The basic strategy is to create a window "around" whatever direct-to-screen
- stuff you're going to do, and attach the appropriate palette to it. The
- window does two useful things for us: it keeps the rest of the system from
- drawing on top of us--that is, it sorta legitimizes our poking onto the
- screen (this is what I meant in the first post about screen real estate),
- and it gives us an easy place to hang a palette that is used whenever the
- window is frontmost.
-
- So let's create the window (this code assumes an 8-bit color display and
- System 7):
-
- // global stuff
-
- #include <Palettes.h>
-
- static WindowPtr window;
- static CTabHandle clut;
- static PaletteHandle palette;
-
- ..
-
- // inside initialization code
-
- Rect bounds;
-
- SetRect( &bounds, 50, 50, 512+50, 384+50 );
- window = NewCWindow( nil, &bounds, "\pRed", true, noGrowDocProc,
- (WindowPtr) -1, true, 0 );
- SetPort( window );
-
- And stick a palette onto it:
-
- clut = (CTabHandle) GetResource( 'clut', 128 );
- palette = NewPalette( 32, clut, pmAnimated+pmExplicit, 0 );
- SetPalette( window, palette, false );
-
- The 'clut' resource is a ramp from white in index zero to 100% red in
- index 31. ResEdit has a blend command which makes this easy. Once you get
- this working, experiment with different values in the clut.
-
- The flags to NewPalette() tell the Palette Manager that index zero in the
- clut resource should be stuck in the video card's clut at index zero, and
- so on (pmExplicit), and that no one else can use our colors (pmAnimated).
- As I read Inside Mac 6, the combination of these two makes them the highest
- priority as the Palette Manager is trying to shoehorn colors into the
- hardware clut. Basically we're saying that colors 0 through 31 belong to
- us and nobody else, and here they are. Nyah.
-
- To see if all of this works, I draw a ramp of my colors into the window
- on update events:
-
- // In response to update events
-
- int c, y;
- RGBColor black;
-
- y = 0;
- PenSize( 10, 10 );
- black.red = black.green = black.blue = 0;
- TextSize( 9 );
-
- for ( c = 0; c < 32; ++c ) {
- unsigned char text[100];
-
- PmForeColor( c );
- MoveTo( 16, y );
- LineTo( 16384, y );
-
- RGBForeColor( &black );
- MoveTo( 2, y + 9 );
- NumToString( c, text );
- DrawString( text );
-
- y += 12;
- }
- PenNormal();
-
- Each line in the window lists an index (0 - 31) and shows a bar of that
- color. Using PmForeColor() says we want the RGB color of that particular
- index--which, if all this Palette Manager stuff is working, should be the
- value that's stored into screen memory. Hmmm... what if I just poked those
- values into memory myself?
-
- // Do this on mouse downs, or whenever you want
-
- static int c = 0;
- PixMapHandle pix;
- Ptr baseAddr, rowBase, p;
- int rowBytes, x, y;
- char mmuMode;
- Rect bounds;
- unsigned char text[100];
-
- SetRect( &bounds, -32000, -32000, 32000, 32000 );
- pix = (**GetMaxDevice( &bounds )).gdPMap;
- baseAddr = (**pix).baseAddr;
- rowBytes = (**pix).rowBytes & 0x3FFF;
-
- mmuMode = true32b;
- SwapMMUMode( &mmuMode );
- for ( rowBase = baseAddr, y = 30; y; --y ) {
- for ( p = rowBase, x = 30; x; --x ) *p++ = c;
- rowBase += rowBytes;
- }
- SwapMMUMode( &mmuMode );
-
- TextSize( 12 );
- SetRect( &bounds, 485, 0, 16384, 20 );
- EraseRect( &bounds );
- MoveTo( bounds.left + 5, bounds.bottom - 5 );
- NumToString( c, text );
- DrawString( text );
-
- c = (c+1) % 32;
-
- I wrote this code as my mouse down handler just to give me an easy way to
- trigger it. It draws a rectangle in the upper left corner of the screen by
- stuffing values directly into screen memory. The value it stuffs--<c>--is
- incremented each time this executes and the value is displayed in the upper
- right corner of our window.
-
- --> I'm using GetMaxDevice() because my main monitor is a 4-bit grayscale
- two-page display, and my second monitor is the 8-bit one where I want the
- drawing to take place. Suit to taste.
-
- Notice that I SwapMMUMode() around the stuff that actually "draws" into
- screen memory. As mentioned before, this is necessary only in certain video
- configurations, but for now it doesn't hurt to be safe, and the alternative
- is death by poking.
-
- So I run this, drag the window over to my 8-bit monitor, and I see a nice
- red ramp in the window, white at the top and deep red at the bottom. When I
- click the mouse button a white square appears in the corner of my monitor
- and the number '0' appears in the window. Each time I click the mouse the
- number increments and the square gets redder. Wow.
-
- What have I just done? In a system-friendly way, I've forced my will upon
- the video hardware and blasted screen memory. I know that a zero written
- into screen memory will be color zero from my clut, a one will be color
- number one, etc. I know this because I TOLD IT.
-
- Just to prove that the Palette Manager is really doing it's job, bring up
- the Monitors control panel and play with the screen depth, moving the app
- window from frontmost to the back and back and forth. By the way, take a look
- at the small clut display at the bottom of the control panel. Is the red
- ramp at the start where you think colors 0 - 31 should be? Wrong! The
- Monitors control panel shows the entries in reverse order. Go figure.
-
- Now of course to really do this right you'd want to put the red square inside
- the window. Otherwise the system doesn't know we've been drawing and odd
- visuals result. (For example, put the window's drag bar so that it overlaps
- the red square and click the mouse button so that the square clobbers part of
- the drag bar. Then move the window.) This entails finding the screen address
- of the upper left corner of the *window*, and possibly aligning the window on
- a long word boundary. But these will have to be subjects of another post, as
- this one is already pushing the limits of my concentration.
-
- /joe
-
-