5

I've got an application where you can watch replays for a given 2D game :

Basically, a vehicle is moving on a map. The view is centered on vehicle so the map is scrolling as replay is playing, something Micro Machines-like (it's just to give an idea, the actual game is not Micro Machines).


(source: randomracket.com)

In my scene, the map is static while the vehicle is moving around. The view is scrolling for each frame of the replay, so that vehicle is centered. For performance reason, the map is tiled in several QGraphicsPixmapItems.

Viewport update mode is set to QGraphicsView::BoundingRectViewportUpdate. Items index method is set to QGraphicsScene::NoIndex.

In most cases, all is working fine. But when the map is larger than usual, the vehicle is not updated. The view is scrolling and tiles are well updated; but not the vehicle, unless I trigger a full viewport update by zooming in/out (so I know the item is well positioned).

The vehicle's boundingRect is set once for ever, and is valid (see below, given in logical coordinates). I do not paint outside item's bounding rect.

some example of debug output (only third configuration does not work) :

ok :
vehicle->boundingRect() : QRectF(-1.9391,-1.9391 3.8782x3.8782)
scene->sceneRect() : QRectF(-117.543,-38.3826 138.834x40.3217)
SCENE_CACHING : 85 tiles

ok :
vehicle->boundingRect() : QRectF(-2.88489,-2.88489 5.76979x5.76979)
scene->sceneRect() : QRectF(-68.8843,-18.2202 187.989x119.277)
SCENE_CACHING : 308 tiles

nok : vehicle won't update
vehicle->boundingRect() : QRectF(-3.45546,-3.45546 6.91092x6.91092)
scene->sceneRect() : QRectF(-64.2988,-107.802 188.927x187.445)
SCENE_CACHING : 506 tiles

I tried to debug an update pass, and the paint event indeed excludes the region where vehicle is...

Anyone know why an update could miss a particular item ?

Edit :

Qt : 4.8.1, and i've seen the problem with previous versions as well

OS : Windows XP SP3, did not test on other OS yet

I did not succeed in reproducing the problem with a minimal example. The minimal example just work like it is expected to do. In real life, here is what is done :

  1. The map is read from a file. It's composed of up to hundreds of polygons delimiting ground/sky (each one of which is graphically made of polygons, edges and vertices layers), thousands of pictures and textures which are then clipped to ground or sky, and some other items.

  2. I compute all the clippings, and then render the scene in a QImage. The image is tiled in several QGraphicsPixmapItems added to the scene, while the former items are removed from scene and deleted (btw the bug also occured when I didn't remove&delete former items).

  3. The replay is launched

I think Qt Graphics internals are messed up, but I can't figure out how to clean/reset it.

Here is an example of graphics (to illustrate what I mean by ground/sky). The map can be quite huge.


(source: kopasite.net)

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
azf
  • 2,179
  • 16
  • 22
  • How do you scroll the view? Are you using `QGraphicsView::centerOn`? – Stephen Chu Jun 14 '12 at 17:14
  • No, i use `QGraphicsView`'s scrollbars to center on something, [like this](http://pastebin.com/vwNEFBQf) – azf Jun 14 '12 at 17:47
  • 1
    I know it is a lot to ask, but is there any way you could post a working minimal example that duplicates the problem? Also, what OS and Qt version? – Dave Mateer Jun 17 '12 at 17:58
  • Have you tried `QGraphicsItem::update()` for the vehicle, in addition to `QGraphicsScene::update()`? It seems like for some reason the view does not think it needs to repaint the item, perhaps because its drawing position does not change. – Anthony Jun 18 '12 at 15:24
  • this does not help unfortunately. @DaveMateer I try to do a minimal example, but I don't know if it will reproduce the problem. – azf Jun 18 '12 at 17:56
  • How are you moving the vehicle? Via `setPos()`? – Anthony Jun 18 '12 at 18:26
  • @Anthony yes, I use `setPos()` to move vehicle's item around the scene – azf Jun 19 '12 at 08:32
  • Does "vehicle don't update" mean that no appropriate method is called by the scene or the view (no breakpoint triggered) or "only" that you do not see the vehicle. Could it be that the vehicle is drawn _behind_ the map? – Johannes S. Jun 19 '12 at 14:40
  • Did you try to use `QGraphicsScene::invalidate(...)` to invalidate parts of the scene that should be redrawn? Does it work when you use `FullViewportUpdate` ? If yes, is this too slow for you ? – Johannes S. Jun 19 '12 at 14:48
  • @JohannesS. I meant that no breakpoint was triggered. A `FullViewportUpdate` would have been to heavy. BUT ! a call to `QGraphicsScene::invalidate(xxx, ItemLayer)` did the trick. It seems I misunderstood Qt docs on this method. Post an answer so I can accept it. – azf Jun 19 '12 at 17:45

2 Answers2

3

Picking up my comment from above as an answer:

You need to use QGraphicsScene::invalidate(...) to invalidate the parts of the scene that should be redrawn.

Johannes S.
  • 4,566
  • 26
  • 41
  • Thanks for the idea. Sometimes reading doc is not sufficient. To be more precise, I used `QGraphicsScene::invalidate(bRect,ItemLayer)`, where `bRect` is my item's bounding rect in scene coordinates. And `ItemLayer` because I do not use background nor foreground. – azf Jun 20 '12 at 18:05
1

I believe this is similar to a problem I have had when working with lots QGraphicsItems. I eventually solved my problem by streamlining the amount of QGraphicsItems I had on the screen at any one time, and to not cache QGraphicsItems that did not need to be cached.

An easy way to check if this is your problem would be:

vehicle->setCacheMode(QGraphicsItem::NoCache);

Which should cause the paint method on your vehicle to be called everytime it needs to be drawn.

effjae
  • 151
  • 2
  • 7
  • I tried what you suggested (even if Qt's doc states that _The default mode is NoCache_), but without success. You are right, though, that it only happens when a lot of items is involved. But it's only to render background once, then I delete all useless items. – azf Jun 18 '12 at 17:52