You don't have to use the ScreenBuffer approach, I just find it works better than the tall screen / ScrollVPort method.
Right, about double (or triple) buffering in general. The basic idea is that you always draw to a BitMap that is currently invisible. Once the drawing is done, you swap this BitMap for the one currently on display (waiting for the appropriate synchronization). The BitMap you just drew on is now on screen and the one that was on screen is now available to draw on.
Doing this ensures that you never "see" the rendering happening, which would otherwise produce a very flickery image.
A consequence of this is that the "invisible" and "visible" BitMaps keep swapping over.
Therefore, regarding the W3D_SetDrawRegion() call, you have to do this every time you flip the buffers, not just when you first set up the context. From the looks of what you have written, this is the thing you are neglecting.
So every time you do the ChangeScreenBuffer(), you must also do W3D_SetDrawRegion() to tell the W3D_Context to use the "current" invisible BitMap.
One problem I noticed with your code is that you call the AllocScreenBuffer() both times using the SB_SCREEN_BITMAP argument. This arguement is used to associate the existing screen's BitMap with the ScreenBuffer, not allocate a new one. So in your case you never really had a second buffer anyway, they were both simply pointers to the screens's one. You dont use the SB_SCREEN_BITMAP when you want to actually create an invisible buffer.
Another thing to consider is that the ChangeScreenBuffer() call can fail at the point you call it. An ugly (but working) way around this is to do something like this
Screen* screen;
W3D_Scissor scissor { ... };
ScreenBuffer* buffer[2];
int drawBuffer;
//...
// create the initial visible buffer (this is just the screens bitmap)
buffer[0] = AllocScreenBuffer(screen, NULL, SB_SCREEN_BITMAP); // doesn't allcoate BitMap
// create the initial invisible buffer. Note the second argument is 0
buffer[1] = AllocScreenBuffer(screen, NULL, 0); // does allocate BitMap
// the second buffer is the initial drawing buffer
drawBuffer = 1;
// function to swap the buffers
void mySwapBuffer()
{
// make sure we swap the buffer. This truly is an ugly way, but it works - in any case, the busy loop is almost always never entered. But for the love of god don't do anything like this in a WarpOS ppc version - possible frenzy of context switches - make it a 68K function .
buffer[drawBuffer]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort=0;
while (!ChangeScreenBuffer(screen, buffer[drawBuffer]))
;
// change the drawBuffer number
drawBuffer ^= 1;
// wait for bottom of viewport sync
WaitBOVP(&(screen)->ViewPort);
// update the context to use the new draw region
W3D_SetDrawRegion(context, buffer[drawBuffer]->sb_BitMap, &scissor);
}
If you use the above function (or similar - this is from memory), you should experience smooth, unflickering graphics.
Forget all about the YOffset thing, just use 0. It's only needed for the ScrollVPort() buffering strategy anyway.