Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from pyglet.window import Window, key
- from pyglet.graphics import vertex_list, Batch
- from pyglet import app, clock, gl
- from pyglet.gl import *
- from ctypes import *
- import pymunk
- from pymunk import Vec2d
- from mathutils import Matrix, Vector
- from math import radians
- from random import choice, randint
- #The vertex shader
- vertex_shader = b'''
- uniform mat4 translation;
- uniform mat4 orientation;
- void main()
- {
- vec4 pos = gl_Vertex*orientation*translation;
- gl_Position = gl_ModelViewProjectionMatrix*pos;
- }
- '''
- #The fragment shader
- frag_shader = b'''
- uniform vec4 color;
- void main()
- {
- gl_FragColor = color;
- }
- '''
- class Shader:
- #
- # Copyright Tristam Macdonald 2008.
- #
- # Distributed under the Boost Software License, Version 1.0
- # (see http://www.boost.org/LICENSE_1_0.txt)
- #
- # vert, frag and geom take arrays of source strings
- # the arrays will be concattenated into one string by OpenGL
- def __init__(self, vert = [], frag = [], geom = []):
- # create the program handle
- self.handle = glCreateProgram()
- # we are not linked yet
- self.linked = False
- # create the vertex shader
- self.createShader(vert, GL_VERTEX_SHADER)
- # create the fragment shader
- self.createShader(frag, GL_FRAGMENT_SHADER)
- # the geometry shader will be the same, once pyglet supports the extension
- # self.createShader(frag, GL_GEOMETRY_SHADER_EXT)
- # attempt to link the program
- self.link()
- def createShader(self, strings, type):
- count = len(strings)
- # if we have no source code, ignore this shader
- if count < 1:
- return
- # create the shader handle
- shader = glCreateShader(type)
- # convert the source strings into a ctypes pointer-to-char array, and upload them
- # this is deep, dark, dangerous black magick - don't try stuff like this at home!
- src = (c_char_p * count)(*strings)
- glShaderSource(shader, count, cast(pointer(src), POINTER(POINTER(c_char))), None)
- # compile the shader
- glCompileShader(shader)
- temp = c_int(0)
- # retrieve the compile status
- glGetShaderiv(shader, GL_COMPILE_STATUS, byref(temp))
- # if compilation failed, print the log
- if not temp:
- # retrieve the log length
- glGetShaderiv(shader, GL_INFO_LOG_LENGTH, byref(temp))
- # create a buffer for the log
- buffer = create_string_buffer(temp.value)
- # retrieve the log text
- glGetShaderInfoLog(shader, temp, None, buffer)
- # print the log to the console
- print (buffer.value)
- else:
- # all is well, so attach the shader to the program
- glAttachShader(self.handle, shader);
- def link(self):
- # link the program
- glLinkProgram(self.handle)
- temp = c_int(0)
- # retrieve the link status
- glGetProgramiv(self.handle, GL_LINK_STATUS, byref(temp))
- # if linking failed, print the log
- if not temp:
- # retrieve the log length
- glGetProgramiv(self.handle, GL_INFO_LOG_LENGTH, byref(temp))
- # create a buffer for the log
- buffer = create_string_buffer(temp.value)
- # retrieve the log text
- glGetProgramInfoLog(self.handle, temp, None, buffer)
- # print the log to the console
- print (buffer.value)
- else:
- # all is well, so we are linked
- self.linked = True
- def bind(self):
- # bind the program
- glUseProgram(self.handle)
- def unbind(self):
- # unbind whatever program is currently bound - not necessarily this program,
- # so this should probably be a class method instead
- glUseProgram(0)
- # upload a floating point uniform
- # this program must be currently bound
- def uniformf(self, name, *vals):
- # check there are 1-4 values
- if len(vals) in range(1, 5):
- # select the correct function
- { 1 : glUniform1f,
- 2 : glUniform2f,
- 3 : glUniform3f,
- 4 : glUniform4f
- # retrieve the uniform location, and set
- }[len(vals)](glGetUniformLocation(self.handle, name), *vals)
- # upload an integer uniform
- # this program must be currently bound
- def uniformi(self, name, *vals):
- # check there are 1-4 values
- if len(vals) in range(1, 5):
- # select the correct function
- { 1 : glUniform1i,
- 2 : glUniform2i,
- 3 : glUniform3i,
- 4 : glUniform4i
- # retrieve the uniform location, and set
- }[len(vals)](glGetUniformLocation(self.handle, name), *vals)
- # upload a uniform matrix
- # works with matrices stored as lists,
- # as well as euclid matrices
- def uniform_matrixf(self, name, mat):
- # obtian the uniform location
- loc = glGetUniformLocation(self.handle, name)
- # uplaod the 4x4 floating point matrix
- glUniformMatrix4fv(loc, 1, False, (c_float * 16)(*mat))
- class NoCollisionRectangle():
- '''
- An object that wrap the drawings of a rectangle.
- '''
- def __init__(self, x, y, width, height, color=[0,0,0]):
- vertices = [x,y, x+width,y, x+width,y+height, x,y+height]
- self.array = vertex_list(4, ("v2f", vertices), ("c3B", color*4))
- self.position = (x, y)
- self.size = (width, height)
- self.color = color
- self.registered = False
- def move(self, x, y):
- for i in range(4):
- self.array.vertices[i*2] += x
- self.array.vertices[i*2+1] += y
- def draw(self):
- self.array.draw(gl.GL_QUADS)
- def register(self, batch, group=None):
- vertices = list(self.array.vertices)
- colors = list(self.array.colors)
- self.array = batch.add(4, gl.GL_QUADS, group, ("v2f", vertices), ("c3B", colors))
- self.registered = True
- class StaticLine(object):
- '''
- An object that bind drawing and physics of a static line.
- '''
- def __init__(self, start, end, body, color=[0,0,0], friction=0.0):
- '''
- start(suple): A tuple of 2D vertex coordinate. Start point of the line.
- end(tuple): A tuple of 2D vertex coordinate. End point of the line.
- body(pymunk.Body): Pymunk body object
- color(list): List of [red green blue] in bytes. Color of the vertices.
- friction(float): Friction for the physic.
- '''
- vertices = (start[0], start[1], end[0], end[1])
- self.mesh = vertex_list(2, ('v2i', vertices),
- ('c3B', color*2 ))
- self.mesh_physic = pymunk.Segment(body, start, end, 0.0)
- self.friction = friction
- def registerPhysicSpace(self, space):
- space.add(self.mesh_physic)
- def draw(self):
- self.mesh.draw(gl.GL_LINES)
- class DynamicRectangle():
- '''
- An object that wrap the drawings and the physic of a rectangle.
- Instead of being handled by python, the drawing are done in GLSL
- on the GPU.
- '''
- def __init__(self, x, y, width, height, mass = 10, friction=1, color=[0,0,0,1]):
- #Properties
- self.shader = None
- self.color = color
- self.position = Matrix.Translation((x, y, 0.0))
- self.orientation = Matrix.Rotation(radians(0), 4, 'Z')
- #Visual Shape
- w,h = width/2, height/2
- vertices = [-w,-h, w,-h, w,h, -w,h]
- self.array = vertex_list(4, ("v2f", vertices))
- #Physic shape
- moment = pymunk.moment_for_box(mass, w, h)
- self.body = pymunk.Body(mass, moment)
- self.mesh_physic = pymunk.Poly.create_box(self.body, (w,h), radius = w/2)
- self.mesh_physic.friction = friction
- self.body.position = x+w/2, y+h/2
- def registerShader(self, vertex, fragment):
- self.shader = Shader([vertex], [fragment])
- def draw(self):
- def toList(mat):
- final = []
- for vect in mat:
- final+=list(vect)
- return final
- #Update physics
- self.position = Matrix.Translation(list(self.body.position)+[0])
- self.orientation = Matrix.Rotation(self.body.angle, 4, 'Z')
- if self.shader: #Object need a shader to be drawn
- self.shader.bind()
- self.shader.uniformf(b"color", *self.color)
- self.shader.uniform_matrixf(b"translation", toList(self.position))
- self.shader.uniform_matrixf(b"orientation", toList(self.orientation))
- self.array.draw(GL_QUADS)
- self.shader.unbind()
- def registerPhysicSpace(self, space):
- space.add(self.body, self.mesh_physic)
- def applyMovement(self, x, y):
- self.position *= Matrix.Translation((x,y,0))
- def setPosition(self, x,y):
- self.position = Matrix.Translation((x,y,0))
- def applyRotation(self, rot):
- self.orientation *= Matrix.Rotation(radians(rot), 4, 'Z')
- def setOrientation(self, rot):
- self.orientation = Matrix.Rotation(radians(rot), 4, 'Z')
- class Game(Window):
- def __init__(self, **kwargs):
- super(Game, self).__init__(**kwargs)
- self.initGame()
- self.set_visible(True)
- def initGame(self):
- w,h = self.width, self.height
- #Objects Lists
- self.statics = []
- self.dynamics = []
- #Pymunk space
- self.space = pymunk.Space()
- self.space.gravity = Vec2d(0, -900)
- #Pyglet batch
- self.batch = Batch()
- #Background & Ground
- self.background = NoCollisionRectangle(0,0, w,h, color=[255,255,255])
- self.background.register(self.batch)
- #Lines
- body = pymunk.Body()
- l1 = StaticLine((0,50), (w,50), body)
- l2 = StaticLine((30,50), (30,170), body)
- l3 = StaticLine((w-30,50), (w-30,170), body)
- l4 = StaticLine((90,180), (130,100), body)
- self.statics = [l1, l2, l3, l4]
- for i in self.statics:
- i.registerPhysicSpace(self.space)
- def on_draw(self,):
- self.clear()
- self.batch.draw()
- for i in self.statics:
- i.draw()
- for i in self.dynamics:
- i.draw()
- def on_mouse_press(self, x,y, button, mod):
- color = choice([[0,0,0,1], [1,0,0,1], [0,1,0,1], [0,0,1,1], [1,1,0,1], [1,0,1,1],
- [0,1,1,1]])
- size = randint(10, 35)
- if button == 1:
- d = DynamicRectangle(x, y, size, size, color = color)
- d.registerPhysicSpace(self.space)
- d.registerShader(vertex_shader, frag_shader)
- self.dynamics.append(d)
- def update(self, dt):
- dt = 1.0/60.0
- self.space.step(dt) #Physics steps
- self.on_draw()
- if __name__ == '__main__':
- w = Game(caption="Glsl Test", width=500, height=500, visible = False)
- clock.schedule_interval(w.update, 1.0/45.0)
- app.run()
Advertisement
Add Comment
Please, Sign In to add comment