Jun 01 2011

Improving nxtCanvas

Category: Lego,Mindstorms,Programs,SoftwareSpiller @ 15:56

After a weeks delay (3 exams, playing Little Busters! for three days, and a bit of piano training) I’m finally able to do some more on RICcreator.

Lately I have been working on nxtCanvas, the class which attempts to emulate the drawing functions on the NXT.

First of all, LineOut() and RectOut() have been optimized quite a bit since they weren’t that well written… (For example, when drawing a filled rectangle, it first drew a normal rectangle and then a filled one inside that.)

Not minding the small stuff, I finally fixed the EllipseOut() implementation. After doing a bit of math it just worked much more like I wanted in a much simpler procedure… I also added fill-shape, so this is now working for both circles and ellipses. To avoid it drawing on some pixels several times it has quite a bit of exceptions, so it needs to be cleaned up someday. But well, it works.

RIC fonts

I have also finally written a simple implementation of RIC fonts. In short, it is just FontTextOut() without any special font copy options. However this much is enough to get a TextOut() and NumOut() working. I made a RIC font which looks like the default font on the NXT and TextOut() simply calls FontTextOut() using this RIC font.

So the Number opcode is now working, meaning only Polygons aren’t fully supported. And I’m not sure when this will be added, because I’m simply unsure on how it should work…

Interestingly, the font I used is different from the one used in nxtRICedit. I based it on the 1.29 standard firmware source and it looks the same when trying it on my NXT. Was the font different in the 1.0x firmwares? For now I’m not planning to emulate how it would look on the standard or older versions of the firmware, but it would be good to know if there is a difference here.

Editing nxtCanvas

I have also done a bit of work on the GUI side.

You can now edit the copy options settings which opens up the possibility of drawing in white, using fill-shape, and XOR drawing:

Scrennshot of the nxtCanvasEdit GUI

There are some performance issues with displaying the canvas. Right now it needs to fully redraw everything each time the nxtCanvas has been changed. It does so by drawing the entire field white and then adds the black pixels. This means the performance decreases the more black pixels there are. (So the performance issues with fill-shape is actually because of the huge black areas.)

There are two solutions to this problem. One is to make nxtCanvas draw directly on the image class QT needs. However since I want to make riclib completely independent on QT for reusability reasons, this is not an option.

The other solution is to only partially redraw the image. It would surely speed up the redrawing but nxtCanvas would need to specify the changes with every drawing operation… I will try to add this some other day.

It might be possible  to take a more low-level approach to this, I will try to look into this and see if it is possible to gain anything by doing that.

EDIT START: Just tried that, made quite a difference… It needs to redraw everything each time this way, so no point in partial redrawing in nxtCanvas. Still slows down with more black pixels, but it should rather be treated as an optimization anyway… EDIT END

Future additions to nxtCanvas

Other than features to speed up redrawing, I’m also planning to make it possible to auto expand the canvas when the drawing operation attempts to draw outside the canvas.  The issue here would be performance though… I’m not going to add it right now anyway though…

There are also a few functions that need to be added, like shrinking the canvas size to the area actually used, and filling an random shape with a color.

VarMaps?

The most important missing feature right now is editing VarMaps. I just can’t come up with a good interface to do this with though. The solution in nxtRICedit works, but I don’t quite like it… There must be some better way to do it, but I’m still on a loss on how this should be…

Well, this is it for now… I will upload a build in a couple of days, I want to add a little bit to the GUI first.

EDIT: it has been uploaded, revision 80.

EDIT2: I forgot to upload the font file together with it, fonts will not draw without it…  Will be fixed in the next release. For now, you can place a ricfont named “font.ric” together with the .exe, it will use that one. If you really want to test it out…

6 Responses to “Improving nxtCanvas”

  1. muntoo says:

    Looks good. (I compiled revision 90.)

    I’d suggest storing the current image (sprite) into a buffer, and adding your changes on that, instead of redrawing everything. All the while, you could record user actions in an edit history. So if a user wants to undo, it simply redraws everything up to the last undo.

    As an optimization to this undo feature, you could push() “snapshot” in a std::vector every 10 user actions, or something. In other words, a [double!] time-space tradeoff.

    • muntoo says:

      Woops. That’s supposed to say: std::vector < nxtCanvas >.

    • Spiller says:

      The nxtCanvas rendering have been changed since this post. Because of lack of experience in QT I made a stupid mistake… I used a QGraphicsView in order to display the nxtCanvas. However QGraphicsView is meant to be used when you have multiple interactive elements to display, and not a single bitmap like here.
      I should just have used a QWidget and drawn it directly on that. So I did that. However that meant I need to implement scrollbars, cursor mapping and such myself. At this time it is still quite rough, but it allows me to control the drawing more precisely which opens up some possibilities for optimization. It will be a bit tricky to implement properly though.

      About undos, I will try to add it once the basic features are done. There is a history framework in QT for this kind of operations however I have not looked into it yet so I don’t know how this will be used together with the current code. (I hope it will be easier than to implement my own…) I would like something that works on the document as a whole, and not just the sprite.

      But for now… I guess I should focus on my exams… -__-
      I’m currently simplifying and improving the code though, so nothing mayor for now. Afterwards I will continue on the nxtCanvas rendering and add some new ways to work with it, namely copying, import of images and writing using RIC fonts.

  2. muntoo says:

    The following lines in nxtCanvas.h are giving me runtime errors when I try to compile with VS2010:
    unsigned int get_width() const{ return width; }
    unsigned int get_height() const{ return height; }

    Error:
    Unhandled exception at 0x0084f9ba in RICcreator.exe: 0xC0000005: Access violation reading location 0xcdcdcde5.

    • Spiller says:

      Those lines of code can’t give access violations unless the ‘this’ pointer is invalid. So it must be the function which calls those functions which has an invalid nxtCanvas pointer…

      Does the runtime errors happen immediately when you start the program, or after a while?

      EDIT: There is a crash when you rapidly open/close tabs, is this what you are experiencing? I’m quite unsure what is causing this bug though…

      EDIT2: Tried to run it with the debugger active and found the bug. The nxtCanvasWidget class, which displays the canvas, didn’t initialize the nxtCanvas pointer to NULL so it might contain an invalid pointer when the object is created. It didn’t happen very often except when closing and then reopening a tab, so I didn’t pay it much attention. I should run it in the debugger more often I guess…
      rev. 91 fixes this issue.

  3. muntoo says:

    I was unable to see the window at all. (The error occurred before window.show().) I think “setting it to NULL” solved it – revision 97 compiles and runs OK.

    http://i.imgur.com/ivUnD.png

Leave a Reply