def set_uniform(self, name, value): name = name.encode() valtype = type(value) if valtype == bool or valtype == int: glUniform1i(glGetUniformLocation(self.shader, name), int(value)) elif valtype == float: glUniform1f(glGetUniformLocation(self.shader, name), value) # elif valtype == VECTOR2_TYPE: # glUniform2fv(glGetUniformLocation(self.shader, name), 1, value) elif valtype == VECTOR3_TYPE: glUniform3fv(glGetUniformLocation(self.shader, name), 1, c_float(value[0]), c_float(value[1]), c_float(value[2])) elif valtype == VECTOR4_TYPE: glUniform4fv(glGetUniformLocation(self.shader, name), 1, c_float(value[0]), c_float(value[1]), c_float(value[2]), c_float(value[3])) elif valtype == MATRIX3_TYPE: glUniformMatrix3fv( glGetUniformLocation(self.shader, name), 1, GL_FALSE, c_float(value[0][0])) # Should this be value[0][0]? elif valtype == MATRIX4_TYPE: glUniformMatrix4fv( glGetUniformLocation(self.shader, name), 1, GL_FALSE, c_float(value[0][0])) # Should this be value[0][0]?
def send(self): for name, array in iteritems(self): # Attach a shader location value to the array, for quick memory lookup. (gl calls are expensive, for some reason) try: loc = array.loc except AttributeError: shader_id = c_int(0) gl.glGetIntegerv(gl.GL_CURRENT_PROGRAM, byref(shader_id)) if shader_id.value == 0: raise UnboundLocalError( "Shader not bound to OpenGL context--uniform cannot be sent." ) array.loc = gl.glGetUniformLocation(shader_id.value, name.encode('ascii')) loc = array.loc if array.ndim == 2: # Assuming a 4x4 float32 matrix (common for graphics operations) try: pointer = array.pointer except AttributeError: array.pointer = array.ctypes.data_as(POINTER(c_float * 16)).contents pointer = array.pointer gl.glUniformMatrix4fv(loc, 1, True, pointer) else: sendfun = self._sendfuns[array.dtype.kind][ len(array) - 1] # Find correct glUniform function sendfun(loc, *array)
def uniform_matrixf(self, name, mat): ''' Upload uniform matrix, program must be currently bound. ''' loc = self.uniforms.get(name, gl.glGetUniformLocation(self.handle,name)) self.uniforms[name] = loc # Upload the 4x4 floating point matrix gl.glUniformMatrix4fv(loc, 1, False, (ctypes.c_float * 16)(*mat))
def __init__(self, ec, fill_color, line_color, line_width, line_loop): self._ec = ec self._line_width = line_width self._line_loop = line_loop # whether or not lines drawn are looped # initialize program and shaders from pyglet import gl self._program = gl.glCreateProgram() vertex = gl.glCreateShader(gl.GL_VERTEX_SHADER) buf = create_string_buffer(tri_vert.encode('ASCII')) ptr = cast(pointer(pointer(buf)), POINTER(POINTER(c_char))) gl.glShaderSource(vertex, 1, ptr, None) gl.glCompileShader(vertex) _check_log(vertex, gl.glGetShaderInfoLog) fragment = gl.glCreateShader(gl.GL_FRAGMENT_SHADER) buf = create_string_buffer(tri_frag.encode('ASCII')) ptr = cast(pointer(pointer(buf)), POINTER(POINTER(c_char))) gl.glShaderSource(fragment, 1, ptr, None) gl.glCompileShader(fragment) _check_log(fragment, gl.glGetShaderInfoLog) gl.glAttachShader(self._program, vertex) gl.glAttachShader(self._program, fragment) gl.glLinkProgram(self._program) _check_log(self._program, gl.glGetProgramInfoLog) gl.glDetachShader(self._program, vertex) gl.glDetachShader(self._program, fragment) gl.glUseProgram(self._program) # Prepare buffers and bind attributes loc = gl.glGetUniformLocation(self._program, b'u_view') view = ec.window_size_pix view = np.diag([2. / view[0], 2. / view[1], 1., 1.]) view[-1, :2] = -1 view = view.astype(np.float32).ravel() gl.glUniformMatrix4fv(loc, 1, False, (c_float * 16)(*view)) self._counts = dict() self._colors = dict() self._buffers = dict() self._points = dict() self._tris = dict() for kind in ('line', 'fill'): self._counts[kind] = 0 self._colors[kind] = (0., 0., 0., 0.) self._buffers[kind] = dict(array=gl.GLuint()) gl.glGenBuffers(1, pointer(self._buffers[kind]['array'])) self._buffers['fill']['index'] = gl.GLuint() gl.glGenBuffers(1, pointer(self._buffers['fill']['index'])) gl.glUseProgram(0) self.set_fill_color(fill_color) self.set_line_color(line_color)
def draw(self, uniforms, entity, models, textures=(), color=(1.0, 1.0, 1.0), *args, **kwargs): glUseProgram(self) glDisable(GL_DEPTH_TEST) # Draw objects once as invisible to set stencil values. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) # Don't write any color values to color buffer. glStencilMask(0xFF) # Enable writing. model = models[entity.model] model.positions.enable() model.indices.enable() self.uniforms[b'perspective'].load( uniforms.get(b'perspective').ctypes.data_as(POINTER(GLfloat))) self.uniforms[b'view'].load( uniforms.get(b'view').ctypes.data_as(POINTER(GLfloat))) self.uniforms[b'color'].load(*color) entity.get_transformation_matrix( location=self.uniforms[b'transformation']) model.draw() # Draw again with larger model. glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) glStencilFunc(GL_NOTEQUAL, 1, 0xFF) # Update with 1's where the objects are rendered. glStencilMask( 0x00 ) # Value that AND's the value written to buffer. 0x00 basically disables writing to stencil. glUniformMatrix4fv( self.uniforms[b'transformation'], 1, GL_TRUE, create_transformation_matrix( *entity._location, *entity.rotation, *(entity.scale + 0.05)).ctypes.data_as(POINTER(GLfloat))) model.draw() glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) glDisableVertexAttribArray(0) glEnable(GL_DEPTH_TEST) glStencilMask(0xFF)
def uniform_matrixf(self, name: str, mat: mat4): # upload a uniform matrix # works with matrices stored as lists, # as well as euclid matrices # obtain the uniform location location = glGetUniformLocation(self.handle, bytes(name, "utf-8")) # upload the 4x4 floating point matrix mat_values = (c_float * 16)(*mat.to_list()) # noinspection PyCallingNonCallable, PyTypeChecker glUniformMatrix4fv(location, 1, True, mat_values)
def _draw_mouse_cursor(self): """ If the mouse is over the image, draw a cursom crosshair. """ if self.mouse_position is None: return x, y = self.mouse_position w, h = self.get_size() vm = self._make_cursor_view_matrix(x, y) with self.mouse_texture: gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, (gl.GLfloat * 16)(*vm)) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) gl.glBlendFunc(gl.GL_ONE, gl.GL_ZERO)
def _draw_mouse_cursor(self): """ If the mouse is over the image, draw a cursor crosshair. """ if self.mouse_position is None: return x, y = self.mouse_position tw, th = self.mouse_texture.size gl.glViewport(x - tw, y - th - 1, tw * 2 + 1, th * 2 + 1) with self.vao, self.copy_program: with self.mouse_texture: gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, EYE4) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) gl.glBlendFunc(gl.GL_ONE, gl.GL_ZERO) ww, wh = self.get_pixel_aligned_size() gl.glViewport(0, 0, int(ww), int(wh))
def send(self): """ Sends all the key-value pairs to the graphics card. These uniform variables will be available in the currently-bound shader. """ for name, array in iteritems(self): shader_id = c_int(0) gl.glGetIntegerv(gl.GL_CURRENT_PROGRAM, byref(shader_id)) if shader_id.value == 0: raise UnboundLocalError( """Shader not bound to OpenGL context--uniform cannot be sent. ------------ Tip ------------- with ratcave.default_shader: mesh.draw() ------------------------------ """) # Attach a shader location value to the array, for quick memory lookup. (gl calls are expensive, for some reason) try: loc, shader_id_for_array = array.loc if shader_id.value != shader_id_for_array: raise Exception( 'Uniform location bound to a different shader') except (AttributeError, Exception) as e: array.loc = (gl.glGetUniformLocation(shader_id.value, name.encode('ascii')), shader_id.value) if array.ndim == 2: # Assuming a 4x4 float32 matrix (common for graphics operations) try: pointer = array.pointer except AttributeError: array.pointer = array.ctypes.data_as(POINTER(c_float * 16)).contents pointer = array.pointer gl.glUniformMatrix4fv(array.loc[0], 1, True, pointer) else: sendfun = self._sendfuns[array.dtype.kind][ len(array) - 1] # Find correct glUniform function sendfun(array.loc[0], *array)
def draw(self, uniforms, entities, models, textures=(), lights=(), *args, **kwargs): glUseProgram(self) # PREPARE SHADER glUniformMatrix4fv( # ctypes.data_as must be here and not at initialization. self.uniforms[b'perspective'], 1, GL_TRUE, uniforms.get(b'perspective').ctypes.data_as(POINTER(GLfloat)) ) glUniformMatrix4fv( self.uniforms[b'view'], 1, GL_TRUE, uniforms.get(b'view').ctypes.data_as(POINTER(GLfloat)) ) for i, entity in enumerate(lights): glUniform3f(self.uniforms[b'light[' + bytes(str(i), 'utf-8') + b'].position'], *entity.location) glUniform3f(self.uniforms[b'light[' + bytes(str(i), 'utf-8') + b'].color'], *entity.color) glUniform1f(self.uniforms[b'light[' + bytes(str(i), 'utf-8') + b'].constant'], entity.attenuation[0]) glUniform1f(self.uniforms[b'light[' + bytes(str(i), 'utf-8') + b'].linear'], entity.attenuation[1]) glUniform1f(self.uniforms[b'light[' + bytes(str(i), 'utf-8') + b'].quadratic'], entity.attenuation[1]) # PREPARE MODELS for model_index, texture_mapping in self.entities.items(): model = models[model_index] model.enable() # PREPARE TEXTURES glActiveTexture(GL_TEXTURE0) glActiveTexture(GL_TEXTURE0 + 1) for texture_list, entity_list in texture_mapping.items(): if hasattr(texture_list, '__iter__'): glBindTexture(GL_TEXTURE_2D, textures[0]) glUniform1i(self.uniforms[b'diffuse_texture'], 0) glBindTexture(GL_TEXTURE_2D, textures[1]) glUniform1i(self.uniforms[b'specular_texture'], 1) # textures[0].enable(slot=0) # textures[1].enable(slot=1) else: textures[texture_list].enable(slot=0) glUniform1i(self.uniforms[b'diffuse_texture'], 0) # PREPARE ENTITIES for entity in entity_list: glUniformMatrix4fv( self.uniforms[b'transformation'], 1, GL_TRUE, entity.get_transformation_matrix().ctypes.data_as(POINTER(GLfloat)) ) model.draw() glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) glBindTexture(GL_TEXTURE_2D, 0) glDisableVertexAttribArray(0) glDisableVertexAttribArray(1) glDisableVertexAttribArray(2)
def draw(self, uniforms, entities, models, *args, **kwargs): glUseProgram(self) glUniformMatrix4fv( self.uniforms[b'perspective'], 1, GL_TRUE, uniforms.get(b'perspective').ctypes.data_as(POINTER(GLfloat)) ) glUniformMatrix4fv( self.uniforms[b'view'], 1, GL_TRUE, uniforms.get(b'view').ctypes.data_as(POINTER(GLfloat)) ) for model_index, entity_list in entities.items(): model = models[model_index] model.enable() for entity in entity_list: glUniformMatrix4fv( self.uniforms[b'transformation'], 1, GL_TRUE, entity.get_transformation_matrix().ctypes.data_as(POINTER(GLfloat)) ) glUniform3f(self.uniforms[b'color'], *entity.color) model.draw() glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) glBindTexture(GL_TEXTURE_2D, 0) glDisableVertexAttribArray(0)
def _render_view(self): gl.glClearBufferfv(gl.GL_COLOR, 0, (gl.GLfloat * 4)(0.25, 0.25, 0.25, 1)) if not self.view: return w, h, d = self.view.shape size = w, h window_size = self.get_size() ob = render_view(self) vm = make_view_matrix(window_size, size, self.zoom, self.offset) vm = (gl.GLfloat * 16)(*vm) gl.glViewport(0, 0, *window_size) self._update_border(self.view.shape) with self.border_vao, self.line_program: gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, vm) r, g, b, a = self.drawing.palette.colors[ 0] # Color 0 is currently hardcoded background gl.glUniform3f(1, r / 256, g / 256, b / 256) gl.glDrawArrays(gl.GL_TRIANGLE_FAN, 0, 4) with self.vao, self.copy_program: # Draw the actual drawing with ob["color"]: gl.glEnable(gl.GL_BLEND) gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, (gl.GLfloat * 16)(*vm)) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) self._draw_mouse_cursor() with self.border_vao, self.line_program: gl.glUniform3f(1, 0., 0., 0.) gl.glLineWidth(1) gl.glDrawArrays(gl.GL_LINE_LOOP, 0, 4)
def render(self, position, chunk_meshes): gl.glViewport(0, 0, *self.size) gl.glDisable(gl.GL_BLEND) gl.glDisable(gl.GL_ALPHA_TEST) gl.glEnable(gl.GL_CULL_FACE) gl.glEnable(gl.GL_DEPTH_TEST) gl.glDepthFunc(gl.GL_LEQUAL) gl.glDepthMask(gl.GL_TRUE) x, y, z = position view_matrices = [ Matrix4.new_scale(-1, -1, 1).rotatey(pi / 2).translate(-x, -y, -z), # +X Matrix4.new_scale(-1, -1, 1).rotatey(-pi / 2).translate(-x, -y, -z), # -X Matrix4.new_rotatex(-pi / 2).translate(-x, -y, -z), # +Y Matrix4.new_rotatex(pi / 2).translate(-x, -y, -z), # -Y Matrix4.new_scale(-1, -1, 1).rotatey(pi).translate(-x, -y, -z), # +Z Matrix4.new_scale(-1, -1, 1).translate(-x, -y, -z) # -Z ] model_matrix = Matrix4.new_scale( 1, 1, constants.WALL_TEXTURE_HEIGHT / (constants.WALL_TEXTURE_WIDTH / sqrt(2) * (sqrt(3)))) gl.glUniformMatrix4fv(1, 1, gl.GL_FALSE, gl_matrix(model_matrix)) with self.program, self.name: view_matrix = make_view_matrix_persp(position) gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, gl_matrix(view_matrix)) for chunk, mesh in chunk_meshes.items(): mesh.draw()
def display_update(self): assert self.player is not None self.switch_to() if self.walls is None: self.build_walls() # view if self.cummulative_time >= self.target_time: pc = self.target_camera else: pc = self.target_camera - self.delta_camera * ( max(self.target_time - self.cummulative_time, 0.0) / self.delta_time) camera = pyrr.vector3.create( pc[0] + 0.5, (self.ground_level + self.wall_level) / 2.0, -pc[1] - 0.5, dtype=np.float32, ) direction = pyrr.vector3.create(-np.sin(pc[2]), 0.0, np.cos(pc[2])) view = look_at(camera, direction=direction) transform = view # then project projection = pyrr.matrix44.create_perspective_projection_matrix( 90.0, self.width / self.height, 0.1, 1000.0, dtype=np.float32).T transform = np.dot(projection, transform) gl.glUniformMatrix4fv( self.transform_loc, # location 1, # count gl.GL_TRUE, # Numpy uses Row-Dominant, OpenGL used Column-Dominant (gl.GLfloat * transform.size)(*transform.flatten()), ) # value
def __set_uniforms(self): # projection matrix (proj) proj_loc = gl.glGetUniformLocation(self.__prog.value, "proj") proj_matrix = self.__proj_matrix() proj_matrix_ptr = ct.cast( \ ct.pointer(np.ctypeslib.as_ctypes(proj_matrix)), ct.POINTER(ct.c_float) ) gl.glUniformMatrix4fv(proj_loc, 1, gl.GL_TRUE, proj_matrix_ptr) # voxel spacing voxel_spacing_loc = gl.glGetUniformLocation(self.__prog.value, "voxel_spacing") gl.glUniform3f(voxel_spacing_loc, self.__voxel_spacing[0]*self.__downsample, self.__voxel_spacing[1]*self.__downsample, self.__voxel_spacing[2]*self.__downsample) # voxel size voxel_size_loc = gl.glGetUniformLocation(self.__prog.value, "voxel_size") gl.glUniform3f(voxel_size_loc, self.__voxel_size[0]*self.__downsample, self.__voxel_size[1]*self.__downsample, self.__voxel_size[2]*self.__downsample) # data; not technically a "uniform" but a texture data_loc = gl.glGetUniformLocation(self.__prog.value, "data") gl.glUniform1i(data_loc, 0) gl.glActiveTexture(gl.GL_TEXTURE0) gl.glBindTexture(gl.GL_TEXTURE_BUFFER, self.__data_texture.value) # dims dims_loc = gl.glGetUniformLocation(self.__prog.value, "dims") gl.glUniform3i(dims_loc, self.__data.shape[0]/self.__downsample, self.__data.shape[1]/self.__downsample, self.__data.shape[2]/self.__downsample) # global_opacity global_opacity_loc = gl.glGetUniformLocation(self.__prog.value, "global_opacity") gl.glUniform1f(global_opacity_loc, self.__opacity) # min value min_value_loc = gl.glGetUniformLocation(self.__prog.value, "min_value") gl.glUniform1f(min_value_loc, self.__min_value) # saturation value saturation_value_loc = gl.glGetUniformLocation(self.__prog.value, "saturation_value") gl.glUniform1f(saturation_value_loc, self.__saturation_value) # downsample downsample_loc = gl.glGetUniformLocation(self.__prog.value, "downsample") gl.glUniform1i(downsample_loc, self.__downsample)
def uniform_matrix( self, location, matrix): # pass a matrix to the specified location in the program gl.glUniformMatrix4fv(location, 1, gl.GL_FALSE, (gl.GLfloat * 16)(*sum(matrix.data, [])))
def render_view(window): """ Render the current view to a texture. """ drawing = window.drawing view = window.view changed = False # Update the overlay with the current stroke overlay = view.overlay w, h, d = view.shape size = w, h overlay_texture = _get_overlay_texture(size) if overlay.dirty and overlay.lock.acquire(timeout=0.01): rect = overlay.dirty x0, y0, x1, y1 = rect.box() overlay_data = overlay.data[x0:x1, y0:y1].tobytes("F") gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) # Needed for writing 8bit data gl.glTextureSubImage2D(overlay_texture.name, 0, *rect.position, *rect.size, gl.GL_RGBA_INTEGER, gl.GL_UNSIGNED_BYTE, overlay_data) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 4) overlay.dirty = None overlay.lock.release() changed = True # Update the image texture data = drawing.data drawing_texture = _get_3d_texture(data.shape) if drawing.dirty: with drawing.lock: update_data = data[drawing.dirty].tobytes(order="F") sx, sy, sz = drawing.dirty drawing.dirty = None sw = sx.stop - sx.start sh = sy.stop - sy.start sd = sz.stop - sz.start gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) # Needed for writing 8bit data gl.glTextureSubImage3D(drawing_texture.name, 0, sx.start, sy.start, sz.start, sw, sh, sd, gl.GL_RED_INTEGER, gl.GL_UNSIGNED_BYTE, update_data) gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 4) changed = True # Render everything to the offscreen buffer # TODO we actually should not have to redraw the offscreen_buffer unless something has changed # (e.g. drawing, overlay, palette or cursor) offscreen_buffer = _get_offscreen_buffer(size) colors = _get_colors(drawing.palette.colors) vao = _get_vao() draw_program = _get_program() empty_texture = _get_empty_texture(size) cursor_pos = d - view.index - 1 # TODO why? other_layer_alpha = 0.3 if view.show_only_current_layer or view.layer_being_switched else 1.0 T = _get_transform(view.rotation) with vao, offscreen_buffer: gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glViewport(0, 0, w, h) gl.glClearBufferfv(gl.GL_COLOR, 0, EMPTY_COLOR) with draw_program, drawing_texture: gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, (gl.GLfloat * 16)(*T)) gl.glUniform3f(1, *view.direction) gl.glUniform4fv(5, 256, colors) # Draw the layers below the current one if cursor_pos < d - 1: with empty_texture: gl.glUniform1f(2, other_layer_alpha) gl.glUniform2i(3, cursor_pos + 1, d) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) # Draw the current layer + overlay with overlay_texture: gl.glUniform1f(2, 1) gl.glUniform2i(3, cursor_pos, cursor_pos + 1) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) # Draw the layers on top if cursor_pos > 0: with empty_texture: gl.glUniform1f(2, other_layer_alpha) gl.glUniform2i(3, 0, cursor_pos) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) return offscreen_buffer
def load_uniform_matrix(self, **uniforms): self._assert_bound() for name, data in uniforms.items(): glUniformMatrix4fv(self.uniform[name], 1, GL_TRUE, data.ctypes.data_as(POINTER(GLfloat)))
def __call__(self, oldpaint, imgui, drawing, brush, altitude: float=-120, azimuth: float=0, spin: bool=False): selection = drawing.selection if selection: size = selection.size depth = len(drawing.layers) colors = drawing.palette.as_tuple() mesh = self._get_mesh(tuple(drawing.layers), selection, colors) if not mesh: # TODO hacky self.texture and self.texture[0].clear() return w, h = size model_matrix = Matrix4.new_translate(-w/2, -h/2, depth/2).scale(1, 1, 1/math.sin(math.pi/3)) far = w*2 near = 0 frust = Matrix4() frust[:] = (2/w, 0, 0, 0, 0, 2/h, 0, 0, 0, 0, -2/(far-near), 0, 0, 0, -(far+near)/(far-near), 1) offscreen_buffer = self._get_buffer(size) with offscreen_buffer, self.program, \ enabled(gl.GL_DEPTH_TEST), disabled(gl.GL_CULL_FACE): azimuth = math.degrees(time()) if spin else azimuth view_matrix = ( Matrix4 # .new_scale(2/w, 2/h, 1/max(w, h)) .new_translate(0, 0, -w) .rotatex(math.radians(altitude)) .rotatez(math.radians(azimuth)) # Rotate over time ) gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, gl_matrix(frust * view_matrix * model_matrix)) gl.glViewport(0, 0, *size) gl.glPointSize(1.0) mesh.draw(mode=gl.GL_POINTS) shadow_buffer = self._get_shadow_buffer(size) with shadow_buffer, self.program, \ enabled(gl.GL_DEPTH_TEST), disabled(gl.GL_CULL_FACE): view_matrix = ( Matrix4 # .new_scale(2/w, 2/h, 1/max(w, h)) .new_translate(0, 0, -5) .rotatex(math.pi) .rotatez(azimuth) # Rotate over time ) gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, gl_matrix(frust * view_matrix * model_matrix)) gl.glViewport(0, 0, *size) gl.glPointSize(1.0) mesh.draw(mode=gl.GL_POINTS) final_buffer = self._get_final_buffer(size) with self._vao, final_buffer, self._copy_program, disabled(gl.GL_CULL_FACE, gl.GL_DEPTH_TEST): with offscreen_buffer["color"], offscreen_buffer["normal"], offscreen_buffer["position"], shadow_buffer["depth"]: gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) # TODO must be careful here so that the texture is always valid # (since imgui may read it at any time) Find a way to ensure this. texture = self._get_texture(size) gl.glCopyImageSubData(final_buffer["color"].name, gl.GL_TEXTURE_2D, 0, 0, 0, 0, texture.name, gl.GL_TEXTURE_2D, 0, 0, 0, 0, w, h, 1) self.texture = texture, size
def on_draw(self): # Prevent trying to draw before things have been set up if not hasattr(self, "offscreen_buffer"): return # Model matrix we'll use to position the main model suzanne_model_matrix = (Matrix4.new_identity().rotatex( -math.pi / 2).rotatez(time())) # Rotate over time plane_model_matrix = Matrix4.new_rotatey(math.pi).translate(0, 0, 2) # Render to an offscreen buffer with self.offscreen_buffer, self.view_program, \ enabled(gl.GL_DEPTH_TEST), disabled(gl.GL_CULL_FACE): gl.glDepthMask(gl.GL_TRUE) w, h = self.size aspect = h / w # Calculate a view frustum; this is basically our camera. near = 5 far = 15 width = 2 height = 2 * aspect frustum = (Matrix4.new(near / width, 0, 0, 0, 0, near / height, 0, 0, 0, 0, -(far + near) / (far - near), -1, 0, 0, -2 * far * near / (far - near), 0)) # The view matrix positions the camera in the scene view_matrix = (Matrix4.new_identity().translate(0, 0, -8)) # Send the matrices to GL gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, gl_matrix(frustum * view_matrix)) gl.glUniformMatrix4fv(1, 1, gl.GL_FALSE, gl_matrix(suzanne_model_matrix)) gl.glUniform4f(2, 0.3, 0.3, 1, 1) # Set the "color" uniform to blue self.suzanne.draw() # We'll also draw a simple plane behind the main model gl.glUniformMatrix4fv(1, 1, gl.GL_FALSE, gl_matrix(plane_model_matrix)) gl.glUniform4f(2, 0.3, 1, 0.3, 1) # Set the "color" uniform to green self.plane.draw(mode=gl.GL_TRIANGLE_STRIP) # Render shadow buffer # Basically the same scene as above, but to a different buffer and from a different view with self.shadow_buffer, self.view_program, enabled( gl.GL_DEPTH_TEST), disabled(gl.GL_CULL_FACE): gl.glDepthMask(gl.GL_TRUE) frustum = Matrix4.new_perspective(1, 1, 1, 12) view_matrix = (Matrix4.new_identity().translate( 0, 0, -4).rotatey(0.5).rotatex(0.3)) light_pos = (view_matrix.inverse() * Point3(0, 0, 0)) light_view_matrix = frustum * view_matrix gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, gl_matrix(light_view_matrix)) gl.glUniformMatrix4fv(1, 1, gl.GL_FALSE, gl_matrix(suzanne_model_matrix)) gl.glUniform4f(2, 0.9, 0.3, 0.4, 1) self.suzanne.draw() gl.glUniformMatrix4fv(1, 1, gl.GL_FALSE, gl_matrix(plane_model_matrix)) self.plane.draw(mode=gl.GL_TRIANGLE_STRIP) # Now draw the offscreen buffer to another buffer, combining it with the # lighting information to get a nice image. # Note: This step is pretty pointless here, as we might just draw directly to screen. # Just demonstrates how to do it. with self.vao, self.offscreen_buffer2, self.lighting_program, disabled( gl.GL_CULL_FACE, gl.GL_DEPTH_TEST): gl.glUniform3f(0, *light_pos) gl.glUniformMatrix4fv(1, 1, gl.GL_FALSE, gl_matrix(light_view_matrix)) # Bind some of the offscreen buffer's textures so the shader can read them. with self.offscreen_buffer["color"], self.offscreen_buffer["normal"], \ self.offscreen_buffer["position"], self.shadow_buffer["depth"]: gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) # Now render the finished image to the screen with self.vao, self.copy_program, disabled(gl.GL_CULL_FACE, gl.GL_DEPTH_TEST): with self.offscreen_buffer2["color"]: gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6)
def on_draw(self): gl.glClearBufferfv(gl.GL_COLOR, 0, BG_COLOR) if self.drawing: window_size = self.get_pixel_aligned_size() w, h = self.drawing.size vm = (gl.GLfloat * 16)(*make_view_matrix( window_size, self.drawing.size, self.zoom, self.offset)) offscreen_buffer = render_drawing(self.drawing, self.highlighted_layer) ww, wh = window_size gl.glViewport(0, 0, int(ww), int(wh)) # Draw a background rectangle with self.vao, self.copy_program: gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, (gl.GLfloat * 16)(*vm)) if self.drawing and self.drawing.grid: with self.get_background_texture( self.drawing.palette.colors[0], 0.9): gw, gh = self.drawing.grid_size gl.glUniform2f(1, w / (gw * 2), h / (gh * 2)) gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) else: #gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) # r, g, b, _ = self.drawing.palette.get_color_as_float(self.drawing.palette.colors[0]) # gl.glClearColor(r, g, b, 1) # TODO should fill with color 0 here! # gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) with self.get_background_texture( self.drawing.palette.colors[0], 1): gw, gh = self.drawing.grid_size gl.glUniform2f(1, w / (gw * 2), h / (gh * 2)) gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) with offscreen_buffer["color"]: gl.glUniform2f(1, 1, 1) gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, vm) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) with self.line_program: with self.border_vao: self.update_border(self.drawing.current.rect) gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, vm) # r, g, b, _ = self.drawing.palette.get_color_as_float(self.drawing.palette.colors[0]) # gl.glUniform3f(1, r, g, b) # gl.glDrawArrays(gl.GL_TRIANGLE_FAN, 0, 4) gl.glUniform3f(1, 0., 0., 0.) gl.glLineWidth(1) gl.glDrawArrays(gl.GL_LINE_LOOP, 0, 4) # Selection rectangle if self.stroke: tool = self.stroke.tool selection = ((tool and tool.show_rect and tool.rect) or self.selection) if selection: self.set_selection(selection) with self.selection_vao: gl.glUniformMatrix4fv(0, 1, gl.GL_FALSE, vm) gl.glUniform3f(1, 1., 1., 0.) gl.glLineWidth(1) gl.glDrawArrays(gl.GL_LINE_LOOP, 0, 4) if not self.tablet.active: self._draw_mouse_cursor() ui.draw_ui(self) gl.glFinish( ) # No double buffering, to minimize latency (does this work?)
def set_uniform_matrix(self, name, mat): location = gl.glGetUniformLocation(self.program, name.encode('ascii')) gl.glUniformMatrix4fv(location, 1, False, (ct.c_float * 16)(*mat))
def uniform_matrix(self, location, matrix): gl.glUniformMatrix4fv(location, 1, gl.GL_FALSE, (gl.GLfloat * 16)(*sum(matrix.data, [])))
def uniform_matrixf(self, name, mat): # Obtian the uniform location loc = gl.glGetUniformLocation(self.handle, name) # Uplaod the 4x4 floating point matrix gl.glUniformMatrix4fv(loc, 1, False, (c_float * 16)(*mat))
def __init__(self): #consider bumping opengl version if apple supports it #amdgpu-mesa currently supports up to 4.5 super(ControledRender, self).__init__(512, 512, fullscreen=False, config=gl.Config(major_version=4, minor_version=1), visible=False) print(self.context.get_info().get_version()) self.vertex_buffer = gl.GLuint(0) self.vao = gl.GLuint(0) #self.prev_program = (gl.GLint * 1)() self.dimx = args["A"].shape[0] self.dimy = args["A"].shape[1] self.dimz = args["A"].shape[2] A = args["A"].astype(np.float32) #print("A shape " + str(A.shape)) #print(str(A.dtype)) #print(A) #self.dp = self.tdata.ctypes.data_as(ctypes.POINTER(ctypes.c_void_p)) self.Ap = A.ctypes.data_as(ctypes.POINTER(ctypes.c_void_p)) T = args["transform"].astype(np.float32) self.Tp = T.ctypes.data_as(ctypes.POINTER(ctypes.c_float)) self.setupFBOandTextures() self.setupShaders() data = [ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ] dataGl = (gl.GLfloat * len(data))(*data) gl.glGenBuffers(1, ctypes.byref(self.vertex_buffer)) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertex_buffer) gl.glBufferData(gl.GL_ARRAY_BUFFER, len(dataGl) * 4, dataGl, gl.GL_STATIC_DRAW) gl.glGenVertexArrays(1, ctypes.byref(self.vao)) gl.glBindVertexArray(self.vao) gl.glUseProgram(self.programA) self.pos_posA = gl.glGetAttribLocation( self.programA, ctypes.create_string_buffer(b"a_position")) assert (self.pos_posA >= 0) gl.glEnableVertexAttribArray(self.pos_posA) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertex_buffer) gl.glVertexAttribPointer(self.pos_posA, 2, gl.GL_FLOAT, False, 0, 0) self.tex_pos_A = gl.glGetUniformLocation(self.programA, b"A") self.transform_pos = gl.glGetUniformLocation( self.programA, b"transform") self.step_pos_A = gl.glGetUniformLocation(self.programA, b"step") self.slice_pos_A = gl.glGetUniformLocation(self.programA, b"slice") self.checkUniformLocation(self.tex_pos_A) self.checkUniformLocation(self.transform_pos) self.checkUniformLocation(self.step_pos_A) self.checkUniformLocation(self.slice_pos_A) gl.glUniformMatrix4fv(self.transform_pos, 1, True, self.Tp) #gl.glUniformMatrix4fv(self.transform_pos, 1, False, self.Tp) #may need changed for nonsquare textures gl.glUniform1f(self.step_pos_A, 1 / self.dimx) gl.glViewport(0, 0, self.dimx, self.dimy)
def uniform_matrixf(self, name, mat): # obtian the uniform location loc = GL.glGetUniformLocation(self.Handle, name) # uplaod the 4x4 floating point matrix GL.glUniformMatrix4fv(loc, 1, False, (ctypes.c_float * 16)(*mat))
def render(self, draw_data): # perf: local for faster access io = self.io display_width, display_height = io.display_size fb_width = int(display_width * io.display_fb_scale[0]) fb_height = int(display_height * io.display_fb_scale[1]) if fb_width == 0 or fb_height == 0: return draw_data.scale_clip_rects(*io.display_fb_scale) # backup GL state # todo: provide cleaner version of this backup-restore code last_program = gl.GLint() gl.glGetIntegerv(gl.GL_CURRENT_PROGRAM, byref(last_program)) last_texture = gl.GLint() gl.glGetIntegerv(gl.GL_TEXTURE_BINDING_2D, byref(last_texture)) last_active_texture = gl.GLint() gl.glGetIntegerv(gl.GL_ACTIVE_TEXTURE, byref(last_active_texture)) last_array_buffer = gl.GLint() gl.glGetIntegerv(gl.GL_ARRAY_BUFFER_BINDING, byref(last_array_buffer)) last_element_array_buffer = gl.GLint() gl.glGetIntegerv(gl.GL_ELEMENT_ARRAY_BUFFER_BINDING, byref(last_element_array_buffer)) last_vertex_array = gl.GLint() gl.glGetIntegerv(gl.GL_VERTEX_ARRAY_BINDING, byref(last_vertex_array)) last_blend_src = gl.GLint() gl.glGetIntegerv(gl.GL_BLEND_SRC, byref(last_blend_src)) last_blend_dst = gl.GLint() gl.glGetIntegerv(gl.GL_BLEND_DST, byref(last_blend_dst)) last_blend_equation_rgb = gl.GLint() gl.glGetIntegerv(gl.GL_BLEND_EQUATION_RGB, byref(last_blend_equation_rgb)) last_blend_equation_alpha = gl.GLint() gl.glGetIntegerv(gl.GL_BLEND_EQUATION_ALPHA, byref(last_blend_equation_alpha)) last_viewport = (gl.GLint*4)() gl.glGetIntegerv(gl.GL_VIEWPORT, last_viewport) last_scissor_box = (gl.GLint*4)() gl.glGetIntegerv(gl.GL_SCISSOR_BOX, last_scissor_box) last_enable_blend = gl.GLint() gl.glIsEnabled(gl.GL_BLEND, byref(last_enable_blend)) last_enable_cull_face = gl.GLint() gl.glIsEnabled(gl.GL_CULL_FACE, byref(last_enable_cull_face)) last_enable_depth_test = gl.GLint() gl.glIsEnabled(gl.GL_DEPTH_TEST, byref(last_enable_depth_test)) last_enable_scissor_test = gl.GLint() gl.glIsEnabled(gl.GL_SCISSOR_TEST, byref(last_enable_scissor_test)) gl.glEnable(gl.GL_BLEND) gl.glBlendEquation(gl.GL_FUNC_ADD) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glDisable(gl.GL_CULL_FACE) gl.glDisable(gl.GL_DEPTH_TEST) gl.glEnable(gl.GL_SCISSOR_TEST) gl.glActiveTexture(gl.GL_TEXTURE0) gl.glViewport(0, 0, int(fb_width), int(fb_height)) ortho_projection = [ 2.0/display_width, 0.0, 0.0, 0.0, 0.0, 2.0/-display_height, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0 ] gl.glUseProgram(self._shader_handle) gl.glUniform1i(self._attrib_location_tex, 0) gl.glUniformMatrix4fv(self._attrib_proj_mtx, 1, gl.GL_FALSE, (gl.GLfloat * 16)(*ortho_projection)) gl.glBindVertexArray(self._vao_handle) for commands in draw_data.commands_lists: idx_buffer_offset = 0 gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._vbo_handle) # todo: check this (sizes) gl.glBufferData(gl.GL_ARRAY_BUFFER, commands.vtx_buffer_size * imgui.VERTEX_SIZE, c_void_p(commands.vtx_buffer_data), gl.GL_STREAM_DRAW) gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._elements_handle) # todo: check this (sizes) gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, commands.idx_buffer_size * imgui.INDEX_SIZE, c_void_p(commands.idx_buffer_data), gl.GL_STREAM_DRAW) # todo: allow to iterate over _CmdList for command in commands.commands: gl.glBindTexture(gl.GL_TEXTURE_2D, command.texture_id) # todo: use named tuple x, y, z, w = command.clip_rect gl.glScissor(int(x), int(fb_height - w), int(z - x), int(w - y)) if imgui.INDEX_SIZE == 2: gltype = gl.GL_UNSIGNED_SHORT else: gltype = gl.GL_UNSIGNED_INT gl.glDrawElements(gl.GL_TRIANGLES, command.elem_count, gltype, c_void_p(idx_buffer_offset)) idx_buffer_offset += command.elem_count * imgui.INDEX_SIZE # restore modified GL state gl.glUseProgram(cast((c_int*1)(last_program), POINTER(c_uint)).contents) gl.glActiveTexture(cast((c_int*1)(last_active_texture), POINTER(c_uint)).contents) gl.glBindTexture(gl.GL_TEXTURE_2D, cast((c_int*1)(last_texture), POINTER(c_uint)).contents) gl.glBindVertexArray(cast((c_int*1)(last_vertex_array), POINTER(c_uint)).contents) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, cast((c_int*1)(last_array_buffer), POINTER(c_uint)).contents) gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, cast((c_int*1)(last_element_array_buffer), POINTER(c_uint)).contents) gl.glBlendEquationSeparate(cast((c_int*1)(last_blend_equation_rgb), POINTER(c_uint)).contents, cast((c_int*1)(last_blend_equation_alpha), POINTER(c_uint)).contents) gl.glBlendFunc(cast((c_int*1)(last_blend_src), POINTER(c_uint)).contents, cast((c_int*1)(last_blend_dst), POINTER(c_uint)).contents) if last_enable_blend: gl.glEnable(gl.GL_BLEND) else: gl.glDisable(gl.GL_BLEND) if last_enable_cull_face: gl.glEnable(gl.GL_CULL_FACE) else: gl.glDisable(gl.GL_CULL_FACE) if last_enable_depth_test: gl.glEnable(gl.GL_DEPTH_TEST) else: gl.glDisable(gl.GL_DEPTH_TEST) if last_enable_scissor_test: gl.glEnable(gl.GL_SCISSOR_TEST) else: gl.glDisable(gl.GL_SCISSOR_TEST) gl.glViewport(last_viewport[0], last_viewport[1], last_viewport[2], last_viewport[3]) gl.glScissor(last_scissor_box[0], last_scissor_box[1], last_scissor_box[2], last_scissor_box[3])
def __call__(self, voxpaint, drawing, altitude: float = 120, azimuth: float = 45, spin: bool = False): size = drawing.size depth = drawing.shape[2] colors = drawing.palette.colors x = math.sin(math.pi / 3) altitude = math.radians(altitude) azimuth = math.radians(azimuth) mesh = self._get_mesh(drawing, drawing.version, drawing.hidden_layers_by_axis) if not mesh: # TODO hacky self.texture and self.texture[0].clear() return w, h = size vw = int(w * math.sqrt(2)) vh = int(h + math.sqrt(2) * h // 2) view_size = (vw, vh) model_matrix = (Matrix4.new_scale(1, 1, 1 / x).translate( -w // 2, -h // 2, depth // 2 - 1 / 2)) far = w * 2 near = -w * 2 frust = Matrix4() frust[:] = (2 / vw, 0, 0, 0, 0, 2 / vh, 0, 0, 0, 0, -2 / (far - near), 0, 0, 0, -(far + near) / (far - near), 1) offscreen_buffer = self._get_buffer(view_size) with offscreen_buffer, self.program, \ enabled(gl.GL_DEPTH_TEST), disabled(gl.GL_CULL_FACE): azimuth = time() if spin else azimuth view_matrix = ( Matrix4.new_translate(0, 0, -1).rotatex(altitude).rotatez( azimuth) # Rotate over time ) colors = self._get_colors(colors) gl.glUniform4fv(3, 256, colors) gl.glUniformMatrix4fv( 0, 1, gl.GL_FALSE, gl_matrix(frust * view_matrix * model_matrix)) gl.glViewport(0, 0, vw, vh) gl.glPointSize(1) mesh.draw(mode=gl.GL_POINTS) final_buffer = self._get_final_buffer(view_size) with self._vao, final_buffer, self._copy_program, disabled( gl.GL_CULL_FACE, gl.GL_DEPTH_TEST): with offscreen_buffer["color"], offscreen_buffer[ "normal"], offscreen_buffer["position"]: gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) # TODO must be careful here so that the texture is always valid # (since imgui may read it at any time) Find a way to ensure this. texture = self._get_texture(view_size) gl.glCopyImageSubData(final_buffer["color"].name, gl.GL_TEXTURE_2D, 0, 0, 0, 0, texture.name, gl.GL_TEXTURE_2D, 0, 0, 0, 0, vw, vh, 1) self.texture = texture, view_size
def uniform_matrixf(self, name, mat, loc=None): """Send 4x4 NumPy matrix data as a uniform to the shader, named 'name'. Shader must be already bound.""" # obtain the uniform location if not loc: loc = self.get_uniform_location(name) gl.glUniformMatrix4fv(loc, 1, False, (c_float * 16)(*mat)) # uplaod the 4x4 floating point matrix
def _umat4(uniform, matrix): data_array = (gl.GLfloat * 16)(*matrix[:]) gl.glUniformMatrix4fv(uniform, 1, gl.GL_FALSE, data_array)
GLint: glGetUniformiv } UNIFORMS_DATA = { # TypeIndentifier: (c_type, buffer_length, setter, [matrix_size]) GL_FLOAT: (GLfloat, 1, glUniform1fv), GL_FLOAT_VEC2: (GLfloat, 2, glUniform2fv), GL_FLOAT_VEC3: (GLfloat, 3, glUniform3fv), GL_FLOAT_VEC4: (GLfloat, 4, glUniform4fv), GL_INT: (GLint, 1, glUniform1iv), GL_INT_VEC2: (GLint, 2, glUniform2iv), GL_INT_VEC3: (GLint, 3, glUniform3iv), GL_INT_VEC4: (GLint, 4, glUniform4iv), GL_FLOAT_MAT2: (GLfloat, 4, lambda x,y,z: glUniformMatrix2fv(x,y,TRANSPOSE_MATRIX,z), (2,2)), GL_FLOAT_MAT3: (GLfloat, 9, lambda x,y,z: glUniformMatrix3fv(x,y,TRANSPOSE_MATRIX,z), (3,3)), GL_FLOAT_MAT4: (GLfloat, 16, lambda x,y,z: glUniformMatrix4fv(x,y,TRANSPOSE_MATRIX,z), (4,4)), GL_FLOAT_MAT2x3: (GLfloat, 6, lambda x,y,z: glUniformMatrix2x3fv(x,y,TRANSPOSE_MATRIX,z), (2,3)), GL_FLOAT_MAT2x4: (GLfloat, 8, lambda x,y,z: glUniformMatrix2x4fv(x,y,TRANSPOSE_MATRIX,z), (2,4)), GL_FLOAT_MAT3x2: (GLfloat, 6, lambda x,y,z: glUniformMatrix3x2fv(x,y,TRANSPOSE_MATRIX,z), (3,2)), GL_FLOAT_MAT3x4: (GLfloat, 12, lambda x,y,z: glUniformMatrix3x4fv(x,y,TRANSPOSE_MATRIX,z), (3,4)), GL_FLOAT_MAT4x2: (GLfloat, 8, lambda x,y,z: glUniformMatrix4x2fv(x,y,TRANSPOSE_MATRIX,z), (4,2)), GL_FLOAT_MAT4x3: (GLfloat, 12, lambda x,y,z: glUniformMatrix4x3fv(x,y,TRANSPOSE_MATRIX,z), (4,3)), } UNPACK_ARRAY = [GL_FLOAT, GL_INT] to_seq = lambda x: x if isinstance(x, Sequence) else [x] def as_matrix(values, size): "Transform a flat list into a matrix" row, col = size
GL_FLOAT_VEC2: (GLfloat, 2, glUniform2fv), GL_FLOAT_VEC3: (GLfloat, 3, glUniform3fv), GL_FLOAT_VEC4: (GLfloat, 4, glUniform4fv), GL_INT: (GLint, 1, glUniform1iv), GL_INT_VEC2: (GLint, 2, glUniform2iv), GL_INT_VEC3: (GLint, 3, glUniform3iv), GL_INT_VEC4: (GLint, 4, glUniform4iv), GL_FLOAT_MAT2: (GLfloat, 4, lambda x, y, z: glUniformMatrix2fv(x, y, TRANSPOSE_MATRIX, z), (2, 2)), GL_FLOAT_MAT3: (GLfloat, 9, lambda x, y, z: glUniformMatrix3fv(x, y, TRANSPOSE_MATRIX, z), (3, 3)), GL_FLOAT_MAT4: (GLfloat, 16, lambda x, y, z: glUniformMatrix4fv(x, y, TRANSPOSE_MATRIX, z), (4, 4)), GL_FLOAT_MAT2x3: (GLfloat, 6, lambda x, y, z: glUniformMatrix2x3fv(x, y, TRANSPOSE_MATRIX, z), (2, 3)), GL_FLOAT_MAT2x4: (GLfloat, 8, lambda x, y, z: glUniformMatrix2x4fv(x, y, TRANSPOSE_MATRIX, z), (2, 4)), GL_FLOAT_MAT3x2: (GLfloat, 6, lambda x, y, z: glUniformMatrix3x2fv(x, y, TRANSPOSE_MATRIX, z), (3, 2)), GL_FLOAT_MAT3x4: (GLfloat, 12, lambda x, y, z: glUniformMatrix3x4fv(x, y, TRANSPOSE_MATRIX, z), (3, 4)), GL_FLOAT_MAT4x2: (GLfloat, 8, lambda x, y, z: glUniformMatrix4x2fv(x, y, TRANSPOSE_MATRIX, z), (4, 2)),
def uniform_matrix(self, location, matrix): gl.glUniformMatrix4fv(location, 1, gl.GL_FALSE, glm.value_ptr(matrix))