示例#1
0
    def _update(self):
        """ Actual upload of data to GPU memory  """

        log.debug("GPU: Updating %s" % self.name)

        # Check active status (mandatory)
        #        if not self._active:
        #            raise RuntimeError("Attribute variable is not active")
        #        if self._data is None:
        #            raise RuntimeError("Attribute variable data is not set")

        # Generic vertex attribute (all vertices receive the same value)
        if self._generic:
            if self._handle >= 0:
                gl.glDisableVertexAttribArray(self._handle)
                self._afunction(self._handle, *self._data)

        # Regular vertex buffer
        elif self.handle >= 0:
            #if self._need_update:
            #    self.data._update()
            #    self._need_update = False

            # Get relevant information from gl_typeinfo
            size, gtype, dtype = gl_typeinfo[self._gtype]
            stride = self.data.stride

            # Make offset a pointer, or it will be interpreted as a small array
            offset = ctypes.c_void_p(self.data.offset)
            gl.glEnableVertexAttribArray(self.handle)
            gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.data.handle)
            gl.glVertexAttribPointer(self.handle, size, gtype, gl.GL_FALSE,
                                     stride, offset)
示例#2
0
文件: variable.py 项目: glumpy/glumpy
    def _update(self):
        """ Actual upload of data to GPU memory  """

        log.debug("GPU: Updating %s" % self.name)

        # Check active status (mandatory)
#        if not self._active:
#            raise RuntimeError("Attribute variable is not active")
#        if self._data is None:
#            raise RuntimeError("Attribute variable data is not set")

        # Generic vertex attribute (all vertices receive the same value)
        if self._generic:
            if self._handle >= 0:
                gl.glDisableVertexAttribArray(self._handle)
                self._afunction(self._handle, *self._data)

        # Regular vertex buffer
        elif self.handle >= 0:
            #if self._need_update:
            #    self.data._update()
            #    self._need_update = False

            # Get relevant information from gl_typeinfo
            size, gtype, dtype = gl_typeinfo[self._gtype]
            stride = self.data.stride

            # Make offset a pointer, or it will be interpreted as a small array
            offset = ctypes.c_void_p(self.data.offset)
            gl.glEnableVertexAttribArray(self.handle)
            gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.data.handle)
            gl.glVertexAttribPointer(self.handle, size, gtype,  gl.GL_FALSE, stride, offset)
示例#3
0
    def _transfer_frame_pbo(self):
        # generate PBO's 
        if self._video_thread.has_video_loaded and (self._pbo_shape != self._video_thread.frame.shape):
            if self._pbos is not None:
                gl.glDeleteBuffers(PBO_COUNT, self._pbos)

            self._pbo_shape = self._video_thread.frame.shape
            self._pbos = gl.glGenBuffers(PBO_COUNT)

            h, w, b = self._pbo_shape
            num_bytes = h*w*b
            for pbo in self._pbos:
                gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, pbo)
                gl.glBufferData(gl.GL_PIXEL_UNPACK_BUFFER, num_bytes, None, gl.GL_STREAM_DRAW)
            gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, 0)

        # generate/update OpenGL texture
        if (self._frame is None or self._frame.shape != self._pbo_shape) and self._pbo_shape is not None:
            self._frame = np.zeros(self._pbo_shape, dtype=np.uint8).view(gloo.Texture2D)
            self._frame.activate()
            self._frame.deactivate()

        # do the transfer of pixel data from cpu to gpu using PBO's
        # inspired by this: https://gist.github.com/roxlu/4663550
        if self._video_thread.has_video_loaded and self._video_thread.frame_changed:
            self._video_thread.frame_changed = False

            pbo = self._pbos[self._pbo_index]
            gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, pbo)
            t = self._frame._handle
            h, w, b = self._pbo_shape
            assert t != None and t != 0
            gl.glBindTexture(gl.GL_TEXTURE_2D, t)
            gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, w, h, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, None)

            h, w, b = self._pbo_shape
            num_bytes = h*w*b

            self._pbo_index = (self._pbo_index + 1) % PBO_COUNT
            pbo = self._pbos[self._pbo_index]
            gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, pbo)
            # this might be an alternative, but not so fast as tested so far
            #gl.glBufferSubData(gl.GL_PIXEL_UNPACK_BUFFER, 0, num_bytes, ctypes.c_void_p(self._video_thread.frame.ctypes.data))

            ptr = gl.glMapBuffer(gl.GL_PIXEL_UNPACK_BUFFER, gl.GL_WRITE_ONLY)
            if ptr != 0:
                #start = time.time()
                ctypes.memmove(ctypes.c_voidp(ptr), ctypes.c_void_p(self._video_thread.frame.ctypes.data), num_bytes)
                #end = time.time()
                #elapsed = end - start
                #print("Took %.2fms, %.2fMB/s" % (elapsed * 1000, (num_bytes / 1000000) / elapsed))
                gl.glUnmapBuffer(gl.GL_PIXEL_UNPACK_BUFFER)
            gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, 0)
示例#4
0
    def set_uniforms(self, program):
        super().set_uniforms(program)

        ssbo = self.get("ssbo")
        if ssbo is None:
            ssbo = empty_ssbo
        ssbo.activate()

        b = ssbo._handle
        gl.glBindBuffer(gl.GL_SHADER_STORAGE_BUFFER, b)
        gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, b)

        program["uCount"] = len(ssbo)
示例#5
0
    def draw(self, projection, view, width, height):
        model_matrix = self._transform.matrix

        # Set uniforms
        self._program["u_projection"] = projection
        # Note: OpenGL matrix multiplication works on column-major oriented storage (as least for pre-multiplication).
        # Also glumpy.glm is using column-major assumption for its operations.
        view_model_matrix = np.transpose(
            np.matmul(np.transpose(view), np.transpose(model_matrix)))
        self._program["u_view_model_matrix"] = view_model_matrix
        # self._program["u_view"] = view
        # self._program["u_model"] = self._model
        view_model_normal_matrix = np.transpose(
            np.linalg.inv(view_model_matrix))
        self._program["u_view_model_normal_matrix"] = view_model_normal_matrix
        self._program["u_color_scale"] = self._color_scale
        self._program["u_normal_scale"] = self._normal_scale
        self._program["u_depth_scale"] = self._depth_scale
        if self._shader_type == self.PHONG:
            self._program["u_light_position"] = self._light_position
            self._program[
                "u_light_ambient_intensity"] = 0.4 * self._light_intensity
            self._program[
                "u_light_diffuse_intensity"] = 0.4 * self._light_intensity
            self._program[
                "u_light_specular_intensity"] = 0.2 * self._light_intensity
            self._program["u_material_ambient"] = self._material
            self._program["u_material_diffuse"] = self._material
            self._program["u_material_specular"] = self._material
            self._program["u_material_shininess"] = 32

        with self._program.activate():
            # Bind index buffer and draw
            if self.use_depth_test:
                gl.glEnable(gl.GL_DEPTH_TEST)
            else:
                gl.glDisable(gl.GL_DEPTH_TEST)
            if self.use_face_culling:
                gl.glFrontFace(gl.GL_CCW)
                gl.glCullFace(gl.GL_BACK)
                gl.glEnable(gl.GL_CULL_FACE)
            else:
                gl.glDisable(gl.GL_CULL_FACE)
            gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._gl_index_buffer)
            gl.glDrawElements(gl.GL_TRIANGLES, 3 * len(self._faces),
                              opengl_utils.get_gl_type(self._faces), None)
            gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0)
示例#6
0
    def draw(self, mode=gl.GL_TRIANGLES, indices=None):  #first=0, count=None):
        """ Draw using the specified mode & indices.

        :param gl.GLEnum mode: 
          One of
            * GL_POINTS
            * GL_LINES
            * GL_LINE_STRIP
            * GL_LINE_LOOP,
            * GL_TRIANGLES
            * GL_TRIANGLE_STRIP
            * GL_TRIANGLE_FAN

        :param IndexBuffer|None indices:
            Vertex indices to be drawn. If none given, everything is drawn.
        """

        self.activate()
        attributes = self._attributes.values()

        # Get buffer size first attribute
        # We need more tests here
        #  - do we have at least 1 attribute ?
        #  - does all attributes report same count ?
        # count = (count or attributes[0].size) - first

        if isinstance(indices, IndexBuffer):
            indices.activate()
            gltypes = {
                np.dtype(np.uint8): gl.GL_UNSIGNED_BYTE,
                np.dtype(np.uint16): gl.GL_UNSIGNED_SHORT,
                np.dtype(np.uint32): gl.GL_UNSIGNED_INT
            }
            gl.glDrawElements(mode, indices.size, gltypes[indices.dtype], None)
            indices.deactivate()
        else:
            first = 0
            # count = (self._count or attributes[0].size) - first
            count = len(tuple(attributes)[0])
            gl.glDrawArrays(mode, first, count)

        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
        self.deactivate()
示例#7
0
文件: program.py 项目: jk34/glumpy
    def draw(self, mode=gl.GL_TRIANGLES, indices=None):  # first=0, count=None):
        """ Draw the attribute arrays in the specified mode.

        Parameters
        ----------
        mode : GL_ENUM
            GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP,
            GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN

        first : int
            The starting vertex index in the vertex array. Default 0.

        count : int
            The number of vertices to draw. Default all.
        """

        self.activate()
        attributes = self._attributes.values()

        # Get buffer size first attribute
        # We need more tests here
        #  - do we have at least 1 attribute ?
        #  - does all attributes report same count ?
        # count = (count or attributes[0].size) - first

        if isinstance(indices, IndexBuffer):
            indices.activate()
            gltypes = {
                np.dtype(np.uint8): gl.GL_UNSIGNED_BYTE,
                np.dtype(np.uint16): gl.GL_UNSIGNED_SHORT,
                np.dtype(np.uint32): gl.GL_UNSIGNED_INT,
            }
            gl.glDrawElements(mode, indices.size, gltypes[indices.dtype], None)
            indices.deactivate()
        else:
            first = 0
            # count = (self._count or attributes[0].size) - first
            count = len(tuple(attributes)[0])
            gl.glDrawArrays(mode, first, count)

        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
        self.deactivate()
示例#8
0
文件: program.py 项目: glumpy/glumpy
    def draw(self, mode = gl.GL_TRIANGLES, indices=None): #first=0, count=None):
        """ Draw using the specified mode & indices.

        :param gl.GLEnum mode: 
          One of
            * GL_POINTS
            * GL_LINES
            * GL_LINE_STRIP
            * GL_LINE_LOOP,
            * GL_TRIANGLES
            * GL_TRIANGLE_STRIP
            * GL_TRIANGLE_FAN

        :param IndexBuffer|None indices:
            Vertex indices to be drawn. If none given, everything is drawn.
        """

        self.activate()
        attributes = self._attributes.values()

        # Get buffer size first attribute
        # We need more tests here
        #  - do we have at least 1 attribute ?
        #  - does all attributes report same count ?
        # count = (count or attributes[0].size) - first

        if isinstance(indices, IndexBuffer):
            indices.activate()
            gltypes = { np.dtype(np.uint8) : gl.GL_UNSIGNED_BYTE,
                        np.dtype(np.uint16): gl.GL_UNSIGNED_SHORT,
                        np.dtype(np.uint32): gl.GL_UNSIGNED_INT }
            gl.glDrawElements(mode, indices.size, gltypes[indices.dtype], None)
            indices.deactivate()
        else:
            first = 0
            # count = (self._count or attributes[0].size) - first
            count = len(tuple(attributes)[0])
            gl.glDrawArrays(mode, first, count)

        gl.glBindBuffer( gl.GL_ARRAY_BUFFER, 0 )
        self.deactivate()
示例#9
0
    def _download_texture(self, texture):
        # generate PBO's 
        if self._pbos is None or self._pbo_shape != texture.shape:
            if self._pbos is not None:
                gl.glDeleteBuffers(2, self._pbos)

            self._pbo_shape = texture.shape
            self._pbos = gl.glGenBuffers(2)

            h, w, b = self._pbo_shape
            num_bytes = h*w*b
            for pbo in self._pbos:
                gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, pbo)
                gl.glBufferData(gl.GL_PIXEL_PACK_BUFFER, num_bytes, None, gl.GL_STREAM_DRAW)
            gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, 0)

        # do the transfer of pixel data from gpu to cpu using PBO's
        # inspired by this: https://gist.github.com/roxlu/4663550
        h, w, b = self._pbo_shape
        b -= 1
        num_bytes = h*w*b
        pbo = self._pbos[self._pbo_index]
        gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, pbo)
        t = texture._handle
        assert t != None and t != 0
        gl.glBindTexture(gl.GL_TEXTURE_2D, t)
        gl.glGetTexImage(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, ctypes.c_void_p(0))

        self._pbo_index = (self._pbo_index + 1) % 2
        pbo = self._pbos[self._pbo_index]
        gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, pbo)
        ptr = gl.glMapBuffer(gl.GL_PIXEL_PACK_BUFFER, gl.GL_READ_ONLY)
        data = None
        if ptr != 0:
            p = ctypes.cast(ptr, ctypes.POINTER(ctypes.c_ubyte * num_bytes))
            data = np.frombuffer(p.contents, dtype=np.uint8).copy().reshape((h, w, b))
            gl.glUnmapBuffer(gl.GL_PIXEL_PACK_BUFFER)
        gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, 0)

        assert data is not None
        return data
示例#10
0
    def draw(self, mode = gl.GL_TRIANGLES, indices=None): #first=0, count=None):
        """ Draw the attribute arrays in the specified mode.

        Parameters
        ----------
        mode : GL_ENUM
            GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP,
            GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN

        first : int
            The starting vertex index in the vertex array. Default 0.

        count : int
            The number of vertices to draw. Default all.
        """

        self.activate()
        attributes = self._attributes.values()

        # Get buffer size first attribute
        # We need more tests here
        #  - do we have at least 1 attribute ?
        #  - does all attributes report same count ?
        # count = (count or attributes[0].size) - first

        if isinstance(indices, IndexBuffer):
            indices.activate()
            gltypes = { np.dtype(np.uint8) : gl.GL_UNSIGNED_BYTE,
                        np.dtype(np.uint16): gl.GL_UNSIGNED_SHORT,
                        np.dtype(np.uint32): gl.GL_UNSIGNED_INT }
            gl.glDrawElements(mode, indices.size, gltypes[indices.dtype], None)
            indices.deactivate()
        else:
            first = 0
            # count = (self._count or attributes[0].size) - first
            count = len(attributes[0])
            gl.glDrawArrays(mode, first, count)

        gl.glBindBuffer( gl.GL_ARRAY_BUFFER, 0 )
        self.deactivate()
示例#11
0
    def _deactivate(self):
        """ Unbind the current bound buffer """

        log.debug("GPU: Deactivating buffer (id=%d)" % self._id)
        gl.glBindBuffer(self._target, 0)
示例#12
0
    def _activate(self):
        """ Bind the buffer to some target """

        log.debug("GPU: Activating buffer (id=%d)" % self._id)
        gl.glBindBuffer(self._target, self._handle)
示例#13
0
    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.glGetIntegerv(gl.GL_CURRENT_PROGRAM)
        last_texture = gl.glGetIntegerv(gl.GL_TEXTURE_BINDING_2D)
        last_active_texture = gl.glGetIntegerv(gl.GL_ACTIVE_TEXTURE)
        last_array_buffer = gl.glGetIntegerv(gl.GL_ARRAY_BUFFER_BINDING)
        last_element_array_buffer = gl.glGetIntegerv(
            gl.GL_ELEMENT_ARRAY_BUFFER_BINDING)
        last_vertex_array = gl.glGetIntegerv(gl.GL_VERTEX_ARRAY_BINDING)
        last_blend_src = gl.glGetIntegerv(gl.GL_BLEND_SRC)
        last_blend_dst = gl.glGetIntegerv(gl.GL_BLEND_DST)
        last_blend_equation_rgb = gl.glGetIntegerv(gl.GL_BLEND_EQUATION_RGB)
        last_blend_equation_alpha = gl.glGetIntegerv(
            gl.GL_BLEND_EQUATION_ALPHA)
        last_viewport = gl.glGetIntegerv(gl.GL_VIEWPORT)
        last_scissor_box = gl.glGetIntegerv(gl.GL_SCISSOR_BOX)
        last_enable_blend = gl.glIsEnabled(gl.GL_BLEND)
        last_enable_cull_face = gl.glIsEnabled(gl.GL_CULL_FACE)
        last_enable_depth_test = gl.glIsEnabled(gl.GL_DEPTH_TEST)
        last_enable_scissor_test = gl.glIsEnabled(gl.GL_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 = (ctypes.c_float * 16)(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)

        self.prog["ProjMtx"] = ortho_projection

        for commands in draw_data.commands_lists:

            idx_buffer_offset = 0

            array_type = c_ubyte * commands.vtx_buffer_size * imgui.VERTEX_SIZE
            data_carray = array_type.from_address(commands.vtx_buffer_data)

            if not ( imgui.VERTEX_BUFFER_POS_OFFSET == 0 and \
                     imgui.VERTEX_BUFFER_UV_OFFSET == 8 and \
                     imgui.VERTEX_BUFFER_COL_OFFSET == 16 ):
                log.error(
                    "GlumpyRenderer.render(): imgui vertex buffer layout has changed ! notify the developers ..."
                )

                return

            #TODO: this is a bit convoluted; Imgui delivers uint8 colors, but glumpy wants float32's
            dtype = [('Position', np.float32, 2), ('UV', np.float32, 2),
                     ('Color', np.uint8, 4)]
            vao_content = np.frombuffer(data_carray, dtype=dtype)

            dtype2 = [('Position', np.float32, 2), ('UV', np.float32, 2),
                      ('Color', np.float32, 4)]
            vao_content_f = np.zeros(vao_content.shape, dtype=dtype2)
            for i, val in enumerate(vao_content):
                vao_content_f[i] = vao_content[i]
                vao_content_f[i]['Color'] /= 255

            v_array = vao_content_f.view(gloo.VertexArray)
            self.prog.bind(v_array)

            if imgui.INDEX_SIZE == 1:
                dtype = np.uint8
            if imgui.INDEX_SIZE == 2:
                dtype = np.uint16
            if imgui.INDEX_SIZE == 4:
                dtype = np.uint32

            # 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, ctypes.c_void_p(commands.idx_buffer_data), gl.GL_STREAM_DRAW)
            array_type = c_ubyte * commands.idx_buffer_size * imgui.INDEX_SIZE
            data_carray = array_type.from_address(commands.idx_buffer_data)
            idx_content = np.frombuffer(data_carray, dtype=dtype)

            for command in commands.commands:

                # TODO: ImGui Images will not work yet, homogenizing texture id
                # allocation by imgui/glumpy is likely a larger issue
                #
                #accessing command.texture_id crashes the prog
                #
                #gl.glBindTexture(gl.GL_TEXTURE_2D, command.texture_id )

                x, y, z, w = command.clip_rect
                gl.glScissor(int(x), int(fb_height - w), int(z - x),
                             int(w - y))

                idx_array = idx_content[idx_buffer_offset:(
                    idx_buffer_offset + command.elem_count)].view(
                        gloo.IndexBuffer)
                self.prog.draw(mode=gl.GL_TRIANGLES, indices=idx_array)

                idx_buffer_offset += command.elem_count

        # restore modified GL state
        gl.glUseProgram(last_program)
        gl.glActiveTexture(last_active_texture)
        gl.glBindTexture(gl.GL_TEXTURE_2D, last_texture)
        gl.glBindVertexArray(last_vertex_array)
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, last_array_buffer)
        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer)
        gl.glBlendEquationSeparate(last_blend_equation_rgb,
                                   last_blend_equation_alpha)
        gl.glBlendFunc(last_blend_src, last_blend_dst)

        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])

        log.debug("----------------------end---------------------------------")
示例#14
0
    def _deactivate(self):
        """ Unbind the current bound buffer """

        log.debug("GPU: Deactivating buffer (id=%d)" % self._id)
        gl.glBindBuffer(self._target, 0)
示例#15
0
    def _activate(self):
        """ Bind the buffer to some target """

        log.debug("GPU: Activating buffer (id=%d)" % self._id)
        gl.glBindBuffer(self._target, self._handle)
示例#16
0
    def __init__(self,
                 mesh,
                 use_depth_test=True,
                 use_face_culling=True,
                 shader_type=PHONG):
        self.use_depth_test = use_depth_test
        self.use_face_culling = use_face_culling
        # Compile shaders
        if shader_type == self.FLAT:
            self._program = Program(self.FLAT_VERTEX,
                                    self.FLAT_FRAGMENT,
                                    version="330")
        elif shader_type == self.PHONG:
            self._program = Program(self.PHONG_VERTEX,
                                    self.PHONG_FRAGMENT,
                                    version="330")
        else:
            raise RuntimeError("Unknown shader type: {}".format(shader_type))
        self._shader_type = shader_type
        # Get mesh attributes
        self._vertices_vbo = np.core.records.fromarrays(
            [mesh.vertices],
            dtype=[('a_vertex', np.float32, (3, ))]).view(gloo.VertexBuffer)
        if mesh.colors is None:
            print("Mesh has no color. Using default color [0.5, 0, 0, 1].")
            mesh_colors = np.zeros((self._vertices_vbo.shape[0], 4),
                                   dtype=np.float32)
            mesh_colors[:, :] = [0.5, 0, 0, 1]
        else:
            mesh_colors = mesh.colors
        self._colors_vbo = np.core.records.fromarrays(
            [mesh_colors],
            dtype=[('a_color', np.float32, (4, ))]).view(gloo.VertexBuffer)
        if mesh.normals is None:
            print("Mesh has no normals. Using default normals [0, 0, 0].")
            mesh_normals = np.zeros((self._vertices_vbo.shape[0], 3),
                                    dtype=np.float32)
            mesh_normals[:, :] = [0, 0.5, 0]
        else:
            mesh_normals = mesh.normals
        self._normals_vbo = np.core.records.fromarrays(
            [mesh_normals],
            dtype=[('a_normal', np.float32, (3, ))]).view(gloo.VertexBuffer)
        # self._texcoords_vbo = np.core.records.fromarrays([mesh.texcoords], dtype=[('a_texcoords', np.float32, (2,))]).view(gloo.VertexBuffer)
        self._faces = mesh.faces.view(gloo.IndexBuffer)

        # Bind vertex attributes
        self._program.bind(self._vertices_vbo)
        self._program.bind(self._colors_vbo)
        self._program.bind(self._normals_vbo)
        # self._program.bind(self._texcoords_vbo)
        # Create and fill index buffer
        self._gl_index_buffer = gl.glGenBuffers(1)
        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._gl_index_buffer)
        gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, self._faces.nbytes,
                        self._faces, gl.GL_STATIC_DRAW)
        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0)
        # Initialize uniforms
        self._color_scale = np.array([1, 1, 1, 1])
        self._normal_scale = np.array([1, 1, 1])
        self._depth_scale = 1.0
        self._light_position = np.array([-25, -25, 50.])
        self._light_intensity = 3
        self._material = np.array([0.5, 0.5, 0.5])
        self._transform = pvm.ModelTransform()