Cairo_scale() problem

I have a widget subclassing a GtkDrawingArea with the size of 1000000x1000000 placed inside a viewport in a scrolled window. I am overriding the draw() method, where I draw a number of pixbufs on different positions. I also need to scale them with a varying scale factor. When I do that, the pixbufs move somewhere in the stratosphere. I can’t even find their exact position, because it’s hard to scroll to a random position in such a large area. To scale one pixbuf, maintaining its position, this works:
cairo_translate(cr, pixPosX * (1-z), pixPosY * (1-z)); where z is the scale factor, but it works as long as I add it BEFORE cairo_scale. As I said I am drawing multiple pixbufs and I cannot translate/scale on each, because each pixbuf will individually grow exponentially. I need to scale once, and draw each pixbuf on the translated position. How do I do that?

You really can’t have a widget of this size, for a variety of reasons—the most pressing one being: the Cairo coordinate system is represented as a 24.8 fixed point, 32 bit integer internally, which means it has limits on size and precision.

If you have a large canvas you will need to tile it into separate surfaces, each within a safe size depending on the precision and range you wish to achieve.

Then why don’t I have warnings or errors from Gdk or cairo?
My previous workflow was a big GtkOverlay, maybe not as big, but still, big. It had other complications and disadvantages so I decided to use a GtkDrawingArea. I can reduce the size for now, but I’d need to get the scaling to work. I don’t know what the “safe” size is, I’m just relying on GTK+ and the reference page to guide me.

Because the problem is not the size: GTK will only create a Cairo surface for the visible region. The problem is that once you start scaling and in general change the current transformation matrix, you’re going to hit precision and range problems pretty quickly once you start moving the Cairo pen.

You’re not going to get errors from Cairo because the fixed point format is internal, and the precision cut-off does not generate errors: just rendering artifacts.

I’ll have this in mind, thank you for pointing it out.

Any idea what is the correct way to make the translation so that pixbufs remain on their respective locations, scaled?

Is this for a mapping application? In my experience, I would avoid making a giant widget and putting it in GtkViewport, it works better to implement GtkScrollable on your drawing area and handle the scrolling and transformation of coordinates to screen space there before calling any cairo functions.

I need to get the project done. I haven’t done it, but my guess is that adding a native scrolling behavior on it will take time. One for implementing it and two for finding out what has to be done. The widget represents a virtual space for a game.

  1. Perform cairo_scale(cr, z, z) before drawing pixbufs
  2. For every pixbuf being drawn, add cairo_translate(cr, (xpos*(1-z)/z), (ypos*(1-z)/z)); prior to rendering
  3. After rendering cairo_translate(cr, -(xpos*(1-z)/z), -(ypos*(1-z)/z));

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.