I'm wanting to do something like the following:
...
pixel[0,0] = [ 254, 0, 0 ] # Draw R at pixel x0y0
pixel[2,1] = [ 0, 254, 0 ] # Draw G at pixel x2y1
pixel[4,2] = [ 0, 0, 254 ] # Draw B at pixel x4y2
...
I hope to display many different configurations of pixels and colours in a short space of time -- writing to an intermediary file would be too expensive.
How should I best go about achieving this goal in Python?
Direct answer:
This can only be done with OS-specific APIs. Some OSes do not allow changing pixels on the screen directly.
On Windows, you can use pywin32 libraries to get screen's device context with dc = GetDC(0) call, then paint pixels with SetPixel(dc, x, y, color).
import win32gui
import win32api
dc = win32gui.GetDC(0)
red = win32api.RGB(255, 0, 0)
win32gui.SetPixel(dc, 0, 0, red) # draw red at 0,0
Of course, what you paint this way can be erased at any moment.
Right answer:
Painting pixel by pixel is the slowest way to paint something. For example, on Windows, creating an image in memory then painting it in one operation is order of magnitude faster than painting with SetPixel.
If you need speed, use some user interface library for python, for example, Tkinter module or PyQt. Create a window and image in memory, then paint the image on the window. If you need to manipulate pixels, manipulate them in the image and repaint every time.
Although it does not exactely what you say (paint "by pixel"), I like to use Python, GTK and Cairo.
In this case, you create a GTK Window, add a DrawingArea, create a Cairo context, and do paint operations.
The difference is that you have a continuous canvas with floating-point coordinates, and instead of pixels you draw geometric shapes with strokes and fills. You could even draw rectangles one-pixel-sized, and fill them, but that would not be so fast.
Also, you can take any raster object (image, pixbuffer) and render it at once. Then you could generate images in a fast sequence, and render its pixels all at once, similar to a movie.
A working example can be seen in a previous answer here (second snippet):
quickest way to get started with cairo
Im not sure if I get your question right, but I believe you should investigate some framework or middleware that give you an access to screen. I would say PyGame or Pyglet or maybe even Panda. It may be overkill a bit because Pygame and Panda is a framework that let you develop game while Pyglet is wrapper to Opengl in python, but it will let you control pixels, windows and similar with easy.
Related
I am working on building an interactive rectangle for various OpenCV methods. The big box will be the final contour I feed into the OpenCV methods, and the small boxes and circle are resizing tools. This all works fine except for when I have a large image(I grabbed an iphone image roughly 4000 x 4000). With the larger images, the manipulating of the rectangle is no longer fluid.
I understand that it also may be in the methodology that I've implemented my translation/rotation logic, but I'd like to first check if there is a better way to draw/redraw each frame:
def redraw(self):
self.image = self.image_display.copy()
self.plot(self.image, color=(0, 0, 255),thickness=self.line_thickness)
self.updateimg = True
Upon initialization, I make a copy of the image I'm working on and once I redraw, I copy that said fresh image from my copy and then redraw the contours.
Is there a better way to go about this? I was looking into bitwise_and and just plain adding, but there were masks I had to generate first and it seemed as if it would be much more of a hassle.
I'm wanting to do something like the following:
...
pixel[0,0] = [ 254, 0, 0 ] # Draw R at pixel x0y0
pixel[2,1] = [ 0, 254, 0 ] # Draw G at pixel x2y1
pixel[4,2] = [ 0, 0, 254 ] # Draw B at pixel x4y2
...
I hope to display many different configurations of pixels and colours in a short space of time -- writing to an intermediary file would be too expensive.
How should I best go about achieving this goal in Python?
Direct answer:
This can only be done with OS-specific APIs. Some OSes do not allow changing pixels on the screen directly.
On Windows, you can use pywin32 libraries to get screen's device context with dc = GetDC(0) call, then paint pixels with SetPixel(dc, x, y, color).
import win32gui
import win32api
dc = win32gui.GetDC(0)
red = win32api.RGB(255, 0, 0)
win32gui.SetPixel(dc, 0, 0, red) # draw red at 0,0
Of course, what you paint this way can be erased at any moment.
Right answer:
Painting pixel by pixel is the slowest way to paint something. For example, on Windows, creating an image in memory then painting it in one operation is order of magnitude faster than painting with SetPixel.
If you need speed, use some user interface library for python, for example, Tkinter module or PyQt. Create a window and image in memory, then paint the image on the window. If you need to manipulate pixels, manipulate them in the image and repaint every time.
Although it does not exactely what you say (paint "by pixel"), I like to use Python, GTK and Cairo.
In this case, you create a GTK Window, add a DrawingArea, create a Cairo context, and do paint operations.
The difference is that you have a continuous canvas with floating-point coordinates, and instead of pixels you draw geometric shapes with strokes and fills. You could even draw rectangles one-pixel-sized, and fill them, but that would not be so fast.
Also, you can take any raster object (image, pixbuffer) and render it at once. Then you could generate images in a fast sequence, and render its pixels all at once, similar to a movie.
A working example can be seen in a previous answer here (second snippet):
quickest way to get started with cairo
Im not sure if I get your question right, but I believe you should investigate some framework or middleware that give you an access to screen. I would say PyGame or Pyglet or maybe even Panda. It may be overkill a bit because Pygame and Panda is a framework that let you develop game while Pyglet is wrapper to Opengl in python, but it will let you control pixels, windows and similar with easy.
Background
I'm working in python/pyglet to create a procedurally generated terrain.
I'm visualizing it with pyglet by running a lambda function for each x and y coordinate on the screen and then painting that pixel in the color I want it.
This is not very optimal.
I have a sneaking suspicion that there is a way to create a rectangular object and tell the GL engine to render a texture upon it, giving the GL engine a lambda function that will return the color in exchange for an x and y coordinate.
Pseudo pyglet example
def get_color(pos):
x, y = pos
color = x * y % 255
return [color, color, color]
width = 1680
height = 1024
win = window.Window(fullscreen=False, vsync=True, width=width, height=height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluOrtho2D(0, win.width, 0, win.height)
glTextureMapper(get_color)
win.clear()
points = [0, 0, width, 0, width, height, 0, height]
pyglet.graphics.draw(int(len(points) / 2), GL_QUADS, ('v2f', points))
TLDR Question
How do I color a polygon using a lambda function? Is this a shader?
Pyglet examples are preferred, but examples in any language are welcome
This is probably not a complete answer, but might get you a bit further.
Also keep in mind that I've never worked much with textures at all weirdly enough.
What you might be able to do, is create a texture-group for any set of quads, and add them into a batch. Because I'm not entirely sure why you need a lambda function?
class TextureGroup(pyglet.graphics.Group):
def set_state(self):
glEnable(texture.target)
glBindTexture(texture.target, texture.id)
def unset_state(self):
glDisable(texture.target)
vertice_mem = {}
batch = pyglet.graphics.Batch()
texture_group = TextureGroup()
vertice_list = batch.add(2, pyglet.gl.GL_QUADS, None, ('v2f', points))
vertice_mem[(x,y)] = vertex_list
This is one way to optimize how textures are added to certain faces and also add those faces into a batch rendering them a lot faster and more dynamic.
If you need to update the vertices, you can always access the vertice_list.vertices and change the x,y pair for that particular face.
You can use the custom group to create certain textures "on the fly", or on this case pre-rendered certain textures which you could stitch together to create "procedural" textures.
What #Ripi2 says is also a good tip, read up on how procedural memory mapping works and what it actually is. Most graphics you see in sand-box games are actual clever re-use of textures to create the illusion of on-demand graphics.
The last and final tip is that you will most likely need to look into shaders, they are by far the fastest way to auto-generate "textures" by manipulating and creating turbulence in textures, else will be heavily taxing on your system because you will need to iterate over the pixel area in some way.
But again, this is not my area of experience - only a fellow travelers bits and pieces of information gathered over the years.
As pointed out strictly speaking OpenGL cannot draw rectangles (quads), but you can always use a diagonal between two corners to make two triangles. (There can be some differences in interpolation between corners, but they probably won't affect you.)
And while I'm being pedantic, you're not coloring pixels, you're colouring points on your 3D terrain object surface. (I'm assuming you want the terrain to keep the same colors when viewed from any angle or distance.)
OK, what I hope will be the real answer. Is your procedural terrain generation coloring done once, or does it change dynamically?
If you only create and color the terrain once, use a texture map. You'll need to learn how to assign texture coordinates at the corners of the terrain (TL;DR: they'll be (0.0,0.0), (1.0,0.0), (1.0,1.0), (0.0, 1.0) ) and how to use glTexImage2D to transfer an image to the GPU.
Texture maps are just 2D raster images. Pyglet should be able to handle this for you, if not either Pillow or the Python Imaging Library packages.
If you want the terrain to change colors on the fly, you need a fragment shader, a small function written in OpenGL Shading Language that executes every time the terrain is drawn. And due to the way OpenGL works you'll also have to write a vertex shader that handles the 3D coordinate transformations.
This will mean more thinking and coding that the texture map approach. But everything in OpenGL (or DirectX, or RenderMan, …) is done with shaders these days, so you might as well start learning. And shaders let you do any kind of procedural modelling and animation, not just colors. For example, you could dynamically generate your terrain heights as well as colors.
Hope this helps.
I'm trying to write a 2D game using python / pygame that blits several layers on top of one another every screen refresh. My basic setup is (from bottom to top):
Background: surface (non-transparent), scrolls at a different rate than rest
Midground: SRCALPHA transparent surface (static)
Player / Sprites / Enemies: sprite group
Forground: SRCALPHA transparent surface (static)
Right now, I'm blitting these four layers one on top of another every screen. The background scrolls at a different rate than the other three layers, which is why I have it separate from midground. As I have the game structured now, it runs on my fairly modest laptop at 60fps.
-BUT- I'm having trouble with the sprite group, which I'm blitting directly to the screen. Having to adjust the rect for every sprite according to my current viewport seems like an ugly way to program things, and I'd like a more elegant solution.
I'd love to blit the sprites to another transparent surface which I could manage, but therin lies my problem: I can't find a way of clearing a transparent layer that doesn't half my performance. Some of the setups I've tried:
I've tried filling the layer with a white surface with blend mode rgba_sub (surf.fill((255,255,255,255), area, BLEND_RGBA_SUB)) -- this is super, super slow
I've tried surface.copy() of a blank surface - this is faster, but still halves my fps
I've tried combining the sprites with the midground layer and using pygame.sprite.LayeredUpdates to update the sprites. This has no effect on performance, but does not work where the midground is transparent. I get trails of sprites over the background layer.
The best solution I've found so far is my current setup of drawing sprites directly to the screen. It looks great, runs fast, but is a pain to manage, as I have to make sure each sprites' rect is adjusted according to the viewport every frame. Its also making collision detection difficult.
Is there another quick way to clear a pygame transparent surface? Quick as in, can be done 60+ times a second? Alternately, is there a setup for my layers that would still accomplish the same effect?
I figured out a fast way of clearing a sprites only transparent layer by applying Peter's solution selectively to the layer:
for s in self.level.sprites:
spritelayer.fill((0), s.rect)
This seems to be working fine (erasing everything each frame) and still runs at 60fps.
The Surface.fill() will clear all R, G, B, and A values.
>>> img = pygame.image.load("hasalpha.png")
>>> print img.get_at((300, 300))
(238, 240, 239, 255)
>>> surface.fill(0)
>>> print img.get_at((300, 300))
(0, 0, 0, 0)
It sounds like this will do what you are describing. If you are trying to do something more specific with the alpha values the pygame.surfarray.pixel functions can give you directly editable values. That will be quick, but requires numpy as a dependency.
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).