So, it’s been a few months since I posted an update, but things have been progressing steadily along. I’ve turned my attention to level design for the last few months, and haven’t done much with the code. The core of the game was working nicely and most of the features related to gameplay are done, which has allowed me to focus on level design.
The past few weeks I’ve gone back into the code to work on implementing some of the “extra” features I wanted that weren’t gameplay related. My goal is to have both B&W and colour tilesets to allow colour on systems that have it. I’ve spent the last week struggling with colour offscreens, and I am well and truly stumped. Most of the documentation I can find relating to CGrafPorts and PixMaps talks in passing about the toolbox calls related to using these functions for offscreens, in a sort of hypothetical context, and then says you don’t actually need to ever do this, because you should just use GWorlds for offscreens instead. But GWorlds only existing System 7, and one of my main design goals is to support System 6. So I need to do this manually, and can’t figure out why what I’m doing is not working. I have found some older documentation from the System 6 era, but it’s a bit more limited, and I’m still running into problems.
My program runs a check to see if Colour Quickdraw is present at startup. If it is not, then it just uses a regular GrafPort and and offscreen Bitmap for my offscreen buffer, and then uses CopyBits to blit it to the application window. This has been working flawlessly for months. If Colour Quickdraw is present, then it creates a CGrafPort and and offscreen Pixmap for my offscreen buffer. Again, using CopyBits to blit the offscreen colour pixmap to the application window.
For testing purposes, I’ve just added a few token bits of colour to my tileset. The “C” on the robot’s chest also confirms my program is using the colour tileset, as it would show a “B” if it was the B&W tileset.
Where I seem to be running into problems is the creation of a PixMap. Here is the code I’m using to initialize the colour offscreen (The offscreen CGrafPort and PixMap are set arbitrarily small for testing purposes):
if (colourQdPresent) /* Set up colour offscreen */
{
OpenCPort(&offscreenCPort); /* Open colour offscreen port */
SetPort(&offscreenCPort); /* Set colour offscreen Port to current Port */
PortSize(256,256);
ClipRect(&offscreenCPort.portRect);
RectRgn(offscreenCPort.visRgn, &offscreenCPort.portRect);
offscreenPixmap = MakePixMap(256, 256, 4); /* create PixMap size of map */
SetPortPix(offscreenPixmap);
}
And the code I’m using to create my PixMap is as follows. My understanding is that NewPixMap() creates a duplicate of the current GDevice’s pixmap except for the colour table, and then I’m changing the baseAddr and rowBytes and setting a colour table:
PixMapHandle MakePixMap(short wantedHeight, short wantedWidth, short wantedDepth)
{
PixMapHandle aPixMap;
short tempRowBytes;
aPixMap = NewPixMap();
tempRowBytes = ((wantedDepth * (wantedWidth + 31) / 32) * wantedDepth);
(*aPixMap)->baseAddr = NewPtr((long)tempRowBytes * (long)wantedWidth);
(*aPixMap)->rowBytes = tempRowBytes;
(*aPixMap)->pixelSize = wantedDepth;
(*aPixMap)->pmTable = GetCTable(64+wantedDepth);
return(aPixMap);
}
Alternatively, I’ve tried creating a PixMap from scratch by setting all of the attributes manually instead of using NewPixMap():
PixMapHandle MakePixMap(short wantedHeight, short wantedWidth, short wantedDepth)
{
PixMapHandle aPixMap;
short tempRowBytes;
tempRowBytes = ((wantedDepth * (wantedWidth + 31) / 32) * wantedDepth);
(*aPixMap)->baseAddr = NewPtr((long)tempRowBytes * (long)wantedWidth);
(*aPixMap)->rowBytes = tempRowBytes;
(*aPixMap)->pixelSize = wantedDepth;
(*aPixMap)->pmTable = GetCTable(64+wantedDepth);
(*aPixMap)->pixelType = 0;
(*aPixMap)->hRes = 72 << 16;
(*aPixMap)->vRes = 72 << 16;
(*aPixMap)->pmVersion = 0;
(*aPixMap)->packType = 0;
(*aPixMap)->packSize = 0;
/* (*aPixMap)->planeBytes = 0; */
(*aPixMap)->pmReserved = 0;
(*aPixMap)->cmpCount = 1;
/* (*aPixMap)->cmpSize = wantedDepth; */
return(aPixMap);
}
The two lines that are commented out cause the program to freeze, and I’m not sure why yet.
But regardless of whether I use NewPixMap() or create a pixmap from scratch, I get the same result, which is a 1-bit pixmap. The first image below shows what I get when I run the program. You can see that it is using the colour tileset (“C” on the robots chest) but is drawing a 1-bit image. The second image shows what happens if I comment out my SetPortPix when creating my CGrafPort — it just draws over the desktop, which is to be expected when I haven’t set a separate pixmap, but it’s in colour, which tells me that all of my drawing routines are correctly drawing colour, and CopyBits is also not the problem. So my best guess is that I’m doing something wrong when creating my Pixmap, but I can’t figure out what is wrong.
Image 1: Using SetPortPix to change the CGrafPort pixmap to the one created -- no colour:
Image 2: Not using SetPortPix -- colour works:
A lot of the older documentation I found suggests I need to create a new GDevice for the offscreen, but I’m not really sure why I would need to, and it seems to be working, except for the colour depth, without creating a new GDevice.
A secondary issue is that in my testing, I haven’t been able to set the CGrafPort size larger than the screen resolution. No matter how large I create the PixMap, it won’t exceed screen size. I have no problem creating a B&W GrafPort and bitmap larger than screen size, so is something different about colour? Will it not let you have a port larger than the current GDevice?
Finally, an offscreen colour pixmap is huge. I draw my entire level at once in an offscreen and just blit the visible portion to the screen. When I was B&W only my memory usage was right around 300k. After creating a colour offscreen, I’m now up to about 2000k. Am I doing something inefficient here? Or is colour just going to use a lot more memory? I think I need to draw the entire level offscreen when loading, because otherwise it will be too laggy on slower machines.
As usual, any advice is greatly appreciated!