All I want to do is create a really simple pan and zoom feature in 2D with OpenGL through pyglet. As you can see, the zooming is working perfectly after the first jump:( Then again, the dragging (panning) is also working, but it also jumps (and it jumps a pretty big one)..
Here is my simplified code and a video (pyglet_test.mp4) that shows how it behaves:
import pyglet
from pyglet.gl import *
# Zooming constants
ZOOM_IN_FACTOR = 1.2
ZOOM_OUT_FACTOR = 1/ZOOM_IN_FACTOR
class App(pyglet.window.Window):
def __init__(self, width, height, *args, **kwargs):
# Create GL configuration
conf = Config( sample_buffers=1,
samples=4,
depth_size=16,
double_buffer=True )
# Initialize parent
super().__init__( width, height, config=conf, *args, **kwargs )
# Create Group
self.group = group = pyglet.graphics.Group()
# Create Batch
self.batch = batch = pyglet.graphics.Batch()
# Create QUAD for testing and add it to batch
batch.add(
4, GL_QUADS, group,
('v2i', ( -50, -50,
50, -50,
50, 50,
-50, 50 )),
('c3B', ( 255, 0, 0,
255, 255, 0,
0, 255, 0,
0, 0, 255 ))
)
# Initialize OpenGL
self.init_gl()
# Initialize camera values
self.camera_x = 0
self.camera_y = 0
self.camera_zoom = 1
def init_gl(self):
# Set clear color
glClearColor(0/255, 0/255, 0/255, 0/255)
# Set antialiasing
glEnable( GL_LINE_SMOOTH )
glEnable( GL_POLYGON_SMOOTH )
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST )
# Set alpha blending
glEnable( GL_BLEND )
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )
# Set viewport
glViewport( 0, 0, self.width, self.height )
# Initialize Projection matrix
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
# Set orthographic projection matrix
glOrtho( 0, self.width, 0, self.height, 1, -1 )
# Initialize Modelview matrix
glMatrixMode( GL_MODELVIEW )
glLoadIdentity()
# Save the default modelview matrix
glPushMatrix()
def on_resize(self, width, height):
# Initialize OpenGL for new dimensions
self.width = width
self.height = height
self.init_gl()
def camera_matrix(transformations):
# Create camera setter function
def set_camera(self):
# Take saved matrix off the stack and reset it
glMatrixMode( GL_MODELVIEW )
glPopMatrix()
glLoadIdentity()
# Call wrapped function
transformations(self)
# Save default matrix again with camera translation
glPushMatrix()
# Return wrapper function
return set_camera
@camera_matrix
def move_camera(self):
# Move to camera position
glTranslatef( self.camera_x, self.camera_y, 0 )
# Scale camera
glScalef( self.camera_zoom, self.camera_zoom, 1 )
@camera_matrix
def zoom_camera(self):
# Move to camera position
glTranslatef( self.camera_x, self.camera_y, 0 )
# Scale camera
glScalef( self.camera_zoom, self.camera_zoom, 1 )
# Move back from camera position
glTranslatef( -self.camera_x, -self.camera_y, 0 )
def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
# Move camera
self.camera_x += dx
self.camera_y += dy
self.move_camera()
def on_mouse_scroll(self, x, y, dx, dy):
# Get scale factor
f = ZOOM_IN_FACTOR if dy < 0 else ZOOM_OUT_FACTOR if dy > 0 else 1
# If zoom_level is in the proper range
if .2 < self.camera_zoom*f < 5:
# Zoom camera
self.camera_x = x
self.camera_y = y
self.camera_zoom *= f
self.zoom_camera()
def on_draw(self):
# Clear window with ClearColor
glClear( GL_COLOR_BUFFER_BIT )
# Pop default matrix onto current matrix
glMatrixMode( GL_MODELVIEW )
glPopMatrix()
# Save default matrix again
glPushMatrix()
# Move to center of the screen
glTranslatef( self.width/2, self.height/2, 0 )
# Draw objects
self.batch.draw()
def run(self):
pyglet.app.run()
# Create instance of app and run it
App(500, 500).run()
To apply pan-and-zoom to a selected clip on the timeline, in the timeline, right-click the image or video, and choose Pan-and-Zoom or in the Editor panel, click Pan-and-Zoom.
Zooming and panning in AutoCAD can be done entirely with the mouse wheel. Point the cursor to where you would like to zoom and turn the mouse wheel to zoom in and out. You can also pan by clicking and dragging with the mouse wheel, using it as you would a mouse button.
A 'Pan' is when the camera moves between two subjects while filming and a 'Zoom' is when the camera either moves closer or farther to one part of the frame through the use of a zoom lens.
After another day of suffering, I finally found a solution: in 2D the easiest way of doing mouse coordinate (pivot point) based zooming and right clicked-and-dragged panning without the jumps is to change the projection matrix with the glOrtho()
function.
Here is a simplified version of my original code -- if you are using Pyglet with seriuos amount of data, you should consider using Groups and Batches, but for the easier understanding I used the glBegin()
, glColor()
, glVertex()
, glEnd()
functions here to draw.
import pyglet
from pyglet.gl import *
# Zooming constants
ZOOM_IN_FACTOR = 1.2
ZOOM_OUT_FACTOR = 1/ZOOM_IN_FACTOR
class App(pyglet.window.Window):
def __init__(self, width, height, *args, **kwargs):
conf = Config(sample_buffers=1,
samples=4,
depth_size=16,
double_buffer=True)
super().__init__(width, height, config=conf, *args, **kwargs)
#Initialize camera values
self.left = 0
self.right = width
self.bottom = 0
self.top = height
self.zoom_level = 1
self.zoomed_width = width
self.zoomed_height = height
def init_gl(self, width, height):
# Set clear color
glClearColor(0/255, 0/255, 0/255, 0/255)
# Set antialiasing
glEnable( GL_LINE_SMOOTH )
glEnable( GL_POLYGON_SMOOTH )
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST )
# Set alpha blending
glEnable( GL_BLEND )
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )
# Set viewport
glViewport( 0, 0, width, height )
def on_resize(self, width, height):
# Set window values
self.width = width
self.height = height
# Initialize OpenGL context
self.init_gl(width, height)
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
# Move camera
self.left -= dx*self.zoom_level
self.right -= dx*self.zoom_level
self.bottom -= dy*self.zoom_level
self.top -= dy*self.zoom_level
def on_mouse_scroll(self, x, y, dx, dy):
# Get scale factor
f = ZOOM_IN_FACTOR if dy > 0 else ZOOM_OUT_FACTOR if dy < 0 else 1
# If zoom_level is in the proper range
if .2 < self.zoom_level*f < 5:
self.zoom_level *= f
mouse_x = x/self.width
mouse_y = y/self.height
mouse_x_in_world = self.left + mouse_x*self.zoomed_width
mouse_y_in_world = self.bottom + mouse_y*self.zoomed_height
self.zoomed_width *= f
self.zoomed_height *= f
self.left = mouse_x_in_world - mouse_x*self.zoomed_width
self.right = mouse_x_in_world + (1 - mouse_x)*self.zoomed_width
self.bottom = mouse_y_in_world - mouse_y*self.zoomed_height
self.top = mouse_y_in_world + (1 - mouse_y)*self.zoomed_height
def on_draw(self):
# Initialize Projection matrix
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
# Initialize Modelview matrix
glMatrixMode( GL_MODELVIEW )
glLoadIdentity()
# Save the default modelview matrix
glPushMatrix()
# Clear window with ClearColor
glClear( GL_COLOR_BUFFER_BIT )
# Set orthographic projection matrix
glOrtho( self.left, self.right, self.bottom, self.top, 1, -1 )
# Draw quad
glBegin( GL_QUADS )
glColor3ub( 0xFF, 0, 0 )
glVertex2i( 10, 10 )
glColor3ub( 0xFF, 0xFF, 0 )
glVertex2i( 110, 10 )
glColor3ub( 0, 0xFF, 0 )
glVertex2i( 110, 110 )
glColor3ub( 0, 0, 0xFF )
glVertex2i( 10, 110 )
glEnd()
# Remove default modelview matrix
glPopMatrix()
def run(self):
pyglet.app.run()
App(500, 500).run()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With