def _create_device_objects(self): # save state last_texture = gl.GLint() gl.glGetIntegerv(gl.GL_TEXTURE_BINDING_2D, byref(last_texture)) last_array_buffer = gl.GLint() gl.glGetIntegerv(gl.GL_ARRAY_BUFFER_BINDING, byref(last_array_buffer)) last_vertex_array = gl.GLint() gl.glGetIntegerv(gl.GL_VERTEX_ARRAY_BINDING, byref(last_vertex_array)) self._shader_handle = gl.glCreateProgram() # note: no need to store shader parts handles after linking vertex_shader = gl.glCreateShader(gl.GL_VERTEX_SHADER) fragment_shader = gl.glCreateShader(gl.GL_FRAGMENT_SHADER) gl.glShaderSource(vertex_shader, 1, make_string_buffer(self.VERTEX_SHADER_SRC), None) gl.glShaderSource(fragment_shader, 1, make_string_buffer(self.FRAGMENT_SHADER_SRC), None) gl.glCompileShader(vertex_shader) gl.glCompileShader(fragment_shader) gl.glAttachShader(self._shader_handle, vertex_shader) gl.glAttachShader(self._shader_handle, fragment_shader) gl.glLinkProgram(self._shader_handle) # note: after linking shaders can be removed gl.glDeleteShader(vertex_shader) gl.glDeleteShader(fragment_shader) self._attrib_location_tex = gl.glGetUniformLocation(self._shader_handle, create_string_buffer(b"Texture")) self._attrib_proj_mtx = gl.glGetUniformLocation(self._shader_handle, create_string_buffer(b"ProjMtx")) self._attrib_location_position = gl.glGetAttribLocation(self._shader_handle, create_string_buffer(b"Position")) self._attrib_location_uv = gl.glGetAttribLocation(self._shader_handle, create_string_buffer(b"UV")) self._attrib_location_color = gl.glGetAttribLocation(self._shader_handle, create_string_buffer(b"Color")) self._vbo_handle = gl.GLuint() gl.glGenBuffers(1, byref(self._vbo_handle)) self._elements_handle = gl.GLuint() gl.glGenBuffers(1, byref(self._elements_handle)) self._vao_handle = gl.GLuint() gl.glGenVertexArrays(1, byref(self._vao_handle)) gl.glBindVertexArray(self._vao_handle) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._vbo_handle) gl.glEnableVertexAttribArray(self._attrib_location_position) gl.glEnableVertexAttribArray(self._attrib_location_uv) gl.glEnableVertexAttribArray(self._attrib_location_color) gl.glVertexAttribPointer(self._attrib_location_position, 2, gl.GL_FLOAT, gl.GL_FALSE, imgui.VERTEX_SIZE, c_void_p(imgui.VERTEX_BUFFER_POS_OFFSET)) gl.glVertexAttribPointer(self._attrib_location_uv, 2, gl.GL_FLOAT, gl.GL_FALSE, imgui.VERTEX_SIZE, c_void_p(imgui.VERTEX_BUFFER_UV_OFFSET)) gl.glVertexAttribPointer(self._attrib_location_color, 4, gl.GL_UNSIGNED_BYTE, gl.GL_TRUE, imgui.VERTEX_SIZE, c_void_p(imgui.VERTEX_BUFFER_COL_OFFSET)) # restore state gl.glBindTexture(gl.GL_TEXTURE_2D, cast((c_int*1)(last_texture), POINTER(c_uint)).contents) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, cast((c_int*1)(last_array_buffer), POINTER(c_uint)).contents) gl.glBindVertexArray(cast((c_int*1)(last_vertex_array), POINTER(c_uint)).contents)
def get_uniform_data(program): """ Args: program: Returns: """ uniforms = {} count = pointer(GLint()) buffer_size = GLsizei(32) length = GLsizei() size = GLint() data_type = GLenum() uniform_name = c_string('', size=buffer_size.value) glGetProgramiv(program, GL_ACTIVE_UNIFORMS, count) for i in range(count.contents.value): glGetActiveUniform(program, GLuint(i), buffer_size, length, size, data_type, uniform_name) uniform_name_ = uniform_name.value.decode('utf-8') data_type_string = temp[data_type.value] uniforms[uniform_name_] = { 'dtype': table[data_type_string]['dtype'], 'index': i, 'size': size.value, 'value': None, 'location': glGetUniformLocation(program, uniform_name), 'function': table[data_type_string]['function'], } print(uniform_name_, uniforms[uniform_name_]) return uniforms
def draw(self): """Draw the object to the display buffer""" from pyglet import gl gl.glUseProgram(self._program) for kind in ('fill', 'line'): if self._counts[kind] > 0: if kind == 'line': if self._line_width <= 0.0: continue gl.glLineWidth(self._line_width) if self._line_loop: mode = gl.GL_LINE_LOOP else: mode = gl.GL_LINE_STRIP cmd = partial(gl.glDrawArrays, mode, 0, self._counts[kind]) else: gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._buffers[kind]['index']) cmd = partial(gl.glDrawElements, gl.GL_TRIANGLES, self._counts[kind], gl.GL_UNSIGNED_INT, 0) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._buffers[kind]['array']) loc_pos = gl.glGetAttribLocation(self._program, b'a_position') gl.glEnableVertexAttribArray(loc_pos) gl.glVertexAttribPointer(loc_pos, 2, gl.GL_FLOAT, gl.GL_FALSE, 0, 0) loc_col = gl.glGetUniformLocation(self._program, b'u_color') gl.glUniform4f(loc_col, *self._colors[kind]) cmd() # The following line is probably only necessary because # Pyglet makes some assumptions about the GL state that # it perhaps shouldn't. Without it, Text might not # render properly (see #252) gl.glDisableVertexAttribArray(loc_pos) gl.glUseProgram(0)
def set_uniformf(self, name, *vals): location = gl.glGetUniformLocation(self.program, name.encode('ascii')) { 1: gl.glUniform1f, 2: gl.glUniform2f, 3: gl.glUniform3f, 4: gl.glUniform4f }[len(vals)](location, *vals)
def set_uniformi(self, name, *vals): location = gl.glGetUniformLocation(self.program, name.encode('ascii')) { 1: gl.glUniform1i, 2: gl.glUniform2i, 3: gl.glUniform3i, 4: gl.glUniform4i }[len(vals)](location, *vals)
def uniformfv(self, name, size, data): data_ctype = (gl.GLfloat * len(data))(*data) location = gl.glGetUniformLocation(self.program, name.encode('ascii')) {1: gl.glUniform1fv, 2: gl.glUniform2fv, 3: gl.glUniform3fv, 4: gl.glUniform4fv}[len(data) // size](location, size, data_ctype)
def _introspect_uniforms(self): for index in range(self.get_num_active(gl.GL_ACTIVE_UNIFORMS)): uniform_name, u_type, u_size = self.query_uniform(index) loc = gl.glGetUniformLocation(self.prog_id, uniform_name.encode('utf-8')) if loc == -1: # Skip uniforms that may be in Uniform Blocks continue try: gl_type, gl_setter, length, count = _uniform_setters[u_type] except KeyError: raise ShaderException(f"Unsupported Uniform type {u_type}") gl_getter = _uniform_getters[gl_type] is_matrix = u_type in (gl.GL_FLOAT_MAT2, gl.GL_FLOAT_MAT3, gl.GL_FLOAT_MAT4) # Create persistant mini c_array for getters and setters: c_array = (gl_type * length)() ptr = cast(c_array, POINTER(gl_type)) # Create custom dedicated getters and setters for each uniform: getter = _create_getter_func(self.prog_id, loc, gl_getter, c_array, length) setter = _create_setter_func(loc, gl_setter, c_array, length, count, ptr, is_matrix) # print(f"Found uniform: {uniform_name}, type: {u_type}, size: {u_size}, " # f"location: {loc}, length: {length}, count: {count}") self._uniforms[uniform_name] = Uniform(getter, setter)
def uniform2f(self, name, v0, v1): self.use() loc = gl.glGetUniformLocation(self.handle, ctypes.create_string_buffer(name)) if loc < 0: logging.warning('Uniform {} is not in the shader.'.format(name)) return gl.glUniform2f(loc, v0, v1);
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 uniform2f(self, name, v0, v1): self.use() loc = gl.glGetUniformLocation(self.handle, ctypes.create_string_buffer(name)) if loc < 0: logging.warning('Uniform %s is not in the shader.', name) return gl.glUniform2f(loc, v0, v1)
def uniformi(self, name, *data): location = gl.glGetUniformLocation(self.program, name.encode("ascii")) { 1: gl.glUniform1i, 2: gl.glUniform2i, 3: gl.glUniform3i, 4: gl.glUniform4i }[len(data)](location, *data)
def uniformf(self, name, *data): location = gl.glGetUniformLocation(self.program, name.encode("ascii")) { 1: gl.glUniform1f, 2: gl.glUniform2f, 3: gl.glUniform3f, 4: gl.glUniform4f }[len(data)](location, *data)
def uniform1i(self, name, value): self.use() loc = gl.glGetUniformLocation(self.handle, ctypes.create_string_buffer(name)) if loc < 0: logging.warning('Uniform {} is not in the shader.'.format(name)) return gl.glUniform1i(loc, value)
def send_to(self, shader): """Sends uniform to a currently-bound shader, returning its location (-1 means not sent)""" # glGetUniformLocation only needs to be called once, when the shader is linked. Not a big performance boost, though. if type(self.loc) == type(None): self.loc = gl.glGetUniformLocation(shader.id, self.name) self.sendfun(self.loc, *self.value) return self.loc
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 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 uniformf(self, name, *vals): if len(vals) in range(1, 5): # Select the correct function { 1: gl.glUniform1f, 2: gl.glUniform2f, 3: gl.glUniform3f, 4: gl.glUniform4f # Retrieve the uniform location, and set }[len(vals)](gl.glGetUniformLocation(self.handle, name), *vals)
def __init__(self, game_controller, label: str = None): super().__init__(game_controller, label or "Tunnel View 2") gl.glClearColor(0.4, 0.65, 0.8, 1.0) gl.glEnable(gl.GL_DEPTH_TEST) self.ground_level = 0.0 self.wall_level = 0.75 gravel_scale = 3.0 maze = game_controller.maze self.ground = GLShape( np.array( [ ((-1, self.ground_level, 1), (0.0, 0.0)), # 0 ( (-1, self.ground_level, -maze.shape[1] - 1), (0.0, gravel_scale * (maze.shape[1] + 2)), ), # 1 ( (maze.shape[0] + 1, self.ground_level, -maze.shape[1] - 1), ( gravel_scale * (maze.shape[0] + 2), gravel_scale * (maze.shape[1] + 2), ), ), # 2 ( (maze.shape[0] + 1, self.ground_level, 0.0), (gravel_scale * (maze.shape[0] + 2), 0.0), ), ], # 3 dtype=[("position", np.float32, 3), ("texture", np.float32, 2)], ), np.array([0, 1, 2, 3], dtype=np.uint32), gl.GL_QUADS, "gravel.jpg", ) self.walls = None self.egress = None self.program = GLProgram( (GLShader.from_file(*args) for args in ( (gl.GL_VERTEX_SHADER, "tunnel_view.vert.glsl"), (gl.GL_FRAGMENT_SHADER, "tunnel_view.frag.glsl"), )), do_use=True, ) # Uniform self.transform_loc = gl.glGetUniformLocation(self.program.gl_id, b"transform") self.cummulative_time = 0.0
def uniform(self, name, type, count=1): if name not in self.__uniforms: location = gl.glGetUniformLocation( self.__program, name) self.__uniforms[name] = Uniform( self.__program, location, type, count) return self.__uniforms[name]
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)
def uniformi(self, name, *vals): # check there are 1-4 values if len(vals) in range(1, 5): # select the correct function { 1 : GL.glUniform1i, 2 : GL.glUniform2i, 3 : GL.glUniform3i, 4 : GL.glUniform4i # retrieve the uniform location, and set }[len(vals)](GL.glGetUniformLocation(self.handle, name.encode("ascii")), *vals)
def uniformi(self, name, *vals): # check there are 1-4 values if len(vals) in range(1, 5): # select the correct function { 1: GL.glUniform1i, 2: GL.glUniform2i, 3: GL.glUniform3i, 4: GL.glUniform4i # retrieve the uniform location, and set }[len(vals)](GL.glGetUniformLocation(self.handle, name.encode("ascii")), *vals)
def uniformi(self, name: str, *vals): # upload an integer uniform # this program must be currently bound # check there are 1-4 values if len(vals) in range(1, 5): vals = list(map(c_int, vals)) # select the correct function location = glGetUniformLocation( self.handle, c_char_p(name.encode("utf-8"))) uniform_functions = {1: glUniform1i, 2: glUniform2i, 3: glUniform3i, 4: glUniform4i} uniform_functions[len(vals)](location, *vals)
def uniformf(self, name: str, *vals): # upload a floating point uniform # this program must be currently bound # check there are 1-4 values if len(vals) in range(1, 5): vals = list(map(c_float, vals)) location = glGetUniformLocation( self.handle, c_char_p(name.encode("utf-8"))) # select the correct function uniform_functions = {1: glUniform1f, 2: glUniform2f, 3: glUniform3f, 4: glUniform4f} uniform_functions[len(vals)](location, *vals)
def __init__(self, vertex_shader: Shader, fragment_shader: Shader, attributes=(), uniforms=None): """ The process of creating a shader can be divided into 6 steps: 1. Create an ID. 2. Attach shaders. 3. Bind attributes. 4. Link program. 5. Validate program. 6. Bind uniforms. Args: vertex_shader: fragment_shader: attributes: uniforms: A dictionary with the names of the uniform as the key, and the uniform (glsl value) as value. """ if uniforms is None: uniforms = {} handle = -1 attribute_location = {} uniform_location = {} try: handle = glCreateProgram() glAttachShader(handle, vertex_shader) glAttachShader(handle, fragment_shader) for index, name in enumerate(attributes): glBindAttribLocation(handle, index, c_string(name)) attribute_location[name] = index glLinkProgram(handle) glValidateProgram(handle) for uniform in uniforms: uniform_location[uniform] = glGetUniformLocation( handle, c_string(uniform)) except GLException: debug_program(handle) super(Program, self).__init__(handle) self.vertex_shader = vertex_shader self.fragment_shader = fragment_shader self.attribute_location = attribute_location self.uniform_location = uniform_location self.uniforms = uniforms if CHECK_ERROR: debug_program(self)
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 render_to_texture(in_size, out_size, view_z=None): z0, z1 = (0, in_size[2]) if view_z == None else view_z vertices = (VERTEX * 6)(((-1, -1), (0, 0)), ((1, -1), (1, 0)), ((1, 1), (1, 1)), ((1, 1), (1, 1)), ((-1, 1), (0, 1)), ((-1, -1), (0, 0))) gl.glBindTexture(gl.GL_TEXTURE_3D, rendered_texture) gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, framebuffer) draw_buffers = (gl.GLenum * 1)(gl.GL_COLOR_ATTACHMENT0) gl.glDrawBuffers(1, draw_buffers) gl.glViewport(0, 0, out_size[0], out_size[1]) gl.glUseProgram(render_program) loc_depth = gl.glGetUniformLocation(render_program, ctypes.create_string_buffer(b'depth')) loc_texelSize = gl.glGetUniformLocation( render_program, ctypes.create_string_buffer(b'texelSize')) gl.glUniform3f(loc_texelSize, 1 / in_size[0], 1 / in_size[1], 1 / in_size[2]) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, render_vertexbuffer) gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(vertices), vertices, gl.GL_DYNAMIC_DRAW) gl.glBindVertexArray(render_vao) gl.glClearColor(0.0, 0.0, 0.0, 0.0) for z in range(out_size[2]): gl.glFramebufferTexture3D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_3D, rendered_texture, 0, z) fbs = gl.glCheckFramebufferStatus(gl.GL_FRAMEBUFFER) assert fbs == gl.GL_FRAMEBUFFER_COMPLETE, 'FramebufferStatus is {}'.format( fbs) gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) gl.glUniform1f(loc_depth, (z0 + z * (z1 - z0)) / in_size[2] / out_size[2]) gl.glBindTexture(gl.GL_TEXTURE_3D, input_texture) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) if z % 10 == 0: gl.glFinish() print('\033[K{}/{}'.format(z, out_size[2] - 1), end='\r') gl.glFinish() gl.glBindVertexArray(0)
def add_uniform(self, uname, dtype): """Add a uniform to the shader program. :param uname: name of the uniform. :type uname: str :param dtype: data type of the uniform -- 'vec3', 'mat4', etc :type dtype: str """ ufunc = uniform_function_map[dtype] loc = gl.glGetUniformLocation(self._pid, uname.encode()) self._uniforms[uname] = Uniform(uname, loc, ufunc)
def uniformf(self, name: str, *vals): # upload a floating point uniform # this program must be currently bound # check there are 1-4 values if len(vals) in range(1, 5): c_vals = list(map(c_float, vals)) location = glGetUniformLocation(self.handle, bytes(name, "utf-8")) uniform_functions = { 1: glUniform1f, 2: glUniform2f, 3: glUniform3f, 4: glUniform4f } uniform_functions[len(c_vals)](location, *c_vals)
def uniformf(self, name, *vals): ''' Uploads float uniform(s), program must be currently bound. ''' loc = self.uniforms.get(name, gl.glGetUniformLocation(self.handle,name)) self.uniforms[name] = loc # Check there are 1-4 values if len(vals) in range(1, 5): # Select the correct function { 1 : gl.glUniform1f, 2 : gl.glUniform2f, 3 : gl.glUniform3f, 4 : gl.glUniform4f # Retrieve uniform location, and set it }[len(vals)](loc, *vals)
def uniformi(self, name, *vals): ''' Upload integer uniform(s), program must be currently bound. ''' loc = self.uniforms.get(name, gl.glGetUniformLocation(self.handle,name)) self.uniforms[name] = loc # Checks there are 1-4 values if len(vals) in range(1, 5): # Selects the correct function { 1 : gl.glUniform1i, 2 : gl.glUniform2i, 3 : gl.glUniform3i, 4 : gl.glUniform4i # Retrieves uniform location, and set it }[len(vals)](loc, *vals)
def setInt(self, name, value): if type(name) is not bytes: name = bytes(name, 'utf-8') loc = GL.glGetUniformLocation(self.handle, name) if not hasattr(value, '__len__'): GL.glUniform1i(loc, value) elif len(value) in range(1, 5): # Select the correct function { 1 : GL.glUniform1i, 2 : GL.glUniform2i, 3 : GL.glUniform3i, 4 : GL.glUniform4i # Retrieve uniform location, and set it }[len(value)](loc, value) else: raise ValueError("Shader.setInt '{}' should be length 1-4 not {}" .format(name, len(value)))
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 _uniform_loc_storage_and_type(self, var): """Return the uniform location and a container that can store its value. Parameters ---------- var : string Uniform name. """ if var not in self.active_uniforms: raise GLSLError("Uniform '%s' is not active. Make sure the " "variable is used in the source code." % var) try: var_info = self._uniform_type_info[var] except KeyError: raise ValueError("Uniform variable '%s' is not defined in " "shader source." % var) # If this is an array, how many values are involved? count = var_info['array'] if var_info['kind'] in ['int']: data_type = gl.GLint else: data_type = gl.GLfloat assert gl.glIsProgram(self.handle) == True assert self.linked loc = gl.glGetUniformLocation(self.handle, var) if loc == -1: raise RuntimeError("Could not query uniform location " "for '%s'." % var) storage = data_type * (count * var_info['size']) storage_nested = count * (data_type * var_info['size']) return loc, storage, storage_nested, data_type
def __setitem__(self, uniform, value): try: uid = self.uniforms[uniform] except KeyError: uid = gl.glGetUniformLocation(self.program, uniform) if uid == -1: raise NoSuchUniformError(uniform) self.uniforms[uniform] = uid args = [uid] if isinstance(value, (int, ctypes.c_int)): setter = gl.glUniform1i args.append(value) elif isinstance(value, (float, ctypes.c_float, ctypes.c_double)): setter = gl.glUniform1f args.append(value) else: args.extend(value) setter = SETTERSF[len(args) - 2] setter(*args)
def _introspect_uniforms(self): """Figure out what uniforms are available and build an internal map""" # Number of active uniforms in the program active_uniforms = gl.GLint(0) gl.glGetProgramiv(self._glo, gl.GL_ACTIVE_UNIFORMS, byref(active_uniforms)) # Loop all the active uniforms for index in range(active_uniforms.value): # Query uniform information like name, type, size etc. u_name, u_type, u_size = self._query_uniform(index) u_location = gl.glGetUniformLocation(self._glo, u_name.encode()) # Skip uniforms that may be in Uniform Blocks # TODO: We should handle all uniforms if u_location == -1: # print(f"Uniform {u_location} {u_name} {u_size} {u_type} skipped") continue u_name = u_name.replace("[0]", "") # Remove array suffix self._uniforms[u_name] = Uniform(self._glo, u_location, u_name, u_type, u_size)
def __getitem__(self, var): """Get uniform value. """ loc, container, container_nested, dtype = \ self._uniform_loc_storage_and_type(var) var_info = self._uniform_type_info[var] data = container_nested() if dtype == gl.GLint: get_func = gl.glGetUniformiv else: get_func = gl.glGetUniformfv alen = var_info['array'] for i in range(alen): if i > 0: # Query the location of each array element loc = gl.glGetUniformLocation(self.handle, var + '[%d]' % i) assert loc != -1 get_func(self.handle, loc, data[i]) # Convert to a NumPy array for easier processing data = np.array(data) # Scalar if data.size == 1: return data[0] # Array, matrix, vector elif var_info['kind'] == 'mat': count, n_sqr = data.shape n = np.sqrt(n_sqr) data = data.reshape((count, n, n), order='F') return data
def set_uniform_f(self, name, value): location = gl.glGetUniformLocation(self.program, name) gl.glUniform1f(location, value)
def get_uniform_location(self, name): return gl.glGetUniformLocation(self.id, name.encode('ascii'))
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_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 __init__(self, frames): #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.frames = frames 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] A = args["A"].astype(np.float32) #print("A shape " + str(A.shape)) #print(str(A.dtype)) #print(A) B = args["B"].astype(np.float32) #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)) self.Bp = B.ctypes.data_as(ctypes.POINTER(ctypes.c_void_p)) 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_A = gl.glGetUniformLocation(self.programA, b"A") self.tex_pos_A_B = gl.glGetUniformLocation(self.programA, b"B") self.feed_pos_A = gl.glGetUniformLocation(self.programA, b"f") self.kill_pos_A = gl.glGetUniformLocation(self.programA, b"k") self.dA_pos_A = gl.glGetUniformLocation(self.programA, b"dA") self.dB_pos_A = gl.glGetUniformLocation(self.programA, b"dB") self.dt_pos_A = gl.glGetUniformLocation(self.programA, b"timestep") self.step_pos_A = gl.glGetUniformLocation(self.programA, b"step") gl.glUniform1f(self.feed_pos_A, args["feed"]) gl.glUniform1f(self.kill_pos_A, args["kill"]) gl.glUniform1f(self.dA_pos_A, args["dA"]) gl.glUniform1f(self.dB_pos_A, args["dB"]) gl.glUniform1f(self.dt_pos_A, args["dt"]) #may need changed for nonsquare textures gl.glUniform1f(self.step_pos_A, 1 / self.dimx) gl.glUseProgram(self.programB) self.pos_posB = gl.glGetAttribLocation( self.programB, ctypes.create_string_buffer(b"a_position")) assert (self.pos_posB >= 0) gl.glEnableVertexAttribArray(self.pos_posB) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertex_buffer) gl.glVertexAttribPointer(self.pos_posB, 2, gl.GL_FLOAT, False, 0, 0) self.tex_pos_B_A = gl.glGetUniformLocation(self.programB, b"A") self.tex_pos_B_B = gl.glGetUniformLocation(self.programB, b"B") self.feed_pos_B = gl.glGetUniformLocation(self.programB, b"f") self.kill_pos_B = gl.glGetUniformLocation(self.programB, b"k") self.dA_pos_B = gl.glGetUniformLocation(self.programB, b"dA") self.dB_pos_B = gl.glGetUniformLocation(self.programB, b"dB") self.dt_pos_B = gl.glGetUniformLocation(self.programB, b"timestep") self.step_pos_B = gl.glGetUniformLocation(self.programB, b"step") gl.glUniform1f(self.feed_pos_B, args["feed"]) gl.glUniform1f(self.kill_pos_B, args["kill"]) gl.glUniform1f(self.dA_pos_B, args["dA"]) gl.glUniform1f(self.dB_pos_B, args["dB"]) gl.glUniform1f(self.dt_pos_B, args["dt"]) #may need changed for nonsquare textures gl.glUniform1f(self.step_pos_B, 1 / self.dimx) gl.glViewport(0, 0, self.dimx, self.dimy)
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)