Native PyGame method for automatically scaling inputs to a surface resolution? - python

This question is related to this other one.
In my program (which uses pygame to draw objects on the video) I have two representation of my world:
A physical one that I use to make all the calculations involved in the simulation and in which objects are located on a 1000x1000 metres surface.
A visual one which I use to draw on the screen, in which my objects are located in a window measuring 100x100 pixels.
What I want to achieve is to be able to pass to my pygame drawing functions (which normally accept inputs in pixels) my physical/real-word coordinates. In other words, I would like to be able to say:
Draw a 20m radius circle at coordinates (200m, 500m)
using the precise pygame syntax:
pygame.draw.circle(surface, (255,255,255), (200,500), 20)
and get my circle of 2px radius at centred on pixels (20,50).
Please note that this question is about a native pygame way to do this, not some sort of workaround to achieve that result (if you want to answer that, you should take a look to the question I already mentioned) instead.
Thanks in advance for your time and support.

There is no native pygame way to do this.
You may be misunderstanding the function of pygame. It is not for drawing vector objects. It is for writing pixels into video surfaces.
Since you have vector objects, you must define how they will be converted into pixels. Doing this is not a workaround - it's how you are intended to use pygame.

Since it seems that PyGame developers do not hang around here too much, I brought the question to the Pygame mailing list where it originated a monster thread and the issue has been debated at large.
The summary would be:
At present there is not such a feature.
There is interest to implement it, or at least to try to implement it...
...although is not a priority of the core devs in any way
There is more than one way to skin a cat:
should be the scaling happen both ways (inputting coordinates and reading them)?
how to deal with lines that have no thickness but that should be visible?
how to deal with visibility of objects at the edge of the image? which of their points should be taken as reference to know if a pixel should be lit or not for them?
and more (see linked thread).

Related

how to manipulate an image very fast in accordance to an own math function in python

I'm trying to create a 360 degree camera just like google street cameras
(This is my whole code if you are interested)
I have a individual kind of perspective equation that map pixel [xold,yold] to [xnew,ynew] in accordance to Alpha and Beta angles as inputs.
To simplify that equation and my question, i assume i'm just trying to rotate an image.
Now my question is how to rotate an image by using rotation equation on each pixel very fast on pygame or anyother intractive shell:
xnew = xold * cos(alpha) - yold * sin(alpha)
ynew = xold * sin(alpha) + yold * cos(alpha)
Assume pygame.transform.rotate() is not available
Read the following words from pygame.org:
http://www.pygame.org/docs/ref/surface.html
"There is support for pixel access for the Surfaces. Pixel access on hardware surfaces is slow and not recommended. Pixels can be accessed using the get_at() and set_at() functions. These methods are fine for simple access, but will be considerably slow when doing of pixel work with them. If you plan on doing a lot of pixel level work, it is recommended to use a pygame.PixelArray object for direct pixel access of surfaces, which gives an array like view of the surface. For involved mathematical manipulations try the pygame.surfarray module for accessing surface pixel data using array interfaces module (It’s quite quick, but requires NumPy.)"
pygame.Surface.set_at((x,y),Color) is definitely the easiest way to do it, but for performance (which is what you asked), you must use pygame.PixelArray or pygame.surfarray.
I can't do the coding for you because I'm short on time, but these websites will point you in the right direction:
http://www.pygame.org/docs/ref/pixelarray.html#pygame.PixelArray
http://www.pygame.org/docs/ref/surfarray.html#module-pygame.surfarray
Good luck with your coding!
Given that you are trying to simulate a 3D environment, it would be extremely hard to beat a solution with PyOpenGL performance-wise. From what I saw when I ran your code, it looks like you are implementing a "skybox", where the viewer would be in a virtual cube. OpenGL is meant for 3D computations like this, so you do not need to manually shift pixels on at a time but instead let the GPU do you that for you while you just pass in a series of vertices and textures! If you need really complicated equations that manipulate every single pixel on the screen, you would then be able to use GLSL shaders to do that work on the GPU in parallel. Let me know if you want me to elaborate on this if you are interested in this approach, as it is would be very different from your current code.

Pygame draw behavior

I am currently designing basic pygame projects. Random projects actually, which are just random ideas pop into my head during common daytime. One of them is a wall clock. Where I use sin, cos functions to draw hour hand, minute hand etc..
As a result of these functions, I obtain float values. Which pygame does not allow. So I round and int() all values before using them in drawing functions. This makes sense because of pixels can't be partially filled. However, I think this results in bad drawings.
The Image above is the clock drawn by the pygame module. As you see the handles are somewhat leaning. Not straight.
I also implemented this in codeskulptor. Which is a python2 environment for basic game(or any graphical) programming. Has nice and clear functions, very easy to use indeed. The float values I use in that no needs conversion and accepted directly. I do not know how it handles it, but it is clearly better. Obviously not just rounding and integering(does this word exist ?) values. Let me show you the clock drawn in codeskuptor:
As you can see, the edges are more smooth. The lines does not end sloped, but straight. It is clearly a better drawing than the pygame one.
But the thing is, codeskuptor does not implement many modules and built-in functions that is harder than beginning level knowledge. Also it doesn't support a well-known compiler(basically not a python module). So can't work on computer and can not be compiled with py2exe, pyinstaller as such.
So I wan't to implement all this in pygame, and get smooth results just like in codeskulptor. Maybe a better way to handle float points for drawing. Any idea or knowledge in this area would be greatly appreciated.
My code for codeskuptor(Does not show realtime)
My code for pygame
The codes does not supply proper commenting because they were just a late-night fun nothing more. I'll explain any necessary parts.
To summarize the comments above, the issue you've noticed here is antialiasing. For the lines, pygame provides the aaline function, which can be used to draw a single line. Unfortunately, this does not support a varying thickness. Potential workarounds could be drawing a line of the correct thickness and drawing an aaline on either side of it, or drawing the line using an aapolygon (from the gfxdraw module).
The standard draw module does not include antialiased circles, but you can use another function from gfxdraw to draw an antialiased circle, aacircle.
It is important to note that the gfxdraw module is labeled "experimental", so the functions are not guaranteed to persist across versions of pygame. But for your quick projects that might not be a concern.
As for CodeSkulptor, they are rendering the lines on an HTML5 <canvas> element, which according to this question has anti-aliasing turned on by default.

Draw an image too big to fit into a QImage

I need to display a chart that can be very large, for example the image resolution could be 100 000 x 1000. However, it seems like I am limited to 32768 x 32768 by the QImage.
I can't reasonably redraw directly the chart at every paintEvent so I need to store it into a QImage (it could be a QPixmap that won't change anything). But then, it doesn't fit.
My first idea was:
Create a list of QImage
Plot on the various QImage
Redraw using the good QImages.
The first and last points have been done quite easily. But the second point is more complex. I'm quite confident that my approach would work but it requires to overload the basic paint methods (draw rectangle, circles, etc.) in order to be able to paint on multiple images.
So, before going any further, I would like to know what could be the other options.
You probably do not want to display more than one QImage of data at a time. Few screens are more than 32k pixels wide or tall.
So you want an abstract type that produces QImages on request for reading, at offsets and possibly at different zoom factors.
The next problem is modifying this abstract type. An easy to use, not maximally performance version consists of letting users blit QImages into your internal storage (whatever that is).
The user still has to "tile" their efforts, but can tile their efforts in ways that is convenient for them.
A higher performance version exposes some of the underlying implementation, which we have not yet mentioned.
A traditional implementation for large images is a tiled image. You have a grid of image tiles that abut each other. When someone asks for a blit from your image, you produce a temporary QImage, and blit the appropriate tiles onto it. And when someone blits to you, you figure out what the appropriate tiles are, and write parts of that source QImage over parts of them.
The higher performance interface exposes these tiles.
A low level interface lets the outside know where your tiles are, and lets them ask for them. This is a poor interface.
A better interface exposes a sub tile iterator. They ask for a region, and you return a pair of iterators that describe the region. The data in the iterators consists of either a tile and a region in that tile as well as the location this region is in the "full image", or a sub-tile object (with linestride, line length, etc) and the location of the sub-tile object.
Another good interface is a foreach style interface. Again, the user of the big image class passes in a region they want to work with, but a callback as well. That callback something similar to either one of the above results of the iterator dereference.
This approach has two large advantages over the iterator approach. First, you can implement parallel image processing algorithms within your large image class. Second, it is much easier to write than rolling your own iterator.
Once you have either of these, drawing is relatively easy. Determine the region you are drawing on (be generous). Iterate over the resulting tiles. On each tile, draw after applying the offset of the tile to the drawing.
You can use the Qt Graphics View Framework. Create a QGraphicsView and a QGraphicsScene for it. Add items using QGraphicsScene::addPixmap (that returns QGraphicsPixmapItem which is derived from QGraphicsItem) and adjust their positions using QGraphicsItem::setPos. QGraphicsView will effectively draw your scene and handle scrolling and zooming if necessary.
You do realize that a 100,000 x 1000 RGBA QImage is 400MBytes? There's no point in wasting all that memory. Really, none.
Just paint it every time, one request, in the paintEvent. Be clever about it so that you only paint what needs to be shown. I'd think one should focus on optimizing the painting process and your data structures so that it can be painted effectively.
At small scales (zoomed out), a lot can be gained by approximating/decimating/interpolating the data so that it looks the same, but you don't waste time painting the same pixel too many times.

How to optimize tile rendering in pygame?

I am making a tile based game, and the map needs to be rendered every frame. Right now, each tile is 32X32, and the visible map is 28X28 tiles. The performance is dreadful. I recently made it only render the visible tiles, but this still did not improve the FPS much. Right now I'm looking for a way to speed up the rendering. I attribute the slowness to the way I am rendering ; every tile is individually blitted to the screen. What would be a more effective was of doing this?
In pygame (afaik), updating the screen is always one hell of a bottle neck. Since I could not see your code, I don't know, how you are updating the screen. Only blitting the the sprites that changed is a start, but you need to only update those parts that changed, on the screen.
Basically it is the difference between using display.flip() or using update_rects() with only the changed rects. I know, that does not help at all, when you are scrolling the map.
Take a look at this question: Why is this small (155 lines-long) Pacman game on Python running so slow?, it has a similiar topic.
One thing I tried when I had a map compiled of tiles and some sprites on it, I tried always having a precompiled image of the map for an area containing the currently displayed part and some 200 or so pixels around that, so that I could blit the prepared "ground" (still only in updated parts) without the need of blitting all those tiles contained in it. That, of course, is quite some thinking you have to put into that, espacially if you have multiple layers and parts of the map that can be above your active sprites. It is interesting to think and work that through, but I cannot tell you, how much you will gain by that.
One totally different possible solution: I began with pygame once (since I did SDL in C++ prior to that). Recently I was directed to another python gaming library: pyglet. This does not suffer from the problems of updating the whole screen as much as pygame (I think it's because of usage of OpenGL acceleration; it still works on my not at all accelerated eee-Netbook). If you are not bound to pygame in any way, it might be interesting to take a look at pyglet.

Implementation of collide method in terms of ratio

I would like to create a list of objects that collide with the user. However, I don't want to use the sprite.collide_rect_ratio() method because it creates a rectangular area that is too big for the collision (i.e. the objects seem to collide even though they are not really touching). I want to use the pygame.sprite.collide_rect_ratio(ratio): to fix the problem. How do I implement the method so that it returns a list of objects the user collides with?
It would implement the same code except with a smaller collision area as the following code:
sprite_list = pygame.sprite.spritecollide(myself, all_sprites_list, False)
Thank you.
This may be of use to you,
What you may want to look into is "Per Pixel Collision", which will first use the bounding box of the object (what i suspect the collide_rect function does).
What you will need to do is find where the rectangles collide and how far within each other they are. You then check to see if there are any opaque pixels from one sprite touching any opaque pixels from the other sprite...
This Link may be of use to you, its a very well done tutorial for a C++ framework similar to pygame.
The Per Pixel Collision code is half way down the page, and acts how I describe above.
Hopefully this is useful to you as it negates the need for the rectangle ratios due to 'invisible collisions'.
a quick google search may help you more with this type of collision detection.
For a bit of a boost heres some sample pygame code:
for s in sprites:
# if no intersection then 'intersection' will be of size 0
intersection = s.Rect.clip(user.rect)
if intersection.width != 0 and intersection.height != 0:
# perform collision detection
Here is an already written and tested version From the pygame wiki. Reading every thing on that page will give you a good knowledge on pixel collision and some good sample code which you can use straight away.
apologies if this was too far off topic but I feel this could be very useful to you as ratios (i feel) would not perform well for collision detection.
You may also want to look at Rectangle documentation in pygame.
As for your question, looping through all sprites and using the collide_rect_ratio method would be the only way of using such a method to get a list of colliding sprites as far as i know.

Categories