2007-12-03

Yet More GraphicsPort Progress

Got some more done. The GraphicsPort class is now capable of drawing XORed horizontal and vertical lines, rectangles and pixels. It can also draw text using the TextWriter class. Window border classes and the ScreenTitle class use the GraphicsPort for all of their drawing operations. The GraphicsPort can also blit bitmaps (or portions of bitmaps) to its output bitmap using the new “drawBitmap()” function.

The XORed rectangle drawn when dragging a window is now produced by getting a GraphicsPort object from the window’s parent, rather than drawing directly to the framebuffer as was the case previously. This fixes the bug wherein the rectangle is drawn over the top of other screens. However, since screens are automatically reordered when clicked, this bug was redundant anyway. I’ve removed almost all of the drawing functions from the Gadget class.

Worth noting that the GraphicsPort can actually be used to write to any u16* block of RAM, so I’ll be able to use it to draw to the SuperBitmap once I’ve got all of its functions (circle, etc) moved across.

Gadgets include four methods of creating a GraphicsPort object. The two public methods return a port to the client space within the gadget; one of them uses the visible client space, whilst the other accepts a clipping rect in its constructor (primarily for use in the draw(Rect) function). The other two are protected (for internal use only), and can draw over the entire gadget (including border space).

Fixed a long-standing bug in the TextWriter class - it wasn’t converting width/height to x2/y2 values correctly. This is what caused a lot of my confusion with the TextViewer class, so hopefully I’ll be able to get that working correctly again at some point.

One odd quirk with VMWare Fusion that I’ve come across is that No$GBA won’t play sound from it. Not a big problem, but until you turn off sound output in VMWare, VMWare keeps popping up a dialogue box to tell you that it won’t play sound. Great, but how about sorting that out for me, instead of just telling me over and over again? It’s not immediately obvious how to fix the problem - I initially decided to switch sound off in No$GBA, or kill the process, but that dialogue box kept getting in the way.

Final thing for this post. Can you spot what’s wrong with this code?

// Return the internal graphics port for a specific clipping rect
GraphicsPort* Gadget::newInternalGraphicsPort(Rect clipRect) {

    Rect rect;
    getClientRect(rect);

    // Remaining code OK
    u16* bitmap = PA_DrawBg[getPhysicalScreenNumber()];

    // Ensure visible region cache is up to date
    cacheVisibleRects();

    return new GraphicsPort(this, 0, 0, _width, _height, bitmap, SCREEN_WIDTH, SCREEN_HEIGHT, &clipRect);
}

The first two lines create an instance of the Rect struct and populate it with the current gadget’s client dimensions. You may notice that this rect is subsequently not used. So why not just take it out? I tried that, and the function stops working. I also tried replacing the call to “getClientRect()” with the code from that function, and that doesn’t work either.

I might just rename the rect to “magicRect” and be done.

Comments

Jeff on 2007-12-03 at 22:06 said:

I’m not sure of your definition of “not working” so its hard to tell.

Nevertheless, GraphicsPort() is being passed the address of the rectangle argument which is a copy of the callers rectangle, on the stack - any values GraphicsPort writes will not be propagated back to the caller.

Did you mean to use Rect& ?

If its supposed to be const, make it const.

I’d guess that you have a side-effect in getClientRect() that affects the behaviour of cacheVisibleRects()

ant on 2007-12-03 at 23:37 said:

I would have used const Rect&, but the way it’s written at the moment I need a NULL check in there. I could remove that by creating an extra class variable, I suppose.

By “not working”, I mean it does nothing at all. Seemingly, anyway. Until I get the multiline textbox working properly I’m having difficulties debugging anything - I can’t use the standard text output routines any more because I’m using both DS displays. I’ve bodged together a routine using the TextWriter but it’s not a good solution.

All getClientRect() does is set the properties of the rect that is passed into it. Something like “rect.x = !_flags.borderless”. It’s very strange.

Jeff on 2007-12-04 at 01:58 said:

I meant GraphicsPort* Gadget::newInternalGraphicsPort(Rect& clipRect)

As it stands, its not possible to check clipRect for NULL because its not passed by address; I’m assuming you mean the check for NULL is inside GraphicsPort::GraphicsPort() which is fine the way it is.

I noticed another problem but haven’t been able to eliminate it in my code. Essentially, I have a Screen which contains a Window which contains a MultiText. Normally its on the top screen, but when I flip it to the bottom, the text becomes garbled (ie, it only draws about 1 in 10 characters, and they aren’t the correct ones either). Whats weird is if I press a button that does a redraw of the text, it all comes back just fine - it seems to be the flip from one screen to the next that does the damage.

Having said that, it may still be a problem in my code because I’ve also noticed that occasionally, it seems to run on past the trailing null in the string I’m displaying…