pyglet when using draw() instead of eventloop - python

I'm trying to draw a circle with pyglet. But it is not visible when I use the draw() function instad of the app.run() loop. Any suggestions what I can do? thanks
from math import *
from pyglet.gl import *
window = pyglet.window.Window()
def makeCircle(x_pos, y_pos, radius, numPoints):
verts = []
glClear(pyglet.gl.GL_COLOR_BUFFER_BIT)
glColor3f(1,1,0)
for i in range(numPoints):
angle = radians(float(i)/numPoints * 360.0)
x = radius *cos(angle) + x_pos
y = radius *sin(angle) + y_pos
verts += [x,y]
circle = pyglet.graphics.vertex_list(numPoints, ('v2f', verts))
circle.draw(GL_LINE_LOOP)
input()
makeCircle(5,5, 100, 10)

You've to call window.flip() to update the window.
Since you don't have set a projection matrix, the geometry has to be draw in normalized device coordinates, which are in range [-1, 1] for all 3 components (x, y, z). Note, pyglet set a projection matrix by default when the application is started by pyglet.app.run().
Call window.flip() and change the geometry:
from math import *
from pyglet.gl import *
window = pyglet.window.Window()
def makeCircle(x_pos, y_pos, radius, numPoints):
verts = []
glClear(pyglet.gl.GL_COLOR_BUFFER_BIT)
glColor3f(1,1,0)
for i in range(numPoints):
angle = radians(float(i)/numPoints * 360.0)
x = radius *cos(angle) + x_pos
y = radius *sin(angle) + y_pos
verts += [x,y]
circle = pyglet.graphics.vertex_list(numPoints, ('v2f', verts))
circle.draw(GL_LINE_LOOP)
window.flip() # <--------
input()
makeCircle(0, 0, 0.5, 10) # <--------
Alternatively you can set an orthographic projection on your own, by glOrtho. e.g.:
from math import *
from pyglet.gl import *
window = pyglet.window.Window()
def makeCircle(x_pos, y_pos, radius, numPoints):
verts = []
glMatrixMode(GL_PROJECTION)
glOrtho(0, 640, 0, 480, -1, 1)
glMatrixMode(GL_MODELVIEW)
glClear(pyglet.gl.GL_COLOR_BUFFER_BIT)
glColor3f(1,1,0)
for i in range(numPoints):
angle = radians(float(i)/numPoints * 360.0)
x = radius *cos(angle) + x_pos
y = radius *sin(angle) + y_pos
verts += [x,y]
circle = pyglet.graphics.vertex_list(numPoints, ('v2f', verts))
circle.draw(GL_LINE_LOOP)
text = 'This is a test but it is not visible'
label = pyglet.text.Label(text, font_size=36,
x=10, y=10, anchor_x='left', anchor_y='bottom',
color=(255, 123, 255, 255))
label.draw()
window.flip()
input()
makeCircle(5,5, 100, 10)

Related

No shape display pyopengl

So i'm trying to make a function for displaying a circle, here's the function :
def drawCircle(x,y,size):
glColor3f(1,1,1)
glBegin(GL_TRIANGLE_STRIP)
glVertex2f(0,0)
glVertex2f(100,0)
glVertex2f(100,100)
glVertex2f(0,100)
But when i try it, nothing display. If you have the solution, please explain me in detail, I'm not a profesional in opengl or in pyopengl.
Here's the code :
import glfw
from OpenGL.GL import *
from OpenGL.GLUT import *
import numpy as np
import pyrr
from random import *
from math import *
buffer = bytearray(800 * 600 * 3)
display = (800,600)
if not glfw.init():
raise Exception("glfw can not be initialized!")
def CreateWindow(title="Baguette game",width=800,height=600):
display = (width,height)
window = glfw.create_window(width,height,title, None, None)
glfw.set_window_pos(window,400,200)
glfw.make_context_current(window)
return window
def DrawTriangle(pointA=[-0.5, -0.5, 0.0],pointB=[0.5, -0.5,0.0],
pointC=[-0.5, 0, 0.0],color=[1.0,1.0,1.0]):
vertices = [pointA[0], pointA[1], pointA[2],
pointB[0], pointB[1], pointB[2],
pointC[0], pointC[1], pointC[2]]
colors = [color[0], color[1], color[2],
color[0], color[1], color[2],
color[0], color[1], color[2] ]
v = np.array(vertices,dtype=np.float32)
c = np.array(colors, dtype=np.float32)
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT,0,v)
glEnableClientState(GL_COLOR_ARRAY)
glColorPointer(3, GL_FLOAT,0,c)
glDrawArrays(GL_TRIANGLES,0,3)
def DrawRectangle(size=[0.5,0.5],position=[0,0],color=[1.0,1.0,1.0]):
DrawTriangle([position[0]-size[0]/2,position[1]+size[1]/2,0],
[position[0]+size[0]/2,position[1]+size[1]/2,0],
[position[0]+size[0]/2,position[1]-size[1]/2,0],
color)
DrawTriangle([position[0]-size[0]/2,position[1]-size[1]/2,0],
[position[0]+size[0]/2,position[1]-size[1]/2,0],
[position[0]-size[0]/2,position[1]+size[1]/2,0],
color)
def Pixel(x,y):
buffer_data = [randint(0,255), 0, 0] * (x * y)
buffer = (GLubyte * (x * y * 3))(*buffer_data)
glDrawPixels(x, y, GL_RGB, GL_UNSIGNED_BYTE, buffer)
def drawCircle(x,y,size):
glColor3f(1,1,1)
glBegin(GL_TRIANGLE_STRIP)
glVertex2f(0,0)
glVertex2f(100,0)
glVertex2f(100,100)
glVertex2f(0,100)
if __name__=="__main__":
window = CreateWindow()
initialPosition = (0,0,0)
z=1
while not glfw.window_should_close(window):
glfw.poll_events()
#glClear(GL_COLOR_BUFFER_BIT)
DrawRectangle([1,1],[-0.5,0],[1,0,0])
DrawRectangle([1,1],[0.5,0],[0,1,0])
glfw.swap_buffers(window)
glfw.terminate()
You don't use the x, y and size arguments at all. A glBegin/glEnd sequence must be delimited with glEnd. e.g.:
def drawCircle(cx, cy, radius):
glColor3f(1,1,1)
glBegin(GL_TRIANGLE_FAN)
glVertex2f(cx, cy)
for a in range(361):
x = cx + radius * cos(radians(a))
y = cy + radius * sin(radians(a))
glVertex2f(x, y)
glEnd()
For example draw a circle in the center of the viewport:
drawCircle(0, 0, 0.5)
I recommend reading a good OpenGL tutorial. e.g.: LearnOpenGL

Collision detection between an ellipse and a circle

I want to make a collision detection between an ellipse and circle. The way I am doing this is:
Calculate angle from centre of the ellipse to the circle
Calculate where the point lies in the ellipse at that angle
Check for collision against that point
However, I am having one small problem. When I calculate the angle, it seems like it is 90 degrees off. I did a dirty fix by simply adding 1.5 radians to account for the 90 degrees, and it kind of works but there are inconsistencies and doesn't work properly at certain angles, particularly at around 0.7 and -2.6 radians . Here is the code (all the collision stuff is in collision method in Ellipse class)
import pygame
from math import sin, cos, atan2, radians
pygame.init()
SW = 1200
SH = 600
WIN = pygame.display
D = WIN.set_mode((SW, SH))
class Circle:
def __init__(self, radius):
self.x = 0
self.y = 0
self.radius = radius
def update(self, pos):
self.x = pos[0]
self.y = pos[1]
def draw(self, display):
pygame.draw.circle(display, (255, 0, 0), (int(self.x), int(self.y)), self.radius, 2)
circle = Circle(30)
class Ellipse:
def __init__(self, centre, rx, ry):
self.centre = centre
self.collided = False
self.rx = rx
self.ry = ry
def draw(self, display):
angle = 0
while angle < 6.28:
angle += 0.001
x = self.centre[0] + sin(angle)* self.rx
y = self.centre[1] + cos(angle)* self.ry
if self.collided:
display.set_at((int(x), int(y)), (255, 0, 0))
else:
display.set_at((int(x), int(y)), (0, 0, 255))
pygame.draw.circle(D, (0, 255, 0), (int(self.centre[0]), int(self.centre[1])), 5)
def collision(self, circle):
#angle to the circle
dx = circle.x - self.centre[0]
dy = circle.y - self.centre[1]
angle = atan2(-dy, dx)
print(angle)
#where the point lies in the ellipse at that angle
x = sin(angle + 1.5)* self.rx + self.centre[0]
y = cos(angle + 1.5)* self.ry + self.centre[1]
#print(x, y)
#drawing the point just to make sure its working
# (debugging)
pygame.draw.circle(D, (0, 255, 0), (int(x), int(y)), 5)
# distance between the point we just
# calculated and the circle's centre
distance = ((x-circle.x)**2 + (y-circle.y)**2)**0.5
#print(distance)
#collision condition
if distance < circle.radius:
self.collided = True
else:
self.collided = False
ellipse = Ellipse([600, 300], 300, 200)
while True:
events = pygame.event.get()
mousePos = pygame.mouse.get_pos()
for event in events:
if event.type == pygame.QUIT:
pygame.quit()
D.fill((255, 255, 255))
circle.update(mousePos)
circle.draw(D)
ellipse.draw(D)
ellipse.collision(circle)
pygame.display.flip()
The fist mistake is, that 1.5 is not equal to pi/2:
from math import pi
x = sin(angle + 1.5)* self.rx + self.centre[0]
y = cos(angle + 1.5)* self.ry + self.centre[1]
x = sin(angle + pi/2)* self.rx + self.centre[0]
y = cos(angle + pi/2)* self.ry + self.centre[1]
Second, calculating the point on an ellipse by an angle is a little more complicated. See the answers to the questions How to get a point on an ellipse's outline given an angle? and Calculating a Point that lies on an Ellipse given an Angle:
from math import pi, sin, cos, atan2, radians, copysign, sqrt
class Ellipse:
# [...]
def pointFromAngle(self, a):
c = cos(a)
s = sin(a)
ta = s / c ## tan(a)
tt = ta * self.rx / self.ry ## tan(t)
d = 1. / sqrt(1. + tt * tt)
x = self.centre[0] + copysign(self.rx * d, c)
y = self.centre[1] - copysign(self.ry * tt * d, s)
return x, y
def collision(self, circle):
# [...]
#where the point lies in the ellipse at that angle
x, y = self.pointFromAngle(angle)
# [...]
Minimal example: repl.it/#Rabbid76/PyGame-IntersectCircleEllipse
import math
import pygame
class Circle:
def __init__(self, center_x, center_y, radius):
self.center = center_x, center_y
self.radius = radius
def update(self, center_x, center_y):
self.center = center_x, center_y
def draw(self, surface):
pygame.draw.circle(surface, (255, 0, 0), (round(self.center[0]), round(self.center[1])), self.radius, 3)
class Ellipse:
def __init__(self, center, vertex):
self.center = center
self.collided = False
self.vertex = vertex
def draw(self, surface):
bounding_rect = pygame.Rect(0, 0, self.vertex[0] * 2, self.vertex[1] * 2)
bounding_rect.center = round(self.center[0]), round(self.center[1])
pygame.draw.ellipse(surface, (0, 255, 0), bounding_rect, 3)
def pointFromAngle(self, a):
c = math.cos(a)
s = math.sin(a)
ta = s / c ## tan(a)
tt = ta * self.vertex[0] / self.vertex[1] ## tan(t)
d = 1. / math.sqrt(1. + tt * tt)
x = self.center[0] + math.copysign(self.vertex[0] * d, c)
y = self.center[1] - math.copysign(self.vertex[1] * tt * d, s)
return x, y
def intersect_circle_ellipse(circle, ellipse):
dx = circle.center[0] - ellipse.center[0]
dy = circle.center[1] - ellipse.center[1]
angle = math.atan2(-dy, dx)
x, y = ellipse.pointFromAngle(angle)
distance = math.hypot(x - circle.center[0], y-circle.center[1])
return distance <= circle.radius, (x, y)
pygame.init()
window = pygame.display.set_mode((500, 300))
circle = Circle(0, 0, 30)
ellipse = Ellipse(window.get_rect().center, (150, 100))
run = True
while run:
events = pygame.event.get()
mousePos = pygame.mouse.get_pos()
for event in events:
if event.type == pygame.QUIT:
run = False
circle.update(*mousePos)
isect = intersect_circle_ellipse(circle, ellipse)
window.fill((255, 255, 255))
circle.draw(window)
ellipse.draw(window)
color = (255, 0, 255) if isect[0] else (0, 0, 255)
pygame.draw.circle(window, color, (round(isect[1][0]), round(isect[1][1])), 5)
pygame.display.flip()
pygame.quit()
exit()

How to get tkinter canvas object to move around a circle

I have a canvas created image:
On my canvas, I have drawn a circle:
The code to produce this circle:
def create_circle(x, y, r, canvasName): #center coordinates, radius
x0 = x - r
y0 = y - r
x1 = x + r
y1 = y + r
return canvasName.create_oval(x0, y0, x1, y1, outline='red')
create_circle(100, 100, 50, canvas)
I would like to get the canvas created image to follow the canvas drawn circle exactly (go round the circle), by each pixel. How is this possible?
To elaborate, here is a demonstration of what I want the canvas image to do:
You can use root.after to send a periodic call to change the coordinates of your image. After that its just a matter of calculating the new x, y positions of your image in each call.
import tkinter as tk
from math import cos, sin, radians
root = tk.Tk()
root.geometry("500x500")
canvas = tk.Canvas(root, background="black")
canvas.pack(fill="both",expand=True)
image = tk.PhotoImage(file="plane.png").subsample(4,4)
def create_circle(x, y, r, canvasName):
x0 = x - r
y0 = y - r
x1 = x + r
y1 = y + r
return canvasName.create_oval(x0, y0, x1, y1, outline='red')
def move(angle):
if angle >=360:
angle = 0
x = 200 * cos(radians(angle))
y = 200 * sin(radians(angle))
angle+=1
canvas.coords(plane, 250+x, 250+y)
root.after(10, move, angle)
create_circle(250, 250, 200, canvas)
plane = canvas.create_image(450,250,image=image)
root.after(10, move, 0)
root.mainloop()

pyglet window.flip() not updating

I'm drawing a circle and some text with pyglet. I'd like it to update after a keypres, but instead on calling window.flip() the second time, the window is just empty. Any suggestions are appreciated.
from math import *
from pyglet.gl import *
window = pyglet.window.Window()
def make_circle(x_pos, y_pos, radius, numPoints):
verts = []
glMatrixMode(GL_PROJECTION)
glOrtho(0, 640, 0, 480, -1, 1)
glMatrixMode(GL_MODELVIEW)
glClear(pyglet.gl.GL_COLOR_BUFFER_BIT)
glColor3f(1, 1, 0)
for i in range(numPoints):
angle = radians(float(i) / numPoints * 360.0)
x = radius * cos(angle) + x_pos
y = radius * sin(angle) + y_pos
verts += [x, y]
circle = pyglet.graphics.vertex_list(numPoints, ('v2f', verts))
circle.draw(GL_LINE_LOOP)
def text(x, y, text):
label = pyglet.text.Label(text, font_size=36,
x=x, y=y, anchor_x='left', anchor_y='bottom',
color=(255, 123, 255, 255))
label.draw()
make_circle(5, 5, 100, 10)
text(10, 10, 'Test1')
text(30, 30, 'Text2')
window.flip()
input()
make_circle(5, 5, 22, 10)
text(23, 10, 'This text does not appear')
text(30, 23, 'Neither does this one')
window.flip()
input()
If you don't use the default event loop, then you've to do the steps of the event loop your self. It is not sufficient to call window.flip().
Befor the drawing you've to call pyglet.clock.tick() to signify that one frame has passed and window.dispatch_events() to poll the operating system event queue for new events and call attached event handlers.
Note, Since the events are dispatched manually, it is not necessary to set the projection matrix.
See also Dispatching events manually
e.g.:
from math import *
from pyglet.gl import *
def make_circle(x_pos, y_pos, radius, numPoints):
verts = []
glClear(pyglet.gl.GL_COLOR_BUFFER_BIT)
glColor3f(1, 1, 0)
for i in range(numPoints):
angle = radians(float(i) / numPoints * 360.0)
x = radius * cos(angle) + x_pos
y = radius * sin(angle) + y_pos
verts += [x, y]
circle = pyglet.graphics.vertex_list(numPoints, ('v2f', verts))
circle.draw(GL_LINE_LOOP)
def text(x, y, text):
label = pyglet.text.Label(text, font_size=36,
x=x, y=y, anchor_x='left', anchor_y='bottom',
color=(255, 123, 255, 255))
label.draw()
window = pyglet.window.Window()
# make OpenGL context current
window.switch_to()
# signify that one frame has passed
pyglet.clock.tick()
# poll the operating system event queue
window.dispatch_events()
make_circle(5, 5, 100, 10)
text(10, 10, 'Test1')
text(30, 30, 'Text2')
# swap buffers
window.flip()
input()
# signify that one frame has passed
pyglet.clock.tick()
# poll the operating system event queue
window.dispatch_events()
make_circle(5, 5, 22, 10)
text(23, 10, 'This text does not appear')
text(30, 23, 'Neither does this one')
# swap buffers
window.flip()
input()

How to find PyGame Window Coordinates of an OpenGL Vertice?

I am trying to figure out the coordinates of the vertices of two rectangles in a pygame window that is using OpenGL to create the 3D objects.
import pygame
from pygame.locals import *
import random
from OpenGL.GL import *
from OpenGL.GLU import *
rect1 = [(-5.125,0,-40),(-3.125,0,-40),(-3.125,5,-40),(-5.125,5,-40),]
rect2 = [(3.125,0,-40),(5.125,0,-40),(5.125,5,-40),(3.125,5,-40)]
edges = ((0,1),(1,2),(2,3),(3,0))
#This draws the rectangles edges
def Target():
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(rect1[vertex])
glEnd()
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(rect2[vertex])
glEnd()
def main():
try:
pygame.init()
display = (320,240)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(45, (display[0]/display[1]), .1, 1000)
while True:
#iterates through events to check for quits
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
Target()
pygame.display.flip()
pygame.time.wait(100)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
except Exception as e:
print (e)
main()
How do I grab the coordinates on the pygame window(320,240) of the object?
The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport. It transforms from eye space to the clip space, and the coordinates in the clip space are transformed to the normalized device coordinates (NDC) by dividing with the w component of the clip coordinates. The NDC are in range (-1,-1,-1) to (1,1,1).
At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport. The eye space coordinates in the camera frustum (a truncated pyramid) are mapped to a cube (the normalized device coordinates).
Perspective Projection Matrix:
r = right, l = left, b = bottom, t = top, n = near, f = far
2*n/(r-l) 0 0 0
0 2*n/(t-b) 0 0
(r+l)/(r-l) (t+b)/(t-b) -(f+n)/(f-n) -1
0 0 -2*f*n/(f-n) 0
where :
aspect = w / h
tanFov = tan( fov_y / 2 );
2 * n / (r-l) = 1 / (tanFov * aspect)
2 * n / (t-b) = 1 / tanFov
Since the projection matrix is defined by the field of view and the aspect ratio it is possible to recover the viewport position with the field of view and the aspect ratio. Provided that it is a symmetrical perspective projection, where the field of view is not dispalced (as in your case).
First you have to transform the mose position to normalized device coordianates:
w = with of the viewport
h = height of the viewport
x = X position of the mouse
y = Y position ot the mouse
ndc_x = 2.0 * x/w - 1.0;
ndc_y = 1.0 - 2.0 * y/h; // invert Y axis
Then you have to converte the normalized device coordinates to view coordinates:
z = z coodinate of the geometry in view space
viewPos.x = -z * ndc_x * aspect * tanFov;
viewPos.y = -z * ndc_y * tanFov;
If you want to check if the mouse hovers over your rectangles, then the code may look like this:
mpos = pygame.mouse.get_pos()
z = 40
ndc = [ 2.0 * mpos[0]/width - 1.0, 1.0 - 2.0 * mpos[1]/height ]
tanFov = math.tan( fov_y * 0.5 * math.pi / 180 )
aspect = width / height
viewPos = [z * ndc[0] * aspect * tanFov, z * ndc[1] * tanFov ]
onRect1 = 1 if (viewPos[0]>=rect1[0][0] and viewPos[0]<=rect1[1][0] and viewPos[1]>=rect1[0][1] and viewPos[1]<=rect1[2][1] ) else 0
onRect2 = 1 if (viewPos[0]>=rect2[0][0] and viewPos[0]<=rect2[1][0] and viewPos[1]>=rect2[0][1] and viewPos[1]<=rect2[2][1] ) else 0
See further:
How to recover view space position given view space depth value and ndc xy
Is it possble get which surface of cube will be click in OpenGL?
OpenGL - Mouse coordinates to Space coordinates
In the following I added the algorithm to your example. If the mouse hovers over an rectangle, then the rectangle is colored in red.
import pygame
from pygame.locals import *
import random
from OpenGL.GL import *
from OpenGL.GLU import *
import math
rect1 = [(-5.125,0,-40),(-3.125,0,-40),(-3.125,5,-40),(-5.125,5,-40),]
rect2 = [(3.125,0,-40),(5.125,0,-40),(5.125,5,-40),(3.125,5,-40)]
edges = ((0,1),(1,2),(2,3),(3,0))
fov_y = 45
width = 320
height = 200
#This draws the rectangles edges
def Target():
mpos = pygame.mouse.get_pos()
z = 40
ndc = [ 2.0 * mpos[0]/width - 1.0, 1.0 - 2.0 * mpos[1]/height ]
tanFov = math.tan( fov_y * 0.5 * math.pi / 180 )
aspect = width / height
viewPos = [z * ndc[0] * aspect * tanFov, z * ndc[1] * tanFov ]
onRect1 = 1 if (viewPos[0]>=rect1[0][0] and viewPos[0]<=rect1[1][0] and viewPos[1]>=rect1[0][1] and viewPos[1]<=rect1[2][1] ) else 0
onRect2 = 1 if (viewPos[0]>=rect2[0][0] and viewPos[0]<=rect2[1][0] and viewPos[1]>=rect2[0][1] and viewPos[1]<=rect2[2][1] ) else 0
glColor3f( 1, 1-onRect1, 1-onRect1 )
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(rect1[vertex])
glEnd()
glColor3f( 1, 1-onRect2, 1-onRect2 )
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(rect2[vertex])
glEnd()
def main():
try:
pygame.init()
display = (width,height)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
glMatrixMode(GL_PROJECTION)
gluPerspective(fov_y, (display[0]/display[1]), .1, 1000)
glMatrixMode(GL_MODELVIEW)
while True:
#iterates through events to check for quits
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
Target()
pygame.display.flip()
pygame.time.wait(100)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
except Exception as e:
print (e)
main()
Extension to the answer
Of course you can also do it the other way around. You can transform the corner points of the rectangle to normalized device coordinates and compare them to the mouse position, in normalized device coordinates.
For this you have to read the projection matrix by glGetFloatv(GL_PROJECTION_MATRIX):
prjMat = (GLfloat * 16)()
glGetFloatv(GL_PROJECTION_MATRIX, prjMat)
And you need a function which transform a 3 dimensional cartesian vector by a projection matrix. This is done by multiplying the vector by the projection matrix, which gives homogeneous clip space coordinates. The normalized device coordinates are calculated by dividing the x, y, and z component by the w component.
def TransformVec3(vecA,mat44):
vecB = [0, 0, 0, 0]
for i0 in range(0, 4):
vecB[i0] = vecA[0] * mat44[0*4+i0] + vecA[1] * mat44[1*4+i0] + vecA[2] * mat44[2*4+i0] + mat44[3*4+i0]
return [vecB[0]/vecB[3], vecB[1]/vecB[3], vecB[2]/vecB[3]]
The following function tests if the mouse position is in an rectangle defined by a lower left and a upper right point (the corner points have to be in view space coordinates):
def TestRec(prjMat, mpos, ll, tr):
ll_ndc = TransformVec3(ll, prjMat)
tr_ndc = TransformVec3(tr, prjMat)
ndc = [ 2.0 * mpos[0]/width - 1.0, 1.0 - 2.0 * mpos[1]/height ]
inRect = 1 if (ndc[0]>=ll_ndc[0] and ndc[0]<=tr_ndc[0] and ndc[1]>=ll_ndc[1] and ndc[1]<=tr_ndc[1] ) else 0
return inRect
Again I added the algorithm to your example. If the mouse hovers over an rectangle, then the rectangle is colored in red.
import pygame
from pygame.locals import *
import random
from OpenGL.GL import *
from OpenGL.GLU import *
import math
rect1 = [(-5.125,0,-40),(-3.125,0,-40),(-3.125,5,-40),(-5.125,5,-40),]
rect2 = [(3.125,0,-40),(5.125,0,-40),(5.125,5,-40),(3.125,5,-40)]
edges = ((0,1),(1,2),(2,3),(3,0))
fov_y = 45
width = 320
height = 200
def TransformVec3(vecA,mat44):
vecB = [0, 0, 0, 0]
for i0 in range(0, 4):
vecB[i0] = vecA[0] * mat44[0*4+i0] + vecA[1] * mat44[1*4+i0] + vecA[2] * mat44[2*4+i0] + mat44[3*4+i0]
return [vecB[0]/vecB[3], vecB[1]/vecB[3], vecB[2]/vecB[3]]
def TestRec(prjMat, mpos, ll, tr):
ll_ndc = TransformVec3(ll, prjMat)
tr_ndc = TransformVec3(tr, prjMat)
ndc = [ 2.0 * mpos[0]/width - 1.0, 1.0 - 2.0 * mpos[1]/height ]
inRect = 1 if (ndc[0]>=ll_ndc[0] and ndc[0]<=tr_ndc[0] and ndc[1]>=ll_ndc[1] and ndc[1]<=tr_ndc[1] ) else 0
return inRect
#This draws the rectangles edges
def Target():
prjMat = (GLfloat * 16)()
glGetFloatv(GL_PROJECTION_MATRIX, prjMat)
mpos = pygame.mouse.get_pos()
onRect1 = TestRec(prjMat, mpos, rect1[0], rect1[2])
onRect2 = TestRec(prjMat, mpos, rect2[0], rect2[2])
glColor3f( 1, 1-onRect1, 1-onRect1 )
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(rect1[vertex])
glEnd()
glColor3f( 1, 1-onRect2, 1-onRect2 )
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(rect2[vertex])
glEnd()
def main():
try:
pygame.init()
display = (width,height)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
glMatrixMode(GL_PROJECTION)
gluPerspective(fov_y, (display[0]/display[1]), .1, 1000)
glMatrixMode(GL_MODELVIEW)
while True:
#iterates through events to check for quits
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
Target()
pygame.display.flip()
pygame.time.wait(100)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
except Exception as e:
print (e)
main()

Categories