[comp.sys.mac.programmer] Graphics/Animation Problems

davet@cmi.com (David Temkin) (04/11/91)

I'm developing an animated game for for the Mac which, because of 
performance requirements, doesn't use QuickDraw. It works in 1-bit (black 
and white) mode, as well as 2-bit mode. In black and white everything is 
pretty much fine. But in 2-bit mode things sometimes get a bit flaky, and 
I've been having problems with a variety of obscure (read non-sanctioned) 
Mac graphics techniques. Would some kind (and knowledgeable) souls in 
netland please read on and pass on any info they might have?

1. The most serious problem I have manifests itself in 2-bit mode on some 
machines, but not on others. The problem seems to be that my program 
writes directly into the video buffer. This only works properly on SOME 
configurations. 

On the Mac IIsi and the IIci and some fx configurations, there is no 
apparent problem writing directly to video memory. But on other machines, 
notably the vanilla Mac II, IIx, IIcx (each with the standard video cards) 
and the LC, my program produces a distorted image (multiply overlaid 
copies of the image, separated horizontally) on the top two-thirds of the 
screen, and nothing below it. I'm using 24-bit addressing, but even if I 
use 32-bit addressing (with SwapMMUMode) the result is the same. 
(Incidentally, the new calls provided with 32-bit QuickDraw -- 
GetPixBaseAddr and PixMap32Bit -- do not help. The addresses in question 
are unchanged and apparently do not need to be addressed in 32 bit mode). 
I considered the possibility that the problem may have something to do 
with 32-bit clean ROMs, but (1) I have seen it work on a IIcx with a 
different video card, and (2) there are no ROM calls involved -- all of 
the graphics code is mine.

What is going on? Is the memory mapping following a non-linear or 
discontinuous model with the 2-bit video screen? Does anybody out there 
have any experience with this? I assume that the 2-bit screen is mapped 
essentially like the black and white screen, except that each pixel takes 
two bits. Is this not universally true? Or am I simply missing some 
initialization procedure?

2. For some reason, I have been unable to communicate with the video 
drivers as specified in Designing Cards and Drivers. I'm interested in 
using 
the second video page in Macs that have them (apparently Mac IIs and 
SE/30s may have them as well as the originals), and to determine whether 
such a beast exists, I need to query the video driver using a Status call. 
But it comes up nonsense. Here's the code in question (Think C):

void
this()
{
	GDHandle gdev;
	short refNum;
	OSErr err;
	VDPageInfo csParam;
	
	InitToolbox();
	gdev = GetMainDevice();
	refNum = (**gdev).gdRefNum;
	err = Status(refNum, cscGetMode, &csParam);
}

Following the status call, err is 0 (noErr) but csParam contains garbage. 
What am I missing? One odd aspect of this problem is that on the machine 
I'm currently using (IIci w/built-in video), the device refNum is -49, 
even though IM says reference numbers range from -1 to -32. Is this 
significant?

Along these lines, I am currently using the alternate screen buffers on 
the old (compact) macs using the old segment loader techniques (relaunch 
if I don't have the alternate screen allocated):

if (CurPageOption != -1) { 
	GetAppParms(ApplName, &ref, &aHandle);
	Launch(-1, ApplName); 
	}

There are a number of problems with this method. First, relaunching in 
this manner does not seem to be supported in System 7 or under 
Multifinder. Second, I can't figure out from inside the program whether or 
not the program has already been launched. The problem here is that if I'm 
running under Multifinder or whatever and I cannot get possession of the 
second screen, the program continues to launch itself, over and over, 
without notifying the user (or itself) that there has been a problem. I'd 
like to be able to take some intelligent action if I cannot gain 
possession of the second screen. Ideas?

(In fact, I'd really like to know a way to get at the old Mac alternate 
screen under Multifinder and System 7. What exactly is preventing it from 
being used under these systems? Is there a workaround? It would improve 
the performance of my program by about 20 percent if I could reliably 
access the alternate screen buffer. And on 68000-based systems, that 20 
percent is significant.)

Also -- on the SE/30, one does not flip video pages in the same way as it 
is done on older compact Macs (using the VIA register A, bit 6). Is it 
done using the video driver SetMode control call? A tech note said in 
plain English that the SE/30 has two video buffers, but I haven't been 
able to get at the alternate screen. How is this done? And how is it done 
on the Classic? Is it the same as the Plus/SE?

3. How do you invalidate the whole screen? Because my program takes over 
an entire monitor, and because the pallete manager "hard-wires" black and 
white into the color table (I don't use white), I've resorted to the color 
manager to set the colors directly for the given device, and after 
running, I restore the colors which were present prior to running my 
program. This works fine, but sometimes when the program exits, the text 
in underlying windows is drawn improperly (white on black -- it seems that 
something happens to the QuickDraw background/foreground colors). However, 
if the screen is then blanked using a screen saver and then restored, 
everything comes back to normal. So, the question is: what can I do to 
correct this? How does one invalidate the whole screen in the same manner 
as the screen saver?

Anyway, thanks for reading this far. I would truly appreciate some answers 
to these questions; I've been dealing with these problems for some time 
now. If there's anyone out there who's knowledgeable about low-level Mac 
graphics, I'd appreaciate it if they could give me some pointers.


David Temkin
Center for Machine Intelligence, EDS Corp.
davet@cmi.com

jmunkki@hila.hut.fi (Juri Munkki) (04/14/91)

In article <9822@etsu.CMI.COM> davet@cmi.com (David Temkin) writes:
>notably the vanilla Mac II, IIx, IIcx (each with the standard video cards) 
>and the LC, my program produces a distorted image (multiply overlaid 
>copies of the image, separated horizontally) on the top two-thirds of the 
>screen, and nothing below it.

You are probably assuming that rowBytes is related to the width of the
screen. This isn't so. A 640 pixel screen actually has a rowBytes that
accomodates 1024 on most Macintosh video cards. 640/1024 probably looks
like two thirds of the screen and results in overlaid graphics.

> I'm using 24-bit addressing, but even if I 
>use 32-bit addressing (with SwapMMUMode) the result is the same. 

You should be using 32-bit addressing no matter what machine you are
using. It never hurts and if you fail to use it in the right place,
you'll just a crash or something even worse.

>have any experience with this? I assume that the 2-bit screen is mapped 
>essentially like the black and white screen, except that each pixel takes 
>two bits. Is this not universally true?

As I said above, this is not true. Never assume anything. Dig it out from
Inside Macintosh. Inside Macintosh says that each row is rowBytes wide, so
that's how you have to write software.

>2. For some reason, I have been unable to communicate with the video 
>drivers as specified in Designing Cards and Drivers. I'm interested in 
>using 
>the second video page in Macs that have them (apparently Mac IIs and 
>SE/30s may have them as well as the originals), and to determine whether 
>such a beast exists, I need to query the video driver using a Status call. 

I just wrote something that seems to work quite well. I was thinking about
doing this with the Sega 3D glasses, so this seemed like a good time to try
it out. Project STORM uses a different approach (it plays with color tables).

You have to have a valid mode in the mode parameter, so I first get the
current mode. You then find out how many pages there are. With MaxAppleZoom,
the 16 color mode doesn't allow two pages. This was a surprise, but it also
explains why the Oids demo behaves the way it does. You have to remember
that video cards are not required to support multiple pages. Most of them
just happen to have that capability. Palette animation is a more reliable
method of obtaining double buffering.

Here's some Think C code that works:

#include <video.h>

GDHandle	Device;
CntrlParam	VideoParam;
VDPageInfo	ModeRecord;
int		NumPages=1;	/*	At least one page, I assume	*/

void	GetMainInfo()
{
	Device=GetMainDevice();
	VideoParam.ioCompletion = 0;
	VideoParam.ioRefNum = (*Device)->gdRefNum;
}

int	ReadCurrentMode()
{
	int		theErr;
	VDPageInfo	ThisModeRecord;
	
	*(void **)(&VideoParam.csParam) = &ThisModeRecord;

	VideoParam.csCode = cscGetMode;	
	theErr = PBStatus(&VideoParam,0);
	if(theErr) return theErr;

	ModeRecord = ThisModeRecord;
	
	VideoParam.csCode = cscGetPageCnt;
	theErr = PBStatus(&VideoParam,0);
	NumPages = ThisModeRecord.csPage;

	return theErr;
}

int	SetCurrentPage(n)
int	n;
{
	int		theErr;
	VDPageInfo	NewModeRecord;
	
	NewModeRecord = ModeRecord;
	NewModeRecord.csPage = n;
	
	*(void **)(&VideoParam.csParam) = &NewModeRecord;
	VideoParam.csCode = cscSetMode;
	theErr = PBControl(&VideoParam,0);
	
	return theErr;
}

void	main()
{
	int	i;
	long	j;
		
	GetMainInfo();
	ReadCurrentMode();
	
	
	for(i=0;i<NumPages;i++)
	{	SetCurrentPage(i);
		Delay(60,&j);
	}
	
	SetCurrentPage(ModeRecord.csPage);
}


>There are a number of problems with this method. First, relaunching in 
>this manner does not seem to be supported in System 7 or under 
>Multifinder. Second, I can't figure out from inside the program whether or 
>not the program has already been launched. The problem here is that if I'm 
>running under Multifinder or whatever and I cannot get possession of the 
>second screen, the program continues to launch itself, over and over, 
>without notifying the user (or itself) that there has been a problem. I'd 
>like to be able to take some intelligent action if I cannot gain 
>possession of the second screen. Ideas?

Leave yourself an event that identifies your application. You can put an
application specific event in the event queue and look for it at startup.
I don't know how well this is supported with System 7.0, but at least I
think it should work on anything newer than that. Another way is to use
a file to mark your startup. Of course the system folder might be locked...

>(In fact, I'd really like to know a way to get at the old Mac alternate 
>screen under Multifinder and System 7. What exactly is preventing it from 
>being used under these systems? Is there a workaround? It would improve 
>the performance of my program by about 20 percent if I could reliably 
>access the alternate screen buffer. And on 68000-based systems, that 20 
>percent is significant.)

As far as I know it isn't supported. Just write your program so that it
can do without the alternate buffer if it has to and notify the user that
there will be a 20% improvement if the game is booted from a disk containing
an older system. A boot time init that reserves this RAM area might work.
I remember seeing something like this posted on the net a few years ago...

>Also -- on the SE/30, one does not flip video pages in the same way as it 
>is done on older compact Macs (using the VIA register A, bit 6). Is it 
>done using the video driver SetMode control call? A tech note said in 
>plain English that the SE/30 has two video buffers, but I haven't been 
>able to get at the alternate screen. How is this done? And how is it done 
>on the Classic? Is it the same as the Plus/SE?

Try it, now that you have working code. It might work. Let us know if it
does. I don't have a machine to try it on.

>This works fine, but sometimes when the program exits, the text 
>in underlying windows is drawn improperly (white on black -- it seems that 
>something happens to the QuickDraw background/foreground colors).

I assume that you are using SetEntries to restore the screen contents.
A Develop magazine issue specifically warns about this (it was an article
about the palette manager). I haven't had any problems with a pair of
SaveEntries and RestoreEntries. Just remember that the color count is
not the actual count but the count-1 (I was bitten by that feature).



   ____________________________________________________________________________
  / Juri Munkki	    /  Helsinki University of Technology   /  Wind  / Project /
 / jmunkki@hut.fi  /  Computing Center Macintosh Support  /  Surf  /  STORM  /
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

deadman@garnet.berkeley.edu (Ben Haller) (04/21/91)

In article <1991Apr14.011556.23504@santra.uucp> jmunkki@hila.hut.fi (Juri Munkki) writes:
>In article <9822@etsu.CMI.COM> davet@cmi.com (David Temkin) writes:
>> I'm using 24-bit addressing, but even if I 
>>use 32-bit addressing (with SwapMMUMode) the result is the same. 
>
>You should be using 32-bit addressing no matter what machine you are
>using. It never hurts and if you fail to use it in the right place,
>you'll just a crash or something even worse.

Wrong.  Switching processor modes is slow, because the SwapMMUMode routine
is slow.  So you only want to call it if you have to.  People with 24-bit
boards tend to be people with fast machines, so they can afford the call,
whereas people with vanilla Mac IIs (or an LC, even worse) haven't got much
processor to spare, and probably don't have 24-bit boards.

>>have any experience with this? I assume that the 2-bit screen is mapped 
>>essentially like the black and white screen, except that each pixel takes 
>>two bits. Is this not universally true?
>
>As I said above, this is not true. Never assume anything. Dig it out from
>Inside Macintosh. Inside Macintosh says that each row is rowBytes wide, so
>that's how you have to write software.

Um, he was asking about 2-bit graphics, not about rowBytes.  In answer,
yes, in two-bit mode each pixels takes two consecutive bits, and is
otherwise mapped the same as in 1-bit mode.  This may not be true in
the future, but it's true now.

>>This works fine, but sometimes when the program exits, the text 
>>in underlying windows is drawn improperly (white on black -- it seems that 
>>something happens to the QuickDraw background/foreground colors).
>
>I assume that you are using SetEntries to restore the screen contents.
>A Develop magazine issue specifically warns about this (it was an article
>about the palette manager). I haven't had any problems with a pair of
>SaveEntries and RestoreEntries. Just remember that the color count is
>not the actual count but the count-1 (I was bitten by that feature).

Interesting.  Could you give a more specific reference?  Is there a TN on
this, or is this Develop article the only reference?  I've been having a
fair bit of trouble with QuickDraw's color matching scheme lately, and
I'm pretty sure I've found some outright bugs, so I'd like to see this
article.

-Ben Haller (deadman@garnet.berkeley.edu)

"Wave after wave, each mightier than the last
 'Til last, a ninth one, gathering half the deep
 And full of voices, slowly rose and plunged
 Roaring, and all the wave was in a flame"
   -Tennyson, "The Coming of Arthur"

jmunkki@hila.hut.fi (Juri Munkki) (04/21/91)

In article <1991Apr20.200229.805@agate.berkeley.edu> deadman@garnet.berkeley.edu (Ben Haller) writes:
>In article <1991Apr14.011556.23504@santra.uucp> jmunkki@hila.hut.fi (Juri Munkki) writes:
>>> I'm using 24-bit addressing, but even if I 
>>>use 32-bit addressing (with SwapMMUMode) the result is the same. 
>>
>>You should be using 32-bit addressing no matter what machine you are
>>using. It never hurts and if you fail to use it in the right place,
>>you'll just a crash or something even worse.
>
>Wrong.  Switching processor modes is slow, because the SwapMMUMode routine
>is slow.  So you only want to call it if you have to.  People with 24-bit
>boards tend to be people with fast machines, so they can afford the call,
>whereas people with vanilla Mac IIs (or an LC, even worse) haven't got much
>processor to spare, and probably don't have 24-bit boards.

Assuming that you group all your drawing between two calls to SwapMMUMode,
the overhead is not noticeable. Of course, I was just giving my opinion
and you are quite free to disagree. I just dropped into TMON to look at
the ROM code from SwapMMUMode and it's 27 assembly instructions long. Of
course there's the overhead from the trap dispatcher that you might be
worried about.

If you would like to be useful, how about showing us how to find out which
cards need the call to SwapMMUMode? I have no idea how this could be done
unless one has full documentation for 32 bit QD.

Usually when people try to find out about machine features that they really
do not need to know about, they end up shooting themselves in the foot. Just
think of all those programs that checked for a Mac II and failed to work if
they were run on a IIx. I spent a few hours fixing their code with TMON to
prove my clients that a Mac IIx really was compatible with the software.

>>In article <9822@etsu.CMI.COM> davet@cmi.com (David Temkin) writes:
>>>have any experience with this? I assume that the 2-bit screen is mapped 
>>>essentially like the black and white screen, except that each pixel takes 
>>>two bits. Is this not universally true?
>>
>>As I said above, this is not true. Never assume anything. Dig it out from
>>Inside Macintosh. Inside Macintosh says that each row is rowBytes wide, so
>>that's how you have to write software.
>
>Um, he was asking about 2-bit graphics, not about rowBytes.  In answer,
>yes, in two-bit mode each pixels takes two consecutive bits, and is
>otherwise mapped the same as in 1-bit mode.  This may not be true in
>the future, but it's true now.

Actually what I said fixed the problem. David contacted me with E-mail
to thank for solving the problems he had problems with. He really did
assume that with a 640 pixel wide screen the rowBytes value would be
something like 160. If you read the symptoms that he wrote about, you'll
see why I answered the way I did. [The above quote from David isn't
complete and as such is slightly misleading.]

>>I assume that you are using SetEntries to restore the screen contents.
>>A Develop magazine issue specifically warns about this (it was an article
>>about the palette manager). I haven't had any problems with a pair of
>>SaveEntries and RestoreEntries. Just remember that the color count is
>>not the actual count but the count-1 (I was bitten by that feature).
>
>Interesting.  Could you give a more specific reference?  Is there a TN on
>this, or is this Develop article the only reference?  I've been having a
>fair bit of trouble with QuickDraw's color matching scheme lately, and
>I'm pretty sure I've found some outright bugs, so I'd like to see this
>article.

Develop, volume 2, issue 1, Palette Manager Animation, by Rich Collyer.

   ____________________________________________________________________________
  / Juri Munkki	    /  Helsinki University of Technology   /  Wind  / Project /
 / jmunkki@hut.fi  /  Computing Center Macintosh Support  /  Surf  /  STORM  /
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

deadman@garnet.berkeley.edu (Ben Haller) (04/28/91)

In article <1991Apr21.073551.14802@santra.uucp> jmunkki@hila.hut.fi (Juri Munkki) writes:
>In article <1991Apr20.200229.805@agate.berkeley.edu> deadman@garnet.berkeley.edu (Ben Haller) writes:
>>Wrong.  Switching processor modes is slow, because the SwapMMUMode routine
>>is slow.  So you only want to call it if you have to.
>
>If you would like to be useful, how about showing us how to find out which
>cards need the call to SwapMMUMode? I have no idea how this could be done
>unless one has full documentation for 32 bit QD.
>
>Usually when people try to find out about machine features that they really
>do not need to know about, they end up shooting themselves in the foot.

OK, I'll bite.  First you check if color QuickDraw is available.  This
can be done like:
  
  SysEnvRec worldRec;
  
  SysEnvirons(1, &worldRec);
  if (worldRec.hasColorQD)
    ...CQD is available...
  else
    ...CQD is not available...

If CQD is available, then you should find out monitor information from
the GDevice list, check for 32-Bit QuickDraw, etc.  If it's not, then
you may find out the monitor information from screenBits and GrayRgn,
and you need not check for 32-Bit QuickDraw, swap MMU modes, etc. - all
that is guaranteed not to be necessary.
  So, the next step is checking for 32-Bit QuickDraw.  This can be done
as follows:

#define QD32Trap 0xAB03
#define UnImplTrap 0xA89F

  if (NGetTrapAddress(QD32Trap, ToolTrap) !=
         NGetTrapAddress(UnImplTrap, ToolTrap))
    ...32-Bit QD is available...
  else
    ...32-Bit QD is not available...

If 32-Bit CQD is available, then you need to check whether you should
swap MMU modes or not.  If 32-Bit CQD is not available, then you never
need to swap the MMU.  So the next step is, given that 32-Bit CQD is
available, how do you check whether you need to swap the MMU for a given
PixMap?  I haven't done this yet (I'll be doing it when I get around to the
next revision of Solarian II).  I believe there is a call in the 32-Bit
QuickDraw suite that tells you whether a given PixMap needs to be swapped.
But I don't think that's strictly necessary.  What I would do is get
the base address from the GDevice's PixMap (it *must* be the GDevice's,
other PixMaps will probably have the main GDevice's baseAddr, or may even
have 0 if I recall correctly).  Then do the following comparison:

  if ((long)baseAddr != StripAddress(baseAddr))
    ...need to swap the MMU to write directly to the screen...
  else
    ...don't need to swap the MMU...

  I'm providing this information because it was requested.  I do not vouch
for it's complete accuracy (such as on strange third-party color monitors
for the Plus or SE that hack into QuickDraw in strange ways, etc.)  Also,
Apple may be recommending other ways of checking for some of these things
nowadays, in particular there may be Gestalt calls that Apple recommends
using  instead of SysEnvirons and comparing trap addresses.  But I really
doubt that Apple will break these method of checking, since may programs
use them.
  On a slightly different note, I keep posting things like this relating to
going direct to screen.  I hope someone somewhere is keeping these posts
for future integration into a UMPG-type thing, or a FAQ post.  I spend a
lot of time telling people how to go direct to screen.  It's a popular
topic.

-Ben Haller (deadman@garnet.berkeley.edu)
"Soy el galan de las penas
 Llorando
 Sin compasion." - David Byrne

mxmora@unix.SRI.COM (Matt Mora) (05/02/91)

In article <1991Apr27.193509.19020@agate.berkeley.edu> deadman@garnet.berkeley.edu (Ben Haller) writes:

>  On a slightly different note, I keep posting things like this relating to
>going direct to screen.  I hope someone somewhere is keeping these posts
>for future integration into a UMPG-type thing, or a FAQ post.  I spend a
>lot of time telling people how to go direct to screen.  It's a popular
>topic.


Don't worry, I got it all. It will be in volume II of the UMPG. By the
way, how about posting (or mail it to me so I can include it in the UMPG)
some of the actual direct to screen drawing code you have.
Or is it only available for a nominal fee? I know you mentioned something
about your sorce code was for sale for $25.




>-Ben Haller (deadman@garnet.berkeley.edu)









-- 
___________________________________________________________
Matthew Mora                |   my Mac  Matt_Mora@sri.com
SRI International           |  my unix  mxmora@unix.sri.com
___________________________________________________________

deadman@garnet.berkeley.edu (Ben Haller) (05/05/91)

In article <23841@unix.SRI.COM> mxmora@unix.sri.com (Matt Mora) writes:
(in what perhaps should have been a personal letter, but since it
wasn't I'll reply...since everybody else keeps asking me too... :-> )
>how about posting (or mail it to me so I can include it in the UMPG)
>some of the actual direct to screen drawing code you have.
>Or is it only available for a nominal fee? I know you mentioned something
>about your sorce code was for sale for $25.

  The only program I've done so far that's available as shareware (and,
therefore, that source could conceivably be available for) that does 
direct to screen drawing is Solarian II, and in fact the source to that
is not available.
  However, this is dodging the question.  In actuality, I don't post actual
code because of a few reasons:

    o I would have to write the code, since Solarian II's code is not
      acceptable for general distribution, being poorly written and
      uncommented in large measure.
    
    o I would have to deal with all the questions and such that my post
      would generate (like I don't already... :-> )
    
    o Most of all, I feel that direct to screen stuff is very touchy,
      and should not be attempted by people who don't know a lot about
      Color QuickDraw, GDevices, the cursor handling, etc.  Anyone who
      can't write code based on the (fairly explicit) hints that I give
      shouldn't be anywhere *near* doing direct to screen stuff, IMHO.

    o A final reason: the point of writing direct to screen code is either
      to implement functionality that QuickDraw simply *cannot* do, which
      is very rare and very complex (since QD does everything easy...),
      or is to achieve significant speedups over using QuickDraw.  To
      achieve a significant speedup, one needs to write fairly optimized
      assembly that is specifically geared towards the imaging being done.
      Any post I might do would be almost useless for anything beyond the
      (reasonably simple) details of how to set a pixel to a color without
      QuickDraw.  This isn't a major point, since most people are stuck at
      the how-to-write-to-screen-memory-safely stage, but it is a minor
      point.

-Ben Haller (deadman@garnet.berkeley.edu)
"Jamaica...Afriki..." - Alpha Blondy
It's fascinating the mundane things that pass for
song lyrics... or .sigs...