def _read_pixels_as_in_window(self): # Reads pixels with markers and overlay from the same camera as screen. resolution = glfw.get_framebuffer_size( self.sim._render_context_window.window) resolution = np.array(resolution) resolution = resolution * min(1000 / np.min(resolution), 1) resolution = resolution.astype(np.int32) resolution -= resolution % 16 if self.sim._render_context_offscreen is None: self.sim.render(resolution[0], resolution[1]) offscreen_ctx = self.sim._render_context_offscreen window_ctx = self.sim._render_context_window # Save markers and overlay from offscreen. saved = [copy.deepcopy(offscreen_ctx._markers), copy.deepcopy(offscreen_ctx._overlay), rec_copy(offscreen_ctx.cam)] # Copy markers and overlay from window. offscreen_ctx._markers[:] = window_ctx._markers[:] offscreen_ctx._overlay.clear() offscreen_ctx._overlay.update(window_ctx._overlay) rec_assign(offscreen_ctx.cam, rec_copy(window_ctx.cam)) img = self.sim.render(*resolution) img = img[::-1, :, :] # Rendered images are upside-down. # Restore markers and overlay to offscreen. offscreen_ctx._markers[:] = saved[0][:] offscreen_ctx._overlay.clear() offscreen_ctx._overlay.update(saved[1]) rec_assign(offscreen_ctx.cam, saved[2]) return img
def _read_pixels_as_in_window(self): # Reads pixels with markers and overlay from the same camera as screen. resolution = glfw.get_framebuffer_size( self.sim._render_context_window.window) if self.sim._render_context_offscreen is None: self.sim.render(*resolution) offscreen_ctx = self.sim._render_context_offscreen window_ctx = self.sim._render_context_window # Save markers and overlay from offscreen. saved = [copy.deepcopy(offscreen_ctx._markers), copy.deepcopy(offscreen_ctx._overlay), rec_copy(offscreen_ctx.cam)] # Copy markers and overlay from window. offscreen_ctx._markers[:] = window_ctx._markers[:] offscreen_ctx._overlay.clear() offscreen_ctx._overlay.update(window_ctx._overlay) rec_assign(offscreen_ctx.cam, rec_copy(window_ctx.cam)) img = self.sim.render(*resolution) # Restore markers and overlay to offscreen. offscreen_ctx._markers[:] = saved[0][:] offscreen_ctx._overlay.clear() offscreen_ctx._overlay.update(saved[1]) rec_assign(offscreen_ctx.cam, saved[2]) return img
def _cursor_pos_callback(self, window, xpos, ypos): if not (self._button_left_pressed or self._button_right_pressed): return # Determine whether to move, zoom or rotate view mod_shift = ( glfw.get_key(window, glfw.KEY_LEFT_SHIFT) == glfw.PRESS or glfw.get_key(window, glfw.KEY_RIGHT_SHIFT) == glfw.PRESS) if self._button_right_pressed: action = const.MOUSE_MOVE_H if mod_shift else const.MOUSE_MOVE_V elif self._button_left_pressed: action = const.MOUSE_ROTATE_H if mod_shift else const.MOUSE_ROTATE_V else: action = const.MOUSE_ZOOM # Determine dx = int(self._scale * xpos) - self._last_mouse_x dy = int(self._scale * ypos) - self._last_mouse_y width, height = glfw.get_framebuffer_size(window) with self._gui_lock: self.move_camera(action, dx / height, dy / height) self._last_mouse_x = int(self._scale * xpos) self._last_mouse_y = int(self._scale * ypos)
def get_dimensions(self): """ returns a tuple (width, height) """ if self.window: return glfw.get_framebuffer_size(self.window) return (self.init_width, self.init_height)
def renderLoop(self): self.initGL() while not glfw.window_should_close(self.window): w, h = glfw.get_framebuffer_size(self.window) self.renderFrame() glfw.swap_buffers(self.window) glfw.poll_events() self.destroyGL()
def retrieve_mouse_data(self): window_size = glfw.get_framebuffer_size(self.window) window_center = [window_size[0] / 2, window_size[1] / 2] mouse_pos = [float(p - window_center[i]) / window_center[i] for i, p in enumerate(glfw.get_cursor_pos(self.window))] self.mouse_movement = (mouse_pos[0], mouse_pos[1]) glfw.set_cursor_pos(self.window, *window_center)
def autoscale(self): self.cam.lookat[0] = self.model.stat.center[0] self.cam.lookat[1] = self.model.stat.center[1] self.cam.lookat[2] = self.model.stat.center[2] self.cam.distance = 1.0 * self.model.stat.extent self.cam.camid = -1 self.cam.trackbodyid = -1 if self.window: width, height = glfw.get_framebuffer_size(self.window) mjlib.mjv_updateCameraPose(byref(self.cam), width*1.0/height)
def __init__(self, **kwargs): super().__init__(**kwargs) if not glfw.init(): raise ValueError("Failed to initialize glfw") # Configure the OpenGL context glfw.window_hint(glfw.CONTEXT_CREATION_API, glfw.NATIVE_CONTEXT_API) glfw.window_hint(glfw.CLIENT_API, glfw.OPENGL_API) glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, self.gl_version[0]) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, self.gl_version[1]) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True) glfw.window_hint(glfw.RESIZABLE, self.resizable) glfw.window_hint(glfw.DOUBLEBUFFER, True) glfw.window_hint(glfw.DEPTH_BITS, 24) glfw.window_hint(glfw.SAMPLES, self.samples) monitor = None if self.fullscreen: # Use the primary monitors current resolution monitor = glfw.get_primary_monitor() mode = glfw.get_video_mode(monitor) self.width, self.height = mode.size.width, mode.size.height # Make sure video mode switching will not happen by # matching the desktops current video mode glfw.window_hint(glfw.RED_BITS, mode.bits.red) glfw.window_hint(glfw.GREEN_BITS, mode.bits.green) glfw.window_hint(glfw.BLUE_BITS, mode.bits.blue) glfw.window_hint(glfw.REFRESH_RATE, mode.refresh_rate) self.window = glfw.create_window(self.width, self.height, self.title, monitor, None) if not self.window: glfw.terminate() raise ValueError("Failed to create window") if not self.cursor: glfw.set_input_mode(self.window, glfw.CURSOR, glfw.CURSOR_DISABLED) self.buffer_width, self.buffer_height = glfw.get_framebuffer_size(self.window) glfw.make_context_current(self.window) if self.vsync: glfw.swap_interval(1) glfw.set_key_callback(self.window, self.key_event_callback) glfw.set_cursor_pos_callback(self.window, self.mouse_event_callback) glfw.set_mouse_button_callback(self.window, self.mouse_button_callback) glfw.set_window_size_callback(self.window, self.window_resize_callback) self.ctx = moderngl.create_context(require=self.gl_version_code) self.print_context_info() self.set_default_viewport()
def start(self): if not glfw.init(): return glfw.window_hint(glfw.SAMPLES, 4) # try stereo if refresh rate is at least 100Hz window = None stereo_available = False _, _, refresh_rate = glfw.get_video_mode(glfw.get_primary_monitor()) if refresh_rate >= 100: glfw.window_hint(glfw.STEREO, 1) window = glfw.create_window(500, 500, "Simulate", None, None) if window: stereo_available = True # no stereo: try mono if not window: glfw.window_hint(glfw.STEREO, 0) window = glfw.create_window(500, 500, "Simulate", None, None) if not window: glfw.terminate() return self.running = True # Make the window's context current glfw.make_context_current(window) width, height = glfw.get_framebuffer_size(window) width1, height = glfw.get_window_size(window) self._scale = width * 1.0 / width1 self.window = window mjlib.mjv_makeObjects(byref(self.objects), 1000) mjlib.mjv_defaultCamera(byref(self.cam)) mjlib.mjv_defaultOption(byref(self.vopt)) mjlib.mjr_defaultOption(byref(self.ropt)) mjlib.mjr_defaultContext(byref(self.con)) if self.model: mjlib.mjr_makeContext(self.model.ptr, byref(self.con), 150) self.autoscale() else: mjlib.mjr_makeContext(None, byref(self.con), 150) glfw.set_cursor_pos_callback(window, self.handle_mouse_move) glfw.set_mouse_button_callback(window, self.handle_mouse_button) glfw.set_scroll_callback(window, self.handle_scroll)
def handle_scroll(self, window, x_offset, y_offset): # require model if not self.model: return # get current window size width, height = glfw.get_framebuffer_size(window) # scroll self.gui_lock.acquire() mjlib.mjv_moveCamera(MOUSE_ZOOM, 0, (-20*y_offset), byref(self.cam), width, height) self.gui_lock.release()
def window_resize_callback(self, window, width, height): """ Window resize callback for glfw Args: window: The window width: New width height: New height """ self.width, self.height = width, height self.buffer_width, self.buffer_height = glfw.get_framebuffer_size(self.window) self.set_default_viewport() super().resize(self.buffer_width, self.buffer_height)
def mouse_button_event(self, button, action, mods): """Called when a mouse button is pressed or released :param int button: The pressed/released mouse button :param int action: glfw.PRESS or glfw.RELEASE :param int mods: Bit field describing which modifier keys were held down. """ if button == glfw.MOUSE_BUTTON_LEFT and action == glfw.PRESS: width, height = glfw.get_framebuffer_size(self.window) x, y = glfw.get_cursor_pos(self.window) # integer positions relative to the upper left corner of the window x = x - (width / 2) y = (height / 2) - y self.heightmap.generate(game_core.Point(x, y)) self.generate_texture(width, height)
def on_window_size(window, w, h): # get the frame buffer size and don't rely on the window # the window size and the framebuffer can vary on retina displays size_w, size_h = glfw.get_framebuffer_size(window) window_width = size_w window_height = size_h gl.glViewport(0, 0, window_width, window_height) #Reset The Current Viewport And Perspective Transformation gl.glMatrixMode(gl.GL_PROJECTION) #Select The Projection Matrix gl.glLoadIdentity() #Reset The Projection Matrix glu.gluPerspective(45.0,window_width/window_height,0.1,100.0) #Calculate The Aspect Ratio Of The Window gl.glMatrixMode(gl.GL_MODELVIEW) #Select The Modelview Matrix
def handleResizeEvent(self, window): w, h = glfw.get_framebuffer_size(window) viewport = (int(max(1, w)), int(max(1, h))) if viewport != self.viewport: self.viewport = viewport self.updateMatrix(self.viewport) if self.useFramebuffers: self.initFramebuffers() if self.overlay: self.initOverlay() glViewport(0, 0, *self.viewport) self.redisplay = True
def init(self): super(Window, self).init() # hide the cursor and lock it to this window. GLFW will then take care # of all the details of cursor re-centering and offset calculation and # providing the application with a virtual cursor position glfw.set_input_mode(self.window, glfw.CURSOR, glfw.CURSOR_DISABLED) self.cube = game_core.Mesh(smooth_cube.VERTICES, smooth_cube.NORMALS, smooth_cube.INDICES, smooth_cube.DRAW_METHOD) self.shaders = shaders.init() # set a default matrix for models, otherwise its nothing apparently self.light_direction = game_core.Vector(0.1, 1.0, 0.5) self.light_direction.normalize() model_mat = game_core.Matrix() for name, shader in self.shaders.iteritems(): if 'modelToWorldMatrix' in shader.uniforms: with shader: GL.glUniformMatrix4fv( shader.uniforms['modelToWorldMatrix'], 1, GL.GL_FALSE, model_mat.tolist() ) if 'dirToLight' in shader.uniforms: with shader: GL.glUniform4fv(shader.uniforms['dirToLight'], 1, list(self.light_direction)) # if 'diffuseColor' in shader.uniforms: # with shader: # GL.glUniform4f(shader.uniforms['diffuseColor'], 0.5, 0.5, 0.5, 1.0) self.camera = Camera(position=[0.0, 32.0, 128.0]) self.camera.init(*glfw.get_framebuffer_size(self.window)) self._set_perspective_matrix() self.lod_tree = LodTestTree(size=64.0, max_depth=6) self.lod_tree.init() for depth in range(self.lod_tree.max_depth): fine_distance = self.lod_distances[depth] if depth == 0: coarse_distance = fine_distance * 2.0 else: coarse_distance = self.lod_distances[depth - 1] with self.shaders['lod_test_{}'.format(depth)] as shader: GL.glUniform1f(shader.uniforms['fineDistance'], fine_distance) GL.glUniform1f(shader.uniforms['coarseDistance'], coarse_distance)
def init(self): super(Window, self).init() # hide the cursor and lock it to this window. GLFW will then take care # of all the details of cursor re-centering and offset calculation and # providing the application with a virtual cursor position glfw.set_input_mode(self.window, glfw.CURSOR, glfw.CURSOR_DISABLED) # create a simple cube with smooth normals self.cube = game_core.Mesh(smooth_cube.VERTICES, smooth_cube.NORMALS, smooth_cube.INDICES, smooth_cube.DRAW_METHOD) # create a camera self.camera = game_core.AbstractCamera(position=[0.0, 0.0, 1.5]) self.camera.init(*glfw.get_framebuffer_size(self.window)) # compile a simple shader with MVP matrices frag_shader = compileShader(frag_shader_source, GL.GL_FRAGMENT_SHADER) vert_shader = compileShader(vert_shader_source, GL.GL_VERTEX_SHADER) self.shader = game_core.ShaderProgram(vert_shader, frag_shader) self.shader.store_uniform_location('modelToWorldMatrix') self.shader.store_uniform_location('worldToCameraMatrix') self.shader.store_uniform_location('cameraToClipMatrix') # populate the shader's MVP matrices and pull the "camera" back 1.5 units with self.shader: GL.glUniformMatrix4fv( self.shader.uniforms['cameraToClipMatrix'], 1, GL.GL_FALSE, self.camera.projection_matrix.tolist(), ) inverse_camera_matrix = self.camera.matrix.inverse() GL.glUniformMatrix4fv( self.shader.uniforms['worldToCameraMatrix'], 1, GL.GL_FALSE, inverse_camera_matrix.tolist() ) model_mat = game_core.Matrix() GL.glUniformMatrix4fv( self.shader.uniforms['modelToWorldMatrix'], 1, GL.GL_FALSE, model_mat.tolist() )
def init(self): # Initialize the renderer, set up the Window. glfw.init() glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, gl.GL_TRUE) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) glfw.window_hint(glfw.DECORATED, gl.GL_TRUE) glfw.window_hint(glfw.DECORATED, gl.GL_TRUE) glfw.window_hint(glfw.RESIZABLE, gl.GL_FALSE) width = Config.windowWidth height = Config.windowHeight self.aspect = width/height # Initialize the window self.window = glfw.create_window(width, height, "Magic", None, None) glfw.make_context_current(self.window) self.renderer = Renderer() self.quad = [] self.text = [] # Set up camera self.viewMatrix = Matrix.identity() # Set up view transform. View is always 16 units high, and 16 * aspect units # wide. The extra space outside of a 4:3 ratio is unused, to make sure that # all the cards always fit in a 4:3 aspect monitor. vHeight = 2 vWidth = vHeight * self.aspect self.projectionMatrix = Matrix.ortho(-vWidth/2, vWidth/2, vHeight/2, -vHeight/2, -1, 1) self.viewProjectionMatrix = self.projectionMatrix * self.viewMatrix # Set up viewport fbWidth, fbHeight = glfw.get_framebuffer_size(self.window) gl.glViewport(0, 0, fbWidth, fbHeight) q = Quad(Texture('Images/Sen Triplets.jpg')) # Natural resolution of cards is 480x680 cardAspect = 480/680 q.x = 0 q.y = 0 q.height = .8 q.width = q.height * cardAspect self.quad.append(q)
def __init__(self, sim): super().__init__(sim) self._gui_lock = Lock() self._button_left_pressed = False self._button_right_pressed = False self._last_mouse_x = 0 self._last_mouse_y = 0 framebuffer_width, _ = glfw.get_framebuffer_size(self.window) window_width, _ = glfw.get_window_size(self.window) self._scale = framebuffer_width * 1.0 / window_width glfw.set_cursor_pos_callback(self.window, self._cursor_pos_callback) glfw.set_mouse_button_callback( self.window, self._mouse_button_callback) glfw.set_scroll_callback(self.window, self._scroll_callback) glfw.set_key_callback(self.window, self.key_callback)
def main(): glfw.init() window = glfw.create_window( 640, 480, "glfw triangle", None, None ) glfw.make_context_current( window ) glfw.swap_interval( 1 ) glfw.set_key_callback( window, on_key ) while not glfw.window_should_close( window ): # set up model view width, height = glfw.get_framebuffer_size( window ) ratio = width / float(height) gl.glViewport( 0, 0, width, height ) gl.glClear( gl.GL_COLOR_BUFFER_BIT ) gl.glMatrixMode( gl.GL_PROJECTION ) gl.glLoadIdentity() gl.glOrtho( -ratio, ratio, -1.0, 1.0, 1.0, -1.0 ) gl.glMatrixMode( gl.GL_MODELVIEW ) gl.glLoadIdentity() gl.glRotatef( float(glfw.get_time()) * 50.0, 0.0, 0.0, 1.0 ) # draw triangle gl.glBegin(gl.GL_TRIANGLES); gl.glColor3f( 1.0, 0.0, 0.0 ) gl.glVertex3f( -0.6, -0.4, 0.0 ) gl.glColor3f( 0.0, 1.0, 0.0 ) gl.glVertex3f( 0.6, -0.4, 0.0 ) gl.glColor3f( 0.0, 0.0, 1.0 ) gl.glVertex3f( 0.0, 0.6, 0.0 ) gl.glEnd() # swap buffers glfw.swap_buffers(window) # poll for events glfw.poll_events() glfw.destroy_window(window) glfw.terminate()
def handle_mouse_move(self, window, xpos, ypos): # no buttons down: nothing to do if not self._button_left_pressed \ and not self._button_middle_pressed \ and not self._button_right_pressed: return # compute mouse displacement, save dx = int(self._scale * xpos) - self._last_mouse_x dy = int(self._scale * ypos) - self._last_mouse_y self._last_mouse_x = int(self._scale * xpos) self._last_mouse_y = int(self._scale * ypos) # require model if not self.model: return # get current window size width, height = glfw.get_framebuffer_size(self.window) # get shift key state mod_shift = glfw.get_key(window, glfw.KEY_LEFT_SHIFT) == glfw.PRESS \ or glfw.get_key(window, glfw.KEY_RIGHT_SHIFT) == glfw.PRESS # determine action based on mouse button action = None if self._button_right_pressed: action = MOUSE_MOVE_H if mod_shift else MOUSE_MOVE_V elif self._button_left_pressed: action = MOUSE_ROTATE_H if mod_shift else MOUSE_ROTATE_V else: action = MOUSE_ZOOM self.gui_lock.acquire() mjlib.mjv_moveCamera(action, dx, dy, byref(self.cam), width, height) self.gui_lock.release()
def __init__(self, width=800, height=600, title="QLibs window", swap_interval=1, hint_conf=default_hint_conf, resizable=True, fullscreen=False, transparent=False): self.width = width self.height = height self.resize_callback = None self.mouse_motion_callback = None self.mouse_button_callback = None self.scroll_callback = None self.key_callback = None self.spec_key_callback = None self.flip_mouse_y = False #flipped relatively to usual math-y representation glfw.init() glfw.window_hint(glfw.RESIZABLE, resizable and not fullscreen) glfw.window_hint(glfw.TRANSPARENT_FRAMEBUFFER, transparent) for k, v in hint_conf.items(): glfw.window_hint(k, v) monitor = None if fullscreen: monitor = glfw.get_primary_monitor() mode = glfw.get_video_mode(monitor) width = mode.size.width height = mode.size.height #width = 1920 #height = 1080 glfw.window_hint(glfw.RED_BITS, mode.bits.red) glfw.window_hint(glfw.GREEN_BITS, mode.bits.green) glfw.window_hint(glfw.BLUE_BITS, mode.bits.blue) glfw.window_hint(glfw.REFRESH_RATE, mode.refresh_rate) try: self.window = glfw.create_window(width, height, title, monitor, None) except glfw.GLFWError: logger.warn( "Provided config is unavailable, using fallback config") glfw.default_window_hints() for k, v in fallback_hint_conf.items(): glfw.window_hint(k, v) self.window = glfw.create_window(width, height, title, None, None) if fullscreen: self.width, self.height = glfw.get_framebuffer_size( self.window) #Required on windows glfw.set_window_user_pointer(self.window, id(self.window)) glfw.make_context_current(self.window) glfw.swap_interval(swap_interval) #callbacks glfw.set_window_size_callback(self.window, self._on_resize) glfw.set_framebuffer_size_callback(self.window, self._update_viewport) glfw.set_cursor_pos_callback(self.window, self._on_mouse_motion) glfw.set_mouse_button_callback(self.window, self._on_mouse_button) glfw.set_char_mods_callback(self.window, self._on_key_press) glfw.set_key_callback(self.window, self._on_spec_key_press) glfw.set_scroll_callback(self.window, self._on_scroll) try: self.ctx = moderngl.create_context() except: self.ctx = moderngl.create_context(libgl='libGL.so.1')
def main(): import os import sys os.chdir(os.path.dirname(__file__)) import glfw import time from engine import Engine # Initialize the library if not glfw.init(): sys.exit() glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) glfw.window_hint(glfw.SAMPLES, 16) # Create a windowed mode window and its OpenGL context window = glfw.create_window(640, 480, "Window Name", None, None) if not window: print "Couldn't initialize OpenGL. Check that your OpenGL version >4.3." glfw.terminate() sys.exit() # Make the window's context current glfw.make_context_current(window) # Get window size width, height = glfw.get_framebuffer_size(window) # Create engine engine = Engine(window) engine.setWindowHeight(height) engine.setWindowWidth(width) def on_resize(window, width, height): engine.setWindowWidth(width) engine.setWindowHeight(height) # Install a window size handler glfw.set_window_size_callback(window, on_resize) def on_key(window, key, scancode, action, mods): if key == glfw.KEY_ESCAPE and action == glfw.PRESS: glfw.set_window_should_close(window, 1) # Install a key handler glfw.set_key_callback(window, on_key) def on_mouse(window, button, action, mods): if button == glfw.MOUSE_BUTTON_1 and action == glfw.PRESS: engine.shoot_on() if button == glfw.MOUSE_BUTTON_1 and action == glfw.RELEASE: engine.shoot_off() if button == glfw.MOUSE_BUTTON_2 and action == glfw.PRESS: engine.camera_switch() glfw.set_mouse_button_callback(window, on_mouse) def on_scroll(window, x, y): engine.camera_scroll(y) glfw.set_scroll_callback(window, on_scroll) old_time = time.time() elapsed_time = 0.0 # Loop until the user closes the window while not glfw.window_should_close(window): # Calculate elapsed time elapsed_time = time.time() - old_time old_time = time.time() # Process engine.step(elapsed_time) # Swap front and back buffers glfw.swap_interval(1) glfw.swap_buffers(window) # Poll for and process events glfw.poll_events() # Don't be egoist :) time.sleep(0.01) glfw.terminate()
def on_size(self, win, width, height): """ window size update => update viewport to new framebuffer size """ GL.glViewport(0, 0, *glfw.get_framebuffer_size(win))
TARGET_FRAMERATE: int = 60 time_at_beginning_of_previous_frame: float = glfw.get_time() while not glfw.window_should_close(window): while ( glfw.get_time() < time_at_beginning_of_previous_frame + 1.0 / TARGET_FRAMERATE ): pass time_at_beginning_of_previous_frame = glfw.get_time() glfw.poll_events() width, height = glfw.get_framebuffer_size(window) glViewport(0, 0, width, height) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) draw_in_square_viewport() handle_inputs() axes_list = glfw.get_joystick_axes(glfw.JOYSTICK_1) if len(axes_list) >= 1 and axes_list[0]: if math.fabs(float(axes_list[0][0])) > 0.19: camera.position_worldspace.x += 10.0 * axes_list[0][0] * math.cos(camera.rot_y) camera.position_worldspace.z -= 10.0 * axes_list[0][0] * math.sin(camera.rot_y) if math.fabs(float(axes_list[0][1])) > 0.19: camera.position_worldspace.x += 10.0 * axes_list[0][1] * math.sin(camera.rot_y) camera.position_worldspace.z += 10.0 * axes_list[0][1] * math.cos(camera.rot_y)
def main(): if not glfw.init(): return window = glfw.create_window(WIDTH, HEIGHT, "Hello World", None, None) glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) glfw.window_hint(glfw.RESIZABLE, GL_FALSE) if not window: glfw.terminate() return -1 glfw.make_context_current(window) (width, height) = glfw.get_framebuffer_size(window) glViewport(0, 0, width, height) glfw.set_key_callback(window, key_callback) glClearColor(0.2, 0.3, 0.2, 1.0) quad = [ # coords # colors # texture -0.4, -0.5, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.4, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.4, 0.5, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, -0.4, 0.5, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0 ] quad = numpy.array(quad, dtype=numpy.float32) indexes = [0, 1, 2, 0, 2, 3] indexes = numpy.array(indexes, dtype=numpy.uint32) ourShader = Shader('vertex_shader.vs', 'fragment_shader.frag') VAO = glGenVertexArrays(1) VBO = glGenBuffers(1) EBO = glGenBuffers(1) glBindVertexArray(VAO) glBindBuffer(GL_ARRAY_BUFFER, VBO) glBufferData(GL_ARRAY_BUFFER, quad.itemsize * len(quad), quad, GL_STATIC_DRAW) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO) glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexes.itemsize * len(indexes), indexes, GL_STATIC_DRAW) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 32, ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 32, ctypes.c_void_p(12)) glEnableVertexAttribArray(1) glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 32, ctypes.c_void_p(24)) glEnableVertexAttribArray(2) glBindVertexArray(0) texture1 = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, texture1) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) image = Image.open('../textures/wall.jpg') img_data = numpy.array(list(image.getdata()), numpy.uint8) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data) glGenerateMipmap(GL_TEXTURE_2D) glBindTexture(GL_TEXTURE_2D, 0) texture2 = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, texture2) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) image = Image.open('../textures/container.jpg') img_data = numpy.array(list(image.getdata()), numpy.uint8) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data) glGenerateMipmap(GL_TEXTURE_2D) glBindTexture(GL_TEXTURE_2D, 0) while not glfw.window_should_close(window): glfw.poll_events() glClear(GL_COLOR_BUFFER_BIT) ourShader.Use() dxLoc = glGetUniformLocation(ourShader.shader, "dx") glUniform1f(dxLoc, -0.5) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, texture1) glBindVertexArray(VAO) glDrawElements(GL_TRIANGLES, len(indexes), GL_UNSIGNED_INT, None) glBindVertexArray(0) glUniform1f(dxLoc, 0.5) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, texture2) glBindVertexArray(VAO) glDrawElements(GL_TRIANGLES, len(indexes), GL_UNSIGNED_INT, None) glBindVertexArray(0) glfw.swap_buffers(window) glfw.terminate()
def player_drop(rec_dir, ipc_pub_url, ipc_sub_url, ipc_push_url, user_dir, app_version, debug): # general imports import logging # networking import zmq import zmq_tools from time import sleep # zmq ipc setup zmq_ctx = zmq.Context() ipc_pub = zmq_tools.Msg_Dispatcher(zmq_ctx, ipc_push_url) # log setup logging.getLogger("OpenGL").setLevel(logging.ERROR) logger = logging.getLogger() logger.handlers = [] logger.setLevel(logging.INFO) logger.addHandler(zmq_tools.ZMQ_handler(zmq_ctx, ipc_push_url)) # create logger for the context of this function logger = logging.getLogger(__name__) try: import glfw from gl_utils import GLFWErrorReporting GLFWErrorReporting.set_default() import gl_utils from OpenGL.GL import glClearColor from version_utils import parse_version from file_methods import Persistent_Dict from pyglui.pyfontstash import fontstash from pyglui.ui import get_roboto_font_path import player_methods as pm from pupil_recording import ( assert_valid_recording_type, InvalidRecordingException, ) from pupil_recording.update import update_recording process_was_interrupted = False def interrupt_handler(sig, frame): import traceback trace = traceback.format_stack(f=frame) logger.debug(f"Caught signal {sig} in:\n" + "".join(trace)) nonlocal process_was_interrupted process_was_interrupted = True signal.signal(signal.SIGINT, interrupt_handler) def on_drop(window, paths): nonlocal rec_dir rec_dir = paths[0] if rec_dir: try: assert_valid_recording_type(rec_dir) except InvalidRecordingException as err: logger.error(str(err)) rec_dir = None # load session persistent settings session_settings = Persistent_Dict( os.path.join(user_dir, "user_settings_player")) if parse_version(session_settings.get("version", "0.0")) != app_version: logger.info( "Session setting are from a different version of this app. I will not use those." ) session_settings.clear() w, h = session_settings.get("window_size", (1280, 720)) glfw.init() glfw.window_hint(glfw.SCALE_TO_MONITOR, glfw.TRUE) glfw.window_hint(glfw.RESIZABLE, 0) window = glfw.create_window(w, h, "Pupil Player", None, None) glfw.window_hint(glfw.RESIZABLE, 1) glfw.make_context_current(window) window_position_manager = gl_utils.WindowPositionManager() window_pos = window_position_manager.new_window_position( window=window, default_position=window_position_default, previous_position=session_settings.get("window_position", None), ) glfw.set_window_pos(window, window_pos[0], window_pos[1]) glfw.set_drop_callback(window, on_drop) glfont = fontstash.Context() glfont.add_font("roboto", get_roboto_font_path()) glfont.set_align_string(v_align="center", h_align="middle") glfont.set_color_float((0.2, 0.2, 0.2, 0.9)) gl_utils.basic_gl_setup() glClearColor(0.5, 0.5, 0.5, 0.0) text = "Drop a recording directory onto this window." tip = "(Tip: You can drop a recording directory onto the app icon.)" # text = "Please supply a Pupil recording directory as first arg when calling Pupil Player." def display_string(string, font_size, center_y): x = w / 2 * content_scale y = center_y * content_scale glfont.set_size(font_size * content_scale) glfont.set_blur(10.5) glfont.set_color_float((0.0, 0.0, 0.0, 1.0)) glfont.draw_text(x, y, string) glfont.set_blur(0.96) glfont.set_color_float((1.0, 1.0, 1.0, 1.0)) glfont.draw_text(x, y, string) while not glfw.window_should_close( window) and not process_was_interrupted: fb_size = glfw.get_framebuffer_size(window) content_scale = gl_utils.get_content_scale(window) gl_utils.adjust_gl_view(*fb_size) if rec_dir: try: assert_valid_recording_type(rec_dir) logger.info( "Starting new session with '{}'".format(rec_dir)) text = "Updating recording format." tip = "This may take a while!" except InvalidRecordingException as err: logger.error(str(err)) if err.recovery: text = err.reason tip = err.recovery else: text = "Invalid recording" tip = err.reason rec_dir = None gl_utils.clear_gl_screen() display_string(text, font_size=51, center_y=216) for idx, line in enumerate(tip.split("\n")): tip_font_size = 42 center_y = 288 + tip_font_size * idx * 1.2 display_string(line, font_size=tip_font_size, center_y=center_y) glfw.swap_buffers(window) if rec_dir: try: update_recording(rec_dir) except AssertionError as err: logger.error(str(err)) tip = "Oops! There was an error updating the recording." rec_dir = None except InvalidRecordingException as err: logger.error(str(err)) if err.recovery: text = err.reason tip = err.recovery else: text = "Invalid recording" tip = err.reason rec_dir = None else: glfw.set_window_should_close(window, True) glfw.poll_events() session_settings["window_position"] = glfw.get_window_pos(window) session_settings.close() glfw.destroy_window(window) if rec_dir: ipc_pub.notify({ "subject": "player_process.should_start", "rec_dir": rec_dir }) except Exception: import traceback trace = traceback.format_exc() logger.error( "Process player_drop crashed with trace:\n{}".format(trace)) finally: sleep(1.0)
def get_rect(self): rect = mjcore.MJRRECT(0, 0, 0, 0) rect.width, rect.height = glfw.get_framebuffer_size(self.window) return rect
def get_rect(self): rect = PyMjrRect() rect.width, rect.height = glfw.get_framebuffer_size(self.window) return rect
def main(): if not glfw.init(): return -1 #configure glfw (using OpenGL 3.3 Core) glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) # create the window window = glfw.create_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Hello World", None, None) if not window: glfw.terminate() return -1 glfw.make_context_current(window) # set callbacks glfw.set_window_size_callback(window, framebuffer_size_callback) glfw.set_key_callback(window, key_callback) # set the OpenGL viewport to the whole window (width, height) = glfw.get_framebuffer_size(window) glViewport(0, 0, width, height) # SHADERS ######################################################### vertex_shader_source = """ #version 330 core layout (location = 0) in vec3 position; layout (location = 1) in vec3 aColor; out vec3 vertexColor; void main() { gl_Position = vec4(position, 1.0f); vertexColor = aColor; } """ fragment_shader_source = """ #version 330 core in vec3 vertexColor; out vec4 FragColor; void main() { FragColor = vec4(vertexColor, 1.0f); } """ vertex_shader = OpenGL.GL.shaders.compileShader(vertex_shader_source, GL_VERTEX_SHADER) fragment_shader = OpenGL.GL.shaders.compileShader(fragment_shader_source, GL_FRAGMENT_SHADER) shader = OpenGL.GL.shaders.compileProgram(vertex_shader, fragment_shader) # END SHADERS ######################################################### # vertices data (a triangle) triangle = [ # coords # color -0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 1.0 ] triangle = numpy.array(triangle, dtype=numpy.float32) triangleIndices = [0, 1, 2] triangleIndices = numpy.array(triangleIndices, dtype=numpy.uint32) triangleVAO = glGenVertexArrays(1) triangleVBO = glGenBuffers(1) triangleEBO = glGenBuffers(1) glBindVertexArray(triangleVAO) glBindBuffer(GL_ARRAY_BUFFER, triangleVBO) glBufferData(GL_ARRAY_BUFFER, triangle.itemsize * len(triangle), triangle, GL_STATIC_DRAW) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangleEBO) glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangleIndices.itemsize * len(triangleIndices), triangleIndices, GL_STATIC_DRAW) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(ctypes.c_float), ctypes.c_void_p(0)) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(ctypes.c_float), ctypes.c_void_p(3 * sizeof(ctypes.c_float))) glEnableVertexAttribArray(0) glEnableVertexAttribArray(1) glBindVertexArray(0) # game loop while not glfw.window_should_close(window): # set the color buffer glClearColor(0.2, 0.3, 0.3, 1.0) glClear(GL_COLOR_BUFFER_BIT) glUseProgram(shader) glBindVertexArray(triangleVAO) glDrawElements(GL_TRIANGLES, len(triangleIndices), GL_UNSIGNED_INT, None) glfw.swap_buffers(window) glfw.poll_events() glfw.terminate()
def main(): global rotation_angle global d_x # Initialize the library if not glfw.init(): print("library is not initialized") return # Create a windowed mode window and its OpenGL context window = glfw.create_window(640, 480, "Hello World", None, None) if not window: glfw.terminate() return # Make the window's context current glfw.make_context_current(window) print(glfw.__version__) glfw.set_key_callback(window, on_key) #glfw.set_mouse_button_callback(window, on_mouse) # Loop until the user closes the window while not glfw.window_should_close(window): # Render here, e.g. using pyOpenGL width, height = glfw.get_framebuffer_size(window) ratio = width / float(height) rotation_angle += 0.1 # Set viewport gl.glViewport(0, 0, width, height) # Clear color buffer gl.glClear(gl.GL_COLOR_BUFFER_BIT) # Select and setup the projection matrix gl.glMatrixMode(gl.GL_PROJECTION) gl.glLoadIdentity() gl.glOrtho(-ratio, ratio, -1, 1, 1, -1) # Select and setup the modelview matrix gl.glMatrixMode(gl.GL_MODELVIEW) gl.glLoadIdentity() gl.glRotatef(rotation_angle, 0, 0, 1) gl.glBegin(gl.GL_POLYGON) gl.glColor3f(color.red, color.green, color.blue) gl.glVertex3f(-0.5 + d_x, -0.5, 0) gl.glColor3f(color.red, color.green, color.blue) gl.glVertex3f(-0.5 + d_x, +0.5, 0) gl.glColor3f(color.red, color.green, color.blue) gl.glVertex3f( 0.5 + d_x, +0.5, 0) gl.glColor3f(color.red, color.green, color.blue) gl.glVertex3f( 0.5 + d_x, -0.5, 0) gl.glEnd() # Swap front and back buffers glfw.swap_buffers(window) # Poll for and process events glfw.poll_events() # terminating the whole proccess glfw.destroy_window(window) glfw.terminate()
def on_pos(window, x, y): hdpi_factor = float( glfw.get_framebuffer_size(window)[0] / glfw.get_window_size(window)[0]) x, y = x * hdpi_factor, y * hdpi_factor gui.update_mouse(x, y)
def main(): if not glfw.init(): return window = glfw.create_window(WIDTH, HEIGHT, "Hello World", None, None) glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) glfw.window_hint(glfw.RESIZABLE, GL_FALSE) if not window: glfw.terminate() return -1 glfw.make_context_current(window) (width, height) = glfw.get_framebuffer_size(window) glViewport(0, 0, width, height) glfw.set_key_callback(window, key_callback) glClearColor(0.2, 0.3, 0.2, 1.0) triangle = [ # coords # colors -0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 1.0 ] triangle = numpy.array(triangle, dtype=numpy.float32) indexes = [0, 1, 2] indexes = numpy.array(indexes, dtype=numpy.uint32) vertex_shader_source = """ #version 330 core layout (location = 0) in vec3 position; layout (location = 1) in vec3 color; out vec3 ourColor; void main() { gl_Position = vec4(position, 1.0f); ourColor = color; } """ fragment_shader_source = """ #version 330 core in vec3 ourColor; out vec4 color; void main() { color = vec4(ourColor, 1.0f); } """ vertex_shader = OpenGL.GL.shaders.compileShader(vertex_shader_source, GL_VERTEX_SHADER) fragment_shader = OpenGL.GL.shaders.compileShader(fragment_shader_source, GL_FRAGMENT_SHADER) shader = OpenGL.GL.shaders.compileProgram(vertex_shader, fragment_shader) VAO = glGenVertexArrays(1) VBO = glGenBuffers(1) EBO = glGenBuffers(1) glBindVertexArray(VAO) glBindBuffer(GL_ARRAY_BUFFER, VBO) glBufferData(GL_ARRAY_BUFFER, triangle.itemsize * len(triangle), triangle, GL_STATIC_DRAW) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO) glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexes.itemsize * len(indexes), indexes, GL_STATIC_DRAW) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(12)) glEnableVertexAttribArray(1) glBindVertexArray(0) while not glfw.window_should_close(window): glfw.poll_events() glClear(GL_COLOR_BUFFER_BIT) glUseProgram(shader) glBindVertexArray(VAO) glDrawElements(GL_TRIANGLES, len(indexes), GL_UNSIGNED_INT, None) glBindVertexArray(0) glfw.swap_buffers(window) glfw.terminate()
def __init__( self, width, height, caption, resizable=True, fullscreen=False, vsync=True, aspect_ratio=16 / 9, samples=4, cursor=True, ): self.vsync = vsync self.width = width self.cursor = cursor self.height = height self.samples = samples self.caption = caption self.resizable = resizable self.fullscreen = fullscreen self.aspect_ratio = aspect_ratio if not glfw.init(): raise ValueError("Failed to initialize glfw") # Configure the OpenGL context glfw.window_hint(glfw.CONTEXT_CREATION_API, glfw.NATIVE_CONTEXT_API) glfw.window_hint(glfw.CLIENT_API, glfw.OPENGL_API) glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, self.gl_version[0]) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, self.gl_version[1]) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True) glfw.window_hint(glfw.RESIZABLE, self.resizable) glfw.window_hint(glfw.DOUBLEBUFFER, True) glfw.window_hint(glfw.DEPTH_BITS, 24) glfw.window_hint(glfw.SAMPLES, self.samples) monitor = None if self.fullscreen: # Use the primary monitors current resolution monitor = glfw.get_primary_monitor() mode = glfw.get_video_mode(monitor) self.width, self.height = mode.size.width, mode.size.height # Make sure video mode switching will not happen by # matching the desktops current video mode glfw.window_hint(glfw.RED_BITS, mode.bits.red) glfw.window_hint(glfw.GREEN_BITS, mode.bits.green) glfw.window_hint(glfw.BLUE_BITS, mode.bits.blue) glfw.window_hint(glfw.REFRESH_RATE, mode.refresh_rate) self.window = glfw.create_window(self.width, self.height, self.caption, monitor, None) if not self.window: glfw.terminate() raise ValueError("Failed to create window") if not self.cursor: glfw.set_input_mode(self.window, glfw.CURSOR, glfw.CURSOR_DISABLED) self.buffer_width, self.buffer_height = glfw.get_framebuffer_size( self.window) glfw.make_context_current(self.window) if self.vsync: glfw.swap_interval(1) self.frames = 0 glfw.set_key_callback(self.window, self.key_event_callback) glfw.set_cursor_pos_callback(self.window, self.mouse_event_callback) glfw.set_scroll_callback(self.window, self.scroll_callback) glfw.set_mouse_button_callback(self.window, self.mouse_button_callback) glfw.set_window_size_callback(self.window, self.window_resize_callback) self.setup()
def main(): if not glfw.init(): raise RuntimeError('Failed to initialize GLFW') version = glfw.get_version_string().decode('ASCII') print('GLFW', version) monitors = glfw.get_monitors() for i, monitor in enumerate(monitors): name = glfw.get_monitor_name(monitor) primary = (glfw.get_monitor_pos(monitor) == glfw.get_monitor_pos(glfw.get_primary_monitor())) print('Monitor #{}: {}{}'.format(i, name.decode('utf8'), ' (primary)' if primary else '')) width_mm, height_mm = glfw.get_monitor_physical_size(monitor) diag_mm = math.sqrt(width_mm*width_mm + height_mm*height_mm) print('Diagonal: {:.1f}"'.format(diag_mm / 25.4)) mode = glfw.get_video_mode(monitor) print('Video mode: {}x{} {}Hz {}'.format(mode.size.width, mode.size.height, mode.refresh_rate, mode.bits)) xscale, yscale = glfw.get_monitor_content_scale(monitor) print('Scale: {}|{}'.format(xscale, yscale)) print('Virtual position:', glfw.get_monitor_pos(monitor)) print('Work ares:', glfw.get_monitor_workarea(monitor)) for mode in glfw.get_video_modes(monitor): print('Supported: {}x{} {}Hz {}'.format(mode.size.width, mode.size.height, mode.refresh_rate, mode.bits)) print(mode) print() glfw.window_hint(glfw.RESIZABLE, True) glfw.window_hint(glfw.STENCIL_BITS, 8) glfw.window_hint(glfw.CLIENT_API, glfw.OPENGL_API) glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 6) glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) monitor = glfw.get_primary_monitor() mode = glfw.get_video_mode(monitor) window = glfw.create_window(640, 480, 'Title', None, None) # window = glfw.create_window(mode.size.width, mode.size.height, 'Title', monitor, None) if window is None: glfw.terminate() raise RuntimeError('Failed to create a window') # glfw.set_window_monitor(window, monitor, 0, 0, mode.size.width, mode.size.height, mode.refresh_rate) width, height = glfw.get_window_size(window) print('Window size: {}x{}'.format(width, height)) print('Frame size:', glfw.get_window_frame_size(window)) width, height = glfw.get_framebuffer_size(window) print('Framebuffer size: {}x{}'.format(width, height)) print('Client API:', glfw.get_window_attrib(window, glfw.CLIENT_API)) version_major = glfw.get_window_attrib(window, glfw.CONTEXT_VERSION_MAJOR) version_minor = glfw.get_window_attrib(window, glfw.CONTEXT_VERSION_MINOR) revision = glfw.get_window_attrib(window, glfw.CONTEXT_REVISION) print('Version: {}.{} rev{}'.format(version_major, version_minor, revision)) glfw.make_context_current(window) renderer = Renderer(window) while not glfw.window_should_close(window): GL.glClear(GL.GL_COLOR_BUFFER_BIT) renderer.render() glfw.swap_buffers(window) glfw.poll_events() glfw.terminate()
def start(self): logger.info('initializing glfw@%s', glfw.get_version()) glfw.set_error_callback(_glfw_error_callback) if not glfw.init(): raise Exception('glfw failed to initialize') window = None if self.visible: glfw.window_hint(glfw.SAMPLES, 4) else: glfw.window_hint(glfw.VISIBLE, 0); # try stereo if refresh rate is at least 100Hz stereo_available = False _, _, refresh_rate = glfw.get_video_mode(glfw.get_primary_monitor()) if refresh_rate >= 100: glfw.window_hint(glfw.STEREO, 1) window = glfw.create_window( self.init_width, self.init_height, "Simulate", None, None) if window: stereo_available = True # no stereo: try mono if not window: glfw.window_hint(glfw.STEREO, 0) window = glfw.create_window( self.init_width, self.init_height, "Simulate", None, None) if not window: glfw.terminate() return self.running = True # Make the window's context current glfw.make_context_current(window) self._init_framebuffer_object() width, height = glfw.get_framebuffer_size(window) width1, height = glfw.get_window_size(window) self._scale = width * 1.0 / width1 self.window = window mjlib.mjv_makeObjects(byref(self.objects), 1000) mjlib.mjv_defaultCamera(byref(self.cam)) mjlib.mjv_defaultOption(byref(self.vopt)) mjlib.mjr_defaultOption(byref(self.ropt)) mjlib.mjr_defaultContext(byref(self.con)) if self.model: mjlib.mjr_makeContext(self.model.ptr, byref(self.con), 150) self.autoscale() else: mjlib.mjr_makeContext(None, byref(self.con), 150) glfw.set_cursor_pos_callback(window, self.handle_mouse_move) glfw.set_mouse_button_callback(window, self.handle_mouse_button) glfw.set_scroll_callback(window, self.handle_scroll)
def eye( timebase, is_alive_flag, ipc_pub_url, ipc_sub_url, ipc_push_url, user_dir, version, eye_id, overwrite_cap_settings=None, hide_ui=False, debug=False, pub_socket_hwm=None, parent_application="capture", ): """reads eye video and detects the pupil. Creates a window, gl context. Grabs images from a capture. Streams Pupil coordinates. Reacts to notifications: ``eye_process.should_stop``: Stops the eye process ``recording.started``: Starts recording eye video ``recording.stopped``: Stops recording eye video ``frame_publishing.started``: Starts frame publishing ``frame_publishing.stopped``: Stops frame publishing ``start_eye_plugin``: Start plugins in eye process Emits notifications: ``eye_process.started``: Eye process started ``eye_process.stopped``: Eye process stopped Emits data: ``pupil.<eye id>``: Pupil data for eye with id ``<eye id>`` ``frame.eye.<eye id>``: Eye frames with id ``<eye id>`` """ # We deferr the imports becasue of multiprocessing. # Otherwise the world process each process also loads the other imports. import zmq import zmq_tools zmq_ctx = zmq.Context() ipc_socket = zmq_tools.Msg_Dispatcher(zmq_ctx, ipc_push_url) pupil_socket = zmq_tools.Msg_Streamer(zmq_ctx, ipc_pub_url, pub_socket_hwm) notify_sub = zmq_tools.Msg_Receiver(zmq_ctx, ipc_sub_url, topics=("notify",)) # logging setup import logging logging.getLogger("OpenGL").setLevel(logging.ERROR) logger = logging.getLogger() logger.handlers = [] logger.setLevel(logging.NOTSET) logger.addHandler(zmq_tools.ZMQ_handler(zmq_ctx, ipc_push_url)) # create logger for the context of this function logger = logging.getLogger(__name__) if is_alive_flag.value: # indicates eye process that this is a duplicated startup logger.warning("Aborting redundant eye process startup") return with Is_Alive_Manager(is_alive_flag, ipc_socket, eye_id, logger): # general imports import traceback import numpy as np import cv2 from OpenGL.GL import GL_COLOR_BUFFER_BIT # display import glfw from gl_utils import GLFWErrorReporting GLFWErrorReporting.set_default() from pyglui import ui, graph, cygl from pyglui.cygl.utils import Named_Texture import gl_utils from gl_utils import basic_gl_setup, adjust_gl_view, clear_gl_screen from gl_utils import make_coord_system_pixel_based from gl_utils import make_coord_system_norm_based from gl_utils import is_window_visible, glViewport # monitoring import psutil # Plug-ins from plugin import Plugin_List # helpers/utils from uvc import get_time_monotonic from file_methods import Persistent_Dict from version_utils import parse_version from methods import normalize, denormalize, timer from av_writer import JPEG_Writer, MPEG_Writer, NonMonotonicTimestampError from ndsi import H264Writer from video_capture import source_classes, manager_classes from roi import Roi from background_helper import IPC_Logging_Task_Proxy from pupil_detector_plugins import available_detector_plugins, EVENT_KEY IPC_Logging_Task_Proxy.push_url = ipc_push_url def interrupt_handler(sig, frame): import traceback trace = traceback.format_stack(f=frame) logger.debug(f"Caught signal {sig} in:\n" + "".join(trace)) # NOTE: Interrupt is handled in world/service/player which are responsible for # shutting down the eye process properly signal.signal(signal.SIGINT, interrupt_handler) # UI Platform tweaks if platform.system() == "Linux": scroll_factor = 10.0 window_position_default = (600, 300 * eye_id + 30) elif platform.system() == "Windows": scroll_factor = 10.0 window_position_default = (600, 90 + 300 * eye_id) else: scroll_factor = 1.0 window_position_default = (600, 300 * eye_id) icon_bar_width = 50 window_size = None content_scale = 1.0 # g_pool holds variables for this process g_pool = SimpleNamespace() # make some constants avaiable g_pool.debug = debug g_pool.user_dir = user_dir g_pool.version = version g_pool.app = parent_application g_pool.eye_id = eye_id g_pool.process = f"eye{eye_id}" g_pool.timebase = timebase g_pool.camera_render_size = None g_pool.zmq_ctx = zmq_ctx g_pool.ipc_pub = ipc_socket g_pool.ipc_pub_url = ipc_pub_url g_pool.ipc_sub_url = ipc_sub_url g_pool.ipc_push_url = ipc_push_url def get_timestamp(): return get_time_monotonic() - g_pool.timebase.value g_pool.get_timestamp = get_timestamp g_pool.get_now = get_time_monotonic def load_runtime_pupil_detection_plugins(): from plugin import import_runtime_plugins from pupil_detector_plugins.detector_base_plugin import PupilDetectorPlugin plugins_path = os.path.join(g_pool.user_dir, "plugins") for plugin in import_runtime_plugins(plugins_path): if not isinstance(plugin, type): continue if not issubclass(plugin, PupilDetectorPlugin): continue if plugin is PupilDetectorPlugin: continue yield plugin available_detectors = available_detector_plugins() runtime_detectors = list(load_runtime_pupil_detection_plugins()) plugins = ( manager_classes + source_classes + available_detectors + runtime_detectors + [Roi] ) g_pool.plugin_by_name = {p.__name__: p for p in plugins} preferred_names = [ f"Pupil Cam3 ID{eye_id}", f"Pupil Cam2 ID{eye_id}", f"Pupil Cam1 ID{eye_id}", ] if eye_id == 0: preferred_names += ["HD-6000"] default_capture_name = "UVC_Source" default_capture_settings = { "preferred_names": preferred_names, "frame_size": (192, 192), "frame_rate": 120, } default_plugins = [ # TODO: extend with plugins (default_capture_name, default_capture_settings), ("UVC_Manager", {}), *[(p.__name__, {}) for p in available_detectors], ("NDSI_Manager", {}), ("HMD_Streaming_Manager", {}), ("File_Manager", {}), ("Roi", {}), ] def consume_events_and_render_buffer(): glfw.make_context_current(main_window) clear_gl_screen() if all(c > 0 for c in g_pool.camera_render_size): glViewport(0, 0, *g_pool.camera_render_size) for p in g_pool.plugins: p.gl_display() glViewport(0, 0, *window_size) # render graphs fps_graph.draw() cpu_graph.draw() # render GUI try: clipboard = glfw.get_clipboard_string(main_window).decode() except (AttributeError, glfw.GLFWError): # clipboard is None, might happen on startup clipboard = "" g_pool.gui.update_clipboard(clipboard) user_input = g_pool.gui.update() if user_input.clipboard != clipboard: # only write to clipboard if content changed glfw.set_clipboard_string(main_window, user_input.clipboard) for button, action, mods in user_input.buttons: x, y = glfw.get_cursor_pos(main_window) pos = gl_utils.window_coordinate_to_framebuffer_coordinate( main_window, x, y, cached_scale=None ) pos = normalize(pos, g_pool.camera_render_size) if g_pool.flip: pos = 1 - pos[0], 1 - pos[1] # Position in img pixels pos = denormalize(pos, g_pool.capture.frame_size) for plugin in g_pool.plugins: if plugin.on_click(pos, button, action): break for key, scancode, action, mods in user_input.keys: for plugin in g_pool.plugins: if plugin.on_key(key, scancode, action, mods): break for char_ in user_input.chars: for plugin in g_pool.plugins: if plugin.on_char(char_): break # update screen glfw.swap_buffers(main_window) # Callback functions def on_resize(window, w, h): nonlocal window_size nonlocal content_scale is_minimized = bool(glfw.get_window_attrib(window, glfw.ICONIFIED)) if is_minimized: return # Always clear buffers on resize to make sure that there are no overlapping # artifacts from previous frames. gl_utils.glClear(GL_COLOR_BUFFER_BIT) gl_utils.glClearColor(0, 0, 0, 1) active_window = glfw.get_current_context() glfw.make_context_current(window) content_scale = gl_utils.get_content_scale(window) framebuffer_scale = gl_utils.get_framebuffer_scale(window) g_pool.gui.scale = content_scale window_size = w, h g_pool.camera_render_size = w - int(icon_bar_width * g_pool.gui.scale), h g_pool.gui.update_window(w, h) g_pool.gui.collect_menus() for g in g_pool.graphs: g.scale = content_scale g.adjust_window_size(w, h) adjust_gl_view(w, h) glfw.make_context_current(active_window) # Minimum window size required, otherwise parts of the UI can cause openGL # issues with permanent effects. Depends on the content scale, which can # potentially be dynamically modified, so we re-adjust the size limits every # time here. min_size = int(2 * icon_bar_width * g_pool.gui.scale / framebuffer_scale) glfw.set_window_size_limits( window, min_size, min_size, glfw.DONT_CARE, glfw.DONT_CARE, ) # Needed, to update the window buffer while resizing consume_events_and_render_buffer() def on_window_key(window, key, scancode, action, mods): g_pool.gui.update_key(key, scancode, action, mods) def on_window_char(window, char): g_pool.gui.update_char(char) def on_iconify(window, iconified): g_pool.iconified = iconified def on_window_mouse_button(window, button, action, mods): g_pool.gui.update_button(button, action, mods) def on_pos(window, x, y): x, y = gl_utils.window_coordinate_to_framebuffer_coordinate( window, x, y, cached_scale=None ) g_pool.gui.update_mouse(x, y) pos = x, y pos = normalize(pos, g_pool.camera_render_size) if g_pool.flip: pos = 1 - pos[0], 1 - pos[1] # Position in img pixels pos = denormalize(pos, g_pool.capture.frame_size) for p in g_pool.plugins: p.on_pos(pos) def on_scroll(window, x, y): g_pool.gui.update_scroll(x, y * scroll_factor) def on_drop(window, paths): for plugin in g_pool.plugins: if plugin.on_drop(paths): break # load session persistent settings session_settings = Persistent_Dict( os.path.join(g_pool.user_dir, "user_settings_eye{}".format(eye_id)) ) if parse_version(session_settings.get("version", "0.0")) != g_pool.version: logger.info( "Session setting are from a different version of this app. I will not use those." ) session_settings.clear() camera_is_physically_flipped = eye_id == 0 g_pool.iconified = False g_pool.capture = None g_pool.flip = session_settings.get("flip", camera_is_physically_flipped) g_pool.display_mode = session_settings.get("display_mode", "camera_image") g_pool.display_mode_info_text = { "camera_image": "Raw eye camera image. This uses the least amount of CPU power", "roi": "Click and drag on the blue circles to adjust the region of interest. The region should be as small as possible, but large enough to capture all pupil movements.", "algorithm": "Algorithm display mode overlays a visualization of the pupil detection parameters on top of the eye video. Adjust parameters within the Pupil Detection menu below.", } def set_display_mode_info(val): g_pool.display_mode = val g_pool.display_mode_info.text = g_pool.display_mode_info_text[val] def toggle_general_settings(collapsed): # this is the menu toggle logic. # Only one menu can be open. # If no menu is open the menubar should collapse. g_pool.menubar.collapsed = collapsed for m in g_pool.menubar.elements: m.collapsed = True general_settings.collapsed = collapsed # Initialize glfw glfw.init() glfw.window_hint(glfw.SCALE_TO_MONITOR, glfw.TRUE) if hide_ui: glfw.window_hint(glfw.VISIBLE, 0) # hide window title = "Pupil Capture - eye {}".format(eye_id) # Pupil Cam1 uses 4:3 resolutions. Pupil Cam2 and Cam3 use 1:1 resolutions. # As all Pupil Core and VR/AR add-ons are shipped with Pupil Cam2 and Cam3 # cameras, we adjust the default eye window size to a 1:1 content aspect ratio. # The size of 500 was chosen s.t. the menu still fits. default_window_size = 500 + icon_bar_width, 500 width, height = session_settings.get("window_size", default_window_size) main_window = glfw.create_window(width, height, title, None, None) window_position_manager = gl_utils.WindowPositionManager() window_pos = window_position_manager.new_window_position( window=main_window, default_position=window_position_default, previous_position=session_settings.get("window_position", None), ) glfw.set_window_pos(main_window, window_pos[0], window_pos[1]) glfw.make_context_current(main_window) cygl.utils.init() # gl_state settings basic_gl_setup() g_pool.image_tex = Named_Texture() g_pool.image_tex.update_from_ndarray(np.ones((1, 1), dtype=np.uint8) + 125) # setup GUI g_pool.gui = ui.UI() g_pool.menubar = ui.Scrolling_Menu( "Settings", pos=(-500, 0), size=(-icon_bar_width, 0), header_pos="left" ) g_pool.iconbar = ui.Scrolling_Menu( "Icons", pos=(-icon_bar_width, 0), size=(0, 0), header_pos="hidden" ) g_pool.gui.append(g_pool.menubar) g_pool.gui.append(g_pool.iconbar) general_settings = ui.Growing_Menu("General", header_pos="headline") def set_window_size(): # Get current capture frame size f_width, f_height = g_pool.capture.frame_size # Eye camera resolutions are too small to be used as default window sizes. # We use double their size instead. frame_scale_factor = 2 f_width *= frame_scale_factor f_height *= frame_scale_factor # Get current display scale factor content_scale = gl_utils.get_content_scale(main_window) framebuffer_scale = gl_utils.get_framebuffer_scale(main_window) display_scale_factor = content_scale / framebuffer_scale # Scale the capture frame size by display scale factor f_width *= display_scale_factor f_height *= display_scale_factor # Increas the width to account for the added scaled icon bar width f_width += icon_bar_width * display_scale_factor # Set the newly calculated size (scaled capture frame size + scaled icon bar width) glfw.set_window_size(main_window, int(f_width), int(f_height)) general_settings.append(ui.Button("Reset window size", set_window_size)) general_settings.append(ui.Switch("flip", g_pool, label="Flip image display")) general_settings.append( ui.Selector( "display_mode", g_pool, setter=set_display_mode_info, selection=["camera_image", "roi", "algorithm"], labels=["Camera Image", "ROI", "Algorithm"], label="Mode", ) ) g_pool.display_mode_info = ui.Info_Text( g_pool.display_mode_info_text[g_pool.display_mode] ) general_settings.append(g_pool.display_mode_info) g_pool.menubar.append(general_settings) icon = ui.Icon( "collapsed", general_settings, label=chr(0xE8B8), on_val=False, off_val=True, setter=toggle_general_settings, label_font="pupil_icons", ) icon.tooltip = "General Settings" g_pool.iconbar.append(icon) plugins_to_load = session_settings.get("loaded_plugins", default_plugins) if overwrite_cap_settings: # Ensure that overwrite_cap_settings takes preference over source plugins # with incorrect settings that were loaded from session settings. plugins_to_load.append(overwrite_cap_settings) # Add runtime plugins to the list of plugins to load with default arguments, # if not already restored from session settings plugins_to_load_names = set(name for name, _ in plugins_to_load) for runtime_detector in runtime_detectors: runtime_name = runtime_detector.__name__ if runtime_name not in plugins_to_load_names: plugins_to_load.append((runtime_name, {})) g_pool.plugins = Plugin_List(g_pool, plugins_to_load) if not g_pool.capture: # Make sure we always have a capture running. Important if there was no # capture stored in session settings. g_pool.plugins.add( g_pool.plugin_by_name[default_capture_name], default_capture_settings ) toggle_general_settings(True) g_pool.writer = None g_pool.rec_path = None # Register callbacks main_window glfw.set_framebuffer_size_callback(main_window, on_resize) glfw.set_window_iconify_callback(main_window, on_iconify) glfw.set_key_callback(main_window, on_window_key) glfw.set_char_callback(main_window, on_window_char) glfw.set_mouse_button_callback(main_window, on_window_mouse_button) glfw.set_cursor_pos_callback(main_window, on_pos) glfw.set_scroll_callback(main_window, on_scroll) glfw.set_drop_callback(main_window, on_drop) # load last gui configuration g_pool.gui.configuration = session_settings.get("ui_config", {}) # If previously selected plugin was not loaded this time, we will have an # expanded menubar without any menu selected. We need to ensure the menubar is # collapsed in this case. if all(submenu.collapsed for submenu in g_pool.menubar.elements): g_pool.menubar.collapsed = True # set up performance graphs pid = os.getpid() ps = psutil.Process(pid) ts = g_pool.get_timestamp() cpu_graph = graph.Bar_Graph() cpu_graph.pos = (20, 50) cpu_graph.update_fn = ps.cpu_percent cpu_graph.update_rate = 5 cpu_graph.label = "CPU %0.1f" fps_graph = graph.Bar_Graph() fps_graph.pos = (140, 50) fps_graph.update_rate = 5 fps_graph.label = "%0.0f FPS" g_pool.graphs = [cpu_graph, fps_graph] # set the last saved window size on_resize(main_window, *glfw.get_framebuffer_size(main_window)) should_publish_frames = False frame_publish_format = "jpeg" frame_publish_format_recent_warning = False # create a timer to control window update frequency window_update_timer = timer(1 / 60) def window_should_update(): return next(window_update_timer) logger.warning("Process started.") frame = None if platform.system() == "Darwin": # On macOS, calls to glfw.swap_buffers() deliberately take longer in case of # occluded windows, based on the swap interval value. This causes an FPS drop # and leads to problems when recording. To side-step this behaviour, the swap # interval is set to zero. # # Read more about window occlusion on macOS here: # https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/WorkWhenVisible.html glfw.swap_interval(0) # Event loop window_should_close = False while not window_should_close: if notify_sub.new_data: t, notification = notify_sub.recv() subject = notification["subject"] if subject.startswith("eye_process.should_stop"): if notification["eye_id"] == eye_id: break elif subject == "recording.started": if notification["record_eye"] and g_pool.capture.online: g_pool.rec_path = notification["rec_path"] raw_mode = notification["compression"] start_time_synced = notification["start_time_synced"] logger.info(f"Will save eye video to: {g_pool.rec_path}") video_path = os.path.join( g_pool.rec_path, "eye{}.mp4".format(eye_id) ) if raw_mode and frame and g_pool.capture.jpeg_support: g_pool.writer = JPEG_Writer(video_path, start_time_synced) elif hasattr(g_pool.capture._recent_frame, "h264_buffer"): g_pool.writer = H264Writer( video_path, g_pool.capture.frame_size[0], g_pool.capture.frame_size[1], g_pool.capture.frame_rate, ) else: g_pool.writer = MPEG_Writer(video_path, start_time_synced) elif subject == "recording.stopped": if g_pool.writer: logger.info("Done recording.") try: g_pool.writer.release() except RuntimeError: logger.error("No eye video recorded") else: # TODO: wrap recording logic into plugin g_pool.capture.intrinsics.save( g_pool.rec_path, custom_name=f"eye{eye_id}" ) finally: g_pool.writer = None elif subject.startswith("meta.should_doc"): ipc_socket.notify( { "subject": "meta.doc", "actor": "eye{}".format(eye_id), "doc": eye.__doc__, } ) elif subject.startswith("frame_publishing.started"): should_publish_frames = True frame_publish_format = notification.get("format", "jpeg") elif subject.startswith("frame_publishing.stopped"): should_publish_frames = False frame_publish_format = "jpeg" elif ( subject.startswith("start_eye_plugin") and notification["target"] == g_pool.process ): try: g_pool.plugins.add( g_pool.plugin_by_name[notification["name"]], notification.get("args", {}), ) except KeyError as err: logger.error(f"Attempt to load unknown plugin: {err}") elif ( subject.startswith("stop_eye_plugin") and notification["target"] == g_pool.process ): try: plugin_to_stop = g_pool.plugin_by_name[notification["name"]] except KeyError as err: logger.error(f"Attempt to load unknown plugin: {err}") else: plugin_to_stop.alive = False g_pool.plugins.clean() for plugin in g_pool.plugins: plugin.on_notify(notification) event = {} for plugin in g_pool.plugins: plugin.recent_events(event) frame = event.get("frame") if frame: if should_publish_frames: try: if frame_publish_format == "jpeg": data = frame.jpeg_buffer elif frame_publish_format == "yuv": data = frame.yuv_buffer elif frame_publish_format == "bgr": data = frame.bgr elif frame_publish_format == "gray": data = frame.gray assert data is not None except (AttributeError, AssertionError, NameError): if not frame_publish_format_recent_warning: frame_publish_format_recent_warning = True logger.warning( '{}s are not compatible with format "{}"'.format( type(frame), frame_publish_format ) ) else: frame_publish_format_recent_warning = False pupil_socket.send( { "topic": "frame.eye.{}".format(eye_id), "width": frame.width, "height": frame.height, "index": frame.index, "timestamp": frame.timestamp, "format": frame_publish_format, "__raw_data__": [data], } ) t = frame.timestamp dt, ts = t - ts, t try: fps_graph.add(1.0 / dt) except ZeroDivisionError: pass if g_pool.writer: try: g_pool.writer.write_video_frame(frame) except NonMonotonicTimestampError as e: logger.error( "Recorder received non-monotonic timestamp!" " Stopping the recording!" ) logger.debug(str(e)) ipc_socket.notify({"subject": "recording.should_stop"}) ipc_socket.notify( {"subject": "recording.should_stop", "remote_notify": "all"} ) for result in event.get(EVENT_KEY, ()): pupil_socket.send(result) # GL drawing if window_should_update(): cpu_graph.update() if is_window_visible(main_window): consume_events_and_render_buffer() glfw.poll_events() window_should_close = glfw.window_should_close(main_window) # END while running # in case eye recording was still runnnig: Save&close if g_pool.writer: logger.info("Done recording eye.") g_pool.writer.release() g_pool.writer = None session_settings["loaded_plugins"] = g_pool.plugins.get_initializers() # save session persistent settings session_settings["flip"] = g_pool.flip session_settings["display_mode"] = g_pool.display_mode session_settings["ui_config"] = g_pool.gui.configuration session_settings["version"] = str(g_pool.version) if not hide_ui: glfw.restore_window(main_window) # need to do this for windows os session_settings["window_position"] = glfw.get_window_pos(main_window) session_window_size = glfw.get_window_size(main_window) if 0 not in session_window_size: f_width, f_height = session_window_size if platform.system() in ("Windows", "Linux"): # Store unscaled window size as the operating system will scale the # windows appropriately during launch on Windows and Linux. f_width, f_height = ( f_width / content_scale, f_height / content_scale, ) session_settings["window_size"] = int(f_width), int(f_height) session_settings.close() for plugin in g_pool.plugins: plugin.alive = False g_pool.plugins.clean() glfw.destroy_window(main_window) g_pool.gui.terminate() glfw.terminate() logger.info("Process shutting down.")
def window_size(self) -> T.Tuple[int, int]: if self.__gl_handle is not None: return glfw.get_framebuffer_size(self.__gl_handle) else: return (0, 0)
def render(self): super(GatherViewer, self).render() ctx = MjRenderContext(self.env.wrapped_env.sim) scn = ctx.scn con = ctx.con functions.mjv_makeScene(scn, 1000) scn.camera[0].frustum_near = 0.05 scn.camera[1].frustum_near = 0.05 for obj in self.env.objects: x, y, typ = obj qpos = np.zeros_like(self.green_ball_sim.data.qpos) qpos[0] = x qpos[1] = y if typ == APPLE: self.green_ball_sim.data.qpos[:] = qpos self.green_ball_sim.forward() self.green_ball_renderer.render() self.green_ball_ctx = MjRenderContext(self.green_ball_sim) functions.mjv_addGeoms(self.green_ball_sim.model, self.green_ball_sim.data, self.green_ball_ctx.vopt, self.green_ball_ctx.pert, CAT_ALL, scn) else: self.red_ball_sim.data.qpos[:] = qpos self.red_ball_sim.forward() self.red_ball_renderer.render() self.red_ball_ctx = MjRenderContext(self.red_ball_sim) functions.mjv_addGeoms(self.red_ball_sim.model, self.red_ball_sim.data, self.red_ball_ctx.vopt, self.red_ball_ctx.pert, CAT_ALL, scn) functions.mjv_addGeoms(self.env.wrapped_env.sim.model, self.env.wrapped_env.sim.data, ctx.vopt, ctx.pert, CAT_ALL, scn) functions.mjr_render(self.green_ball_renderer.get_rect(), scn, con) try: import OpenGL.GL as GL except ImportError: return def draw_rect(x, y, width, height): # start drawing a rectangle GL.glBegin(GL.GL_QUADS) # bottom left point GL.glVertex2f(x, y) # bottom right point GL.glVertex2f(x + width, y) # top right point GL.glVertex2f(x + width, y + height) # top left point GL.glVertex2f(x, y + height) def refresh2d(width, height): GL.glViewport(0, 0, width, height) GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadIdentity() GL.glOrtho(0.0, width, 0.0, height, 0.0, 1.0) GL.glMatrixMode(GL.GL_MODELVIEW) GL.glLoadIdentity() GL.glBegin(GL.GL_QUADS) GL.glLoadIdentity() width, height = glfw.get_framebuffer_size(self.window) refresh2d(width, height) GL.glDisable(GL.GL_LIGHTING) GL.glEnable(GL.GL_BLEND) GL.glColor4f(0.0, 0.0, 0.0, 0.8) draw_rect(10, 10, 300, 100) apple_readings, bomb_readings = self.env.get_readings() for idx, reading in enumerate(apple_readings): if reading > 0: GL.glColor4f(0.0, 1.0, 0.0, reading) draw_rect(20 * (idx + 1), 10, 5, 50) for idx, reading in enumerate(bomb_readings): if reading > 0: GL.glColor4f(1.0, 0.0, 0.0, reading) draw_rect(20 * (idx + 1), 60, 5, 50)
def open( self, gui_monitor: GUIMonitor, title: str, is_fullscreen: bool = False, size: T.Tuple[int, int] = None, position: T.Tuple[int, int] = None, ): if self.is_open: # TODO: Warn that the window is already open return if not gui_monitor.is_available: raise ValueError(f"Window requires an available monitor.") has_fixed_size = ((size is not None) and (len(size) == 2) and (size[0] > 0) and (size[1] > 0)) if is_fullscreen and has_fixed_size: raise ValueError( f"Fullscreen is mutually exclusive to having a fixed size.") if position is None: if platform.system() == "Windows": position = (8, 90) else: position = (0, 0) if is_fullscreen: size = gui_monitor.size # NOTE: Always creating windowed window here, even if in fullscreen mode. On # windows you might experience a black screen for up to 1 sec when creating # a blank window directly in fullscreen mode. By creating it windowed and # then switching to fullscreen it will stay white the entire time. self.__gl_handle = glfw.create_window(*size, title, None, glfw.get_current_context()) if not is_fullscreen: glfw.set_window_pos(self.__gl_handle, *position) # Register callbacks glfw.set_framebuffer_size_callback(self.__gl_handle, self.on_resize) glfw.set_key_callback(self.__gl_handle, self.on_key) glfw.set_mouse_button_callback(self.__gl_handle, self.on_mouse_button) self.on_resize(self.__gl_handle, *glfw.get_framebuffer_size(self.__gl_handle)) # gl_state settings with self._switch_to_current_context(): gl_utils.basic_gl_setup() glfw.swap_interval(0) if is_fullscreen: # Switch to full screen here. See NOTE above at glfw.create_window(). glfw.set_window_monitor( self.__gl_handle, gui_monitor.unsafe_handle, 0, 0, *gui_monitor.size, gui_monitor.refresh_rate, )
def player(rec_dir, ipc_pub_url, ipc_sub_url, ipc_push_url, user_dir, app_version, debug): # general imports from time import sleep import logging from glob import glob from time import time, strftime, localtime # networking import zmq import zmq_tools import numpy as np # zmq ipc setup zmq_ctx = zmq.Context() ipc_pub = zmq_tools.Msg_Dispatcher(zmq_ctx, ipc_push_url) notify_sub = zmq_tools.Msg_Receiver(zmq_ctx, ipc_sub_url, topics=("notify", )) # log setup logging.getLogger("OpenGL").setLevel(logging.ERROR) logger = logging.getLogger() logger.handlers = [] logger.setLevel(logging.NOTSET) logger.addHandler(zmq_tools.ZMQ_handler(zmq_ctx, ipc_push_url)) # create logger for the context of this function logger = logging.getLogger(__name__) try: from background_helper import IPC_Logging_Task_Proxy IPC_Logging_Task_Proxy.push_url = ipc_push_url from tasklib.background.patches import IPCLoggingPatch IPCLoggingPatch.ipc_push_url = ipc_push_url # imports from file_methods import Persistent_Dict, next_export_sub_dir from OpenGL.GL import GL_COLOR_BUFFER_BIT # display import glfw from gl_utils import GLFWErrorReporting GLFWErrorReporting.set_default() # check versions for our own depedencies as they are fast-changing from pyglui import __version__ as pyglui_version from pyglui import ui, cygl from pyglui.cygl.utils import Named_Texture, RGBA import gl_utils # capture from video_capture import File_Source # helpers/utils from version_utils import parse_version from methods import normalize, denormalize, delta_t, get_system_info import player_methods as pm from pupil_recording import PupilRecording from csv_utils import write_key_value_file from hotkey import Hotkey # Plug-ins from plugin import Plugin, Plugin_List, import_runtime_plugins from plugin_manager import Plugin_Manager from vis_circle import Vis_Circle from vis_cross import Vis_Cross from vis_polyline import Vis_Polyline from vis_light_points import Vis_Light_Points from vis_watermark import Vis_Watermark from vis_fixation import Vis_Fixation from seek_control import Seek_Control from surface_tracker import Surface_Tracker_Offline # from marker_auto_trim_marks import Marker_Auto_Trim_Marks from fixation_detector import Offline_Fixation_Detector from log_display import Log_Display from annotations import Annotation_Player from raw_data_exporter import Raw_Data_Exporter from log_history import Log_History from pupil_producers import ( DisabledPupilProducer, Pupil_From_Recording, Offline_Pupil_Detection, ) from gaze_producer.gaze_from_recording import GazeFromRecording from gaze_producer.gaze_from_offline_calibration import ( GazeFromOfflineCalibration, ) from pupil_detector_plugins.detector_base_plugin import PupilDetectorPlugin from system_graphs import System_Graphs from system_timelines import System_Timelines from blink_detection import Offline_Blink_Detection from audio_playback import Audio_Playback from video_export.plugins.imotions_exporter import iMotions_Exporter from video_export.plugins.eye_video_exporter import Eye_Video_Exporter from video_export.plugins.world_video_exporter import World_Video_Exporter from head_pose_tracker.offline_head_pose_tracker import ( Offline_Head_Pose_Tracker, ) from video_capture import File_Source from video_overlay.plugins import Video_Overlay, Eye_Overlay from pupil_recording import ( assert_valid_recording_type, InvalidRecordingException, ) assert parse_version(pyglui_version) >= parse_version( "1.29"), "pyglui out of date, please upgrade to newest version" process_was_interrupted = False def interrupt_handler(sig, frame): import traceback trace = traceback.format_stack(f=frame) logger.debug(f"Caught signal {sig} in:\n" + "".join(trace)) nonlocal process_was_interrupted process_was_interrupted = True signal.signal(signal.SIGINT, interrupt_handler) runtime_plugins = import_runtime_plugins( os.path.join(user_dir, "plugins")) runtime_plugins = [ p for p in runtime_plugins if not issubclass(p, PupilDetectorPlugin) ] system_plugins = [ Log_Display, Seek_Control, Plugin_Manager, System_Graphs, System_Timelines, Audio_Playback, ] user_plugins = [ Vis_Circle, Vis_Fixation, Vis_Polyline, Vis_Light_Points, Vis_Cross, Vis_Watermark, Eye_Overlay, Video_Overlay, Offline_Fixation_Detector, Offline_Blink_Detection, Surface_Tracker_Offline, Raw_Data_Exporter, Annotation_Player, Log_History, DisabledPupilProducer, Pupil_From_Recording, Offline_Pupil_Detection, GazeFromRecording, GazeFromOfflineCalibration, World_Video_Exporter, iMotions_Exporter, Eye_Video_Exporter, Offline_Head_Pose_Tracker, ] + runtime_plugins plugins = system_plugins + user_plugins def consume_events_and_render_buffer(): gl_utils.glViewport(0, 0, *g_pool.camera_render_size) g_pool.capture.gl_display() for p in g_pool.plugins: p.gl_display() gl_utils.glViewport(0, 0, *window_size) try: clipboard = glfw.get_clipboard_string(main_window).decode() except (AttributeError, glfw.GLFWError): # clipbaord is None, might happen on startup clipboard = "" g_pool.gui.update_clipboard(clipboard) user_input = g_pool.gui.update() if user_input.clipboard and user_input.clipboard != clipboard: # only write to clipboard if content changed glfw.set_clipboard_string(main_window, user_input.clipboard) for b in user_input.buttons: button, action, mods = b x, y = glfw.get_cursor_pos(main_window) pos = gl_utils.window_coordinate_to_framebuffer_coordinate( main_window, x, y, cached_scale=None) pos = normalize(pos, g_pool.camera_render_size) pos = denormalize(pos, g_pool.capture.frame_size) for plugin in g_pool.plugins: if plugin.on_click(pos, button, action): break for key, scancode, action, mods in user_input.keys: for plugin in g_pool.plugins: if plugin.on_key(key, scancode, action, mods): break for char_ in user_input.chars: for plugin in g_pool.plugins: if plugin.on_char(char_): break glfw.swap_buffers(main_window) # Callback functions def on_resize(window, w, h): nonlocal window_size nonlocal content_scale if w == 0 or h == 0: return # Always clear buffers on resize to make sure that there are no overlapping # artifacts from previous frames. gl_utils.glClear(GL_COLOR_BUFFER_BIT) gl_utils.glClearColor(0, 0, 0, 1) content_scale = gl_utils.get_content_scale(window) framebuffer_scale = gl_utils.get_framebuffer_scale(window) g_pool.gui.scale = content_scale window_size = w, h g_pool.camera_render_size = w - int( icon_bar_width * g_pool.gui.scale), h g_pool.gui.update_window(*window_size) g_pool.gui.collect_menus() for p in g_pool.plugins: p.on_window_resize(window, *g_pool.camera_render_size) # Minimum window size required, otherwise parts of the UI can cause openGL # issues with permanent effects. Depends on the content scale, which can # potentially be dynamically modified, so we re-adjust the size limits every # time here. min_size = int(2 * icon_bar_width * g_pool.gui.scale / framebuffer_scale) glfw.set_window_size_limits( window, min_size, min_size, glfw.DONT_CARE, glfw.DONT_CARE, ) # Needed, to update the window buffer while resizing consume_events_and_render_buffer() def on_window_key(window, key, scancode, action, mods): g_pool.gui.update_key(key, scancode, action, mods) def on_window_char(window, char): g_pool.gui.update_char(char) def on_window_mouse_button(window, button, action, mods): g_pool.gui.update_button(button, action, mods) def on_pos(window, x, y): x, y = gl_utils.window_coordinate_to_framebuffer_coordinate( window, x, y, cached_scale=None) g_pool.gui.update_mouse(x, y) pos = x, y pos = normalize(pos, g_pool.camera_render_size) # Position in img pixels pos = denormalize(pos, g_pool.capture.frame_size) for p in g_pool.plugins: p.on_pos(pos) def on_scroll(window, x, y): g_pool.gui.update_scroll(x, y * scroll_factor) def on_drop(window, paths): for path in paths: try: assert_valid_recording_type(path) _restart_with_recording(path) return except InvalidRecordingException as err: logger.debug(str(err)) for plugin in g_pool.plugins: if plugin.on_drop(paths): break def _restart_with_recording(rec_dir): logger.debug("Starting new session with '{}'".format(rec_dir)) ipc_pub.notify({ "subject": "player_drop_process.should_start", "rec_dir": rec_dir }) glfw.set_window_should_close(g_pool.main_window, True) tick = delta_t() def get_dt(): return next(tick) recording = PupilRecording(rec_dir) meta_info = recording.meta_info # log info about Pupil Platform and Platform in player.log logger.info("Application Version: {}".format(app_version)) logger.info("System Info: {}".format(get_system_info())) logger.debug(f"Debug flag: {debug}") icon_bar_width = 50 window_size = None content_scale = 1.0 # create container for globally scoped vars g_pool = SimpleNamespace() g_pool.app = "player" g_pool.process = "player" g_pool.zmq_ctx = zmq_ctx g_pool.ipc_pub = ipc_pub g_pool.ipc_pub_url = ipc_pub_url g_pool.ipc_sub_url = ipc_sub_url g_pool.ipc_push_url = ipc_push_url g_pool.plugin_by_name = {p.__name__: p for p in plugins} g_pool.camera_render_size = None video_path = recording.files().core().world().videos()[0].resolve() File_Source( g_pool, timing="external", source_path=video_path, buffered_decoding=True, fill_gaps=True, ) # load session persistent settings session_settings = Persistent_Dict( os.path.join(user_dir, "user_settings_player")) if parse_version(session_settings.get("version", "0.0")) != app_version: logger.info( "Session setting are a different version of this app. I will not use those." ) session_settings.clear() width, height = g_pool.capture.frame_size width += icon_bar_width width, height = session_settings.get("window_size", (width, height)) window_name = f"Pupil Player: {meta_info.recording_name} - {rec_dir}" glfw.init() glfw.window_hint(glfw.SCALE_TO_MONITOR, glfw.TRUE) main_window = glfw.create_window(width, height, window_name, None, None) window_position_manager = gl_utils.WindowPositionManager() window_pos = window_position_manager.new_window_position( window=main_window, default_position=window_position_default, previous_position=session_settings.get("window_position", None), ) glfw.set_window_pos(main_window, window_pos[0], window_pos[1]) glfw.make_context_current(main_window) cygl.utils.init() g_pool.main_window = main_window g_pool.version = app_version g_pool.timestamps = g_pool.capture.timestamps g_pool.get_timestamp = lambda: 0.0 g_pool.user_dir = user_dir g_pool.rec_dir = rec_dir g_pool.meta_info = meta_info g_pool.min_data_confidence = session_settings.get( "min_data_confidence", MIN_DATA_CONFIDENCE_DEFAULT) g_pool.min_calibration_confidence = session_settings.get( "min_calibration_confidence", MIN_CALIBRATION_CONFIDENCE_DEFAULT) # populated by producers g_pool.pupil_positions = pm.PupilDataBisector() g_pool.gaze_positions = pm.Bisector() g_pool.fixations = pm.Affiliator() g_pool.eye_movements = pm.Affiliator() def set_data_confidence(new_confidence): g_pool.min_data_confidence = new_confidence notification = {"subject": "min_data_confidence_changed"} notification["_notify_time_"] = time() + 0.8 g_pool.ipc_pub.notify(notification) def do_export(_): left_idx = g_pool.seek_control.trim_left right_idx = g_pool.seek_control.trim_right export_range = left_idx, right_idx + 1 # exclusive range.stop export_ts_window = pm.exact_window(g_pool.timestamps, (left_idx, right_idx)) export_dir = os.path.join(g_pool.rec_dir, "exports") export_dir = next_export_sub_dir(export_dir) os.makedirs(export_dir) logger.info('Created export dir at "{}"'.format(export_dir)) export_info = { "Player Software Version": str(g_pool.version), "Data Format Version": meta_info.min_player_version, "Export Date": strftime("%d.%m.%Y", localtime()), "Export Time": strftime("%H:%M:%S", localtime()), "Frame Index Range:": g_pool.seek_control.get_frame_index_trim_range_string(), "Relative Time Range": g_pool.seek_control.get_rel_time_trim_range_string(), "Absolute Time Range": g_pool.seek_control.get_abs_time_trim_range_string(), } with open(os.path.join(export_dir, "export_info.csv"), "w") as csv: write_key_value_file(csv, export_info) notification = { "subject": "should_export", "range": export_range, "ts_window": export_ts_window, "export_dir": export_dir, } g_pool.ipc_pub.notify(notification) def reset_restart(): logger.warning("Resetting all settings and restarting Player.") glfw.set_window_should_close(main_window, True) ipc_pub.notify({"subject": "clear_settings_process.should_start"}) ipc_pub.notify({ "subject": "player_process.should_start", "rec_dir": rec_dir, "delay": 2.0, }) def toggle_general_settings(collapsed): # this is the menu toggle logic. # Only one menu can be open. # If no menu is open the menubar should collapse. g_pool.menubar.collapsed = collapsed for m in g_pool.menubar.elements: m.collapsed = True general_settings.collapsed = collapsed g_pool.gui = ui.UI() g_pool.menubar = ui.Scrolling_Menu("Settings", pos=(-500, 0), size=(-icon_bar_width, 0), header_pos="left") g_pool.iconbar = ui.Scrolling_Menu("Icons", pos=(-icon_bar_width, 0), size=(0, 0), header_pos="hidden") g_pool.timelines = ui.Container((0, 0), (0, 0), (0, 0)) g_pool.timelines.horizontal_constraint = g_pool.menubar g_pool.user_timelines = ui.Timeline_Menu("User Timelines", pos=(0.0, -150.0), size=(0.0, 0.0), header_pos="headline") g_pool.user_timelines.color = RGBA(a=0.0) g_pool.user_timelines.collapsed = True # add container that constaints itself to the seekbar height vert_constr = ui.Container((0, 0), (0, -50.0), (0, 0)) vert_constr.append(g_pool.user_timelines) g_pool.timelines.append(vert_constr) def set_window_size(): # Get current capture frame size f_width, f_height = g_pool.capture.frame_size # Get current display scale factor content_scale = gl_utils.get_content_scale(main_window) framebuffer_scale = gl_utils.get_framebuffer_scale(main_window) display_scale_factor = content_scale / framebuffer_scale # Scale the capture frame size by display scale factor f_width *= display_scale_factor f_height *= display_scale_factor # Increas the width to account for the added scaled icon bar width f_width += icon_bar_width * display_scale_factor # Set the newly calculated size (scaled capture frame size + scaled icon bar width) glfw.set_window_size(main_window, int(f_width), int(f_height)) general_settings = ui.Growing_Menu("General", header_pos="headline") general_settings.append(ui.Button("Reset window size", set_window_size)) general_settings.append( ui.Info_Text( f"Minimum Player Version: {meta_info.min_player_version}")) general_settings.append( ui.Info_Text(f"Player Version: {g_pool.version}")) general_settings.append( ui.Info_Text( f"Recording Software: {meta_info.recording_software_name}")) general_settings.append( ui.Info_Text( f"Recording Software Version: {meta_info.recording_software_version}" )) general_settings.append( ui.Info_Text( "High level data, e.g. fixations, or visualizations only consider gaze data that has an equal or higher confidence than the minimum data confidence." )) general_settings.append( ui.Slider( "min_data_confidence", g_pool, setter=set_data_confidence, step=0.05, min=0.0, max=1.0, label="Minimum data confidence", )) general_settings.append( ui.Button("Restart with default settings", reset_restart)) g_pool.menubar.append(general_settings) icon = ui.Icon( "collapsed", general_settings, label=chr(0xE8B8), on_val=False, off_val=True, setter=toggle_general_settings, label_font="pupil_icons", ) icon.tooltip = "General Settings" g_pool.iconbar.append(icon) user_plugin_separator = ui.Separator() user_plugin_separator.order = 0.35 g_pool.iconbar.append(user_plugin_separator) g_pool.quickbar = ui.Stretching_Menu("Quick Bar", (0, 100), (100, -100)) g_pool.export_button = ui.Thumb( "export", label=chr(0xE2C5), getter=lambda: False, setter=do_export, hotkey=Hotkey.EXPORT_START_PLAYER_HOTKEY(), label_font="pupil_icons", ) g_pool.quickbar.extend([g_pool.export_button]) g_pool.gui.append(g_pool.menubar) g_pool.gui.append(g_pool.timelines) g_pool.gui.append(g_pool.iconbar) g_pool.gui.append(g_pool.quickbar) # we always load these plugins _pupil_producer_plugins = [ # In priority order (first is default) ("Pupil_From_Recording", {}), ("Offline_Pupil_Detection", {}), ("DisabledPupilProducer", {}), ] _pupil_producer_plugins = list(reversed(_pupil_producer_plugins)) _gaze_producer_plugins = [ # In priority order (first is default) ("GazeFromRecording", {}), ("GazeFromOfflineCalibration", {}), ] _gaze_producer_plugins = list(reversed(_gaze_producer_plugins)) default_plugins = [ ("Plugin_Manager", {}), ("Seek_Control", {}), ("Log_Display", {}), ("Raw_Data_Exporter", {}), ("Vis_Polyline", {}), ("Vis_Circle", {}), ("System_Graphs", {}), ("System_Timelines", {}), ("World_Video_Exporter", {}), *_pupil_producer_plugins, *_gaze_producer_plugins, ("Audio_Playback", {}), ] _plugins_to_load = session_settings.get("loaded_plugins", None) if _plugins_to_load is None: # If no plugins are available from a previous session, # then use the default plugin list _plugins_to_load = default_plugins else: # If there are plugins available from a previous session, # then prepend plugins that are required, but might have not been available before _plugins_to_load = [ *_pupil_producer_plugins, *_gaze_producer_plugins, *_plugins_to_load, ] g_pool.plugins = Plugin_List(g_pool, _plugins_to_load) # Manually add g_pool.capture to the plugin list g_pool.plugins._plugins.append(g_pool.capture) g_pool.plugins._plugins.sort(key=lambda p: p.order) g_pool.capture.init_ui() general_settings.insert( -1, ui.Text_Input( "rel_time_trim_section", getter=g_pool.seek_control.get_rel_time_trim_range_string, setter=g_pool.seek_control.set_rel_time_trim_range_string, label="Relative time range to export", ), ) general_settings.insert( -1, ui.Text_Input( "frame_idx_trim_section", getter=g_pool.seek_control.get_frame_index_trim_range_string, setter=g_pool.seek_control.set_frame_index_trim_range_string, label="Frame index range to export", ), ) # Register callbacks main_window glfw.set_framebuffer_size_callback(main_window, on_resize) glfw.set_key_callback(main_window, on_window_key) glfw.set_char_callback(main_window, on_window_char) glfw.set_mouse_button_callback(main_window, on_window_mouse_button) glfw.set_cursor_pos_callback(main_window, on_pos) glfw.set_scroll_callback(main_window, on_scroll) glfw.set_drop_callback(main_window, on_drop) toggle_general_settings(True) g_pool.gui.configuration = session_settings.get("ui_config", {}) # If previously selected plugin was not loaded this time, we will have an # expanded menubar without any menu selected. We need to ensure the menubar is # collapsed in this case. if all(submenu.collapsed for submenu in g_pool.menubar.elements): g_pool.menubar.collapsed = True # gl_state settings gl_utils.basic_gl_setup() g_pool.image_tex = Named_Texture() # trigger on_resize on_resize(main_window, *glfw.get_framebuffer_size(main_window)) def handle_notifications(n): subject = n["subject"] if subject == "start_plugin": g_pool.plugins.add(g_pool.plugin_by_name[n["name"]], args=n.get("args", {})) elif subject.startswith("meta.should_doc"): ipc_pub.notify({ "subject": "meta.doc", "actor": g_pool.app, "doc": player.__doc__ }) for p in g_pool.plugins: if (p.on_notify.__doc__ and p.__class__.on_notify != Plugin.on_notify): ipc_pub.notify({ "subject": "meta.doc", "actor": p.class_name, "doc": p.on_notify.__doc__, }) while not glfw.window_should_close( main_window) and not process_was_interrupted: # fetch newest notifications new_notifications = [] while notify_sub.new_data: t, n = notify_sub.recv() new_notifications.append(n) # notify each plugin if there are new notifications: for n in new_notifications: handle_notifications(n) for p in g_pool.plugins: p.on_notify(n) events = {} # report time between now and the last loop interation events["dt"] = get_dt() # pupil and gaze positions are added by their respective producer plugins events["pupil"] = [] events["gaze"] = [] # allow each Plugin to do its work. for p in g_pool.plugins: p.recent_events(events) # check if a plugin need to be destroyed g_pool.plugins.clean() glfw.make_context_current(main_window) glfw.poll_events() # render visual feedback from loaded plugins if gl_utils.is_window_visible(main_window): gl_utils.glViewport(0, 0, *g_pool.camera_render_size) g_pool.capture.gl_display() for p in g_pool.plugins: p.gl_display() gl_utils.glViewport(0, 0, *window_size) try: clipboard = glfw.get_clipboard_string(main_window).decode() except (AttributeError, glfw.GLFWError): # clipbaord is None, might happen on startup clipboard = "" g_pool.gui.update_clipboard(clipboard) user_input = g_pool.gui.update() if user_input.clipboard and user_input.clipboard != clipboard: # only write to clipboard if content changed glfw.set_clipboard_string(main_window, user_input.clipboard) for b in user_input.buttons: button, action, mods = b x, y = glfw.get_cursor_pos(main_window) pos = gl_utils.window_coordinate_to_framebuffer_coordinate( main_window, x, y, cached_scale=None) pos = normalize(pos, g_pool.camera_render_size) pos = denormalize(pos, g_pool.capture.frame_size) for plugin in g_pool.plugins: if plugin.on_click(pos, button, action): break for key, scancode, action, mods in user_input.keys: for plugin in g_pool.plugins: if plugin.on_key(key, scancode, action, mods): break for char_ in user_input.chars: for plugin in g_pool.plugins: if plugin.on_char(char_): break # present frames at appropriate speed g_pool.seek_control.wait(events["frame"].timestamp) glfw.swap_buffers(main_window) session_settings["loaded_plugins"] = g_pool.plugins.get_initializers() session_settings["min_data_confidence"] = g_pool.min_data_confidence session_settings[ "min_calibration_confidence"] = g_pool.min_calibration_confidence session_settings["ui_config"] = g_pool.gui.configuration session_settings["window_position"] = glfw.get_window_pos(main_window) session_settings["version"] = str(g_pool.version) session_window_size = glfw.get_window_size(main_window) if 0 not in session_window_size: f_width, f_height = session_window_size if platform.system() in ("Windows", "Linux"): f_width, f_height = ( f_width / content_scale, f_height / content_scale, ) session_settings["window_size"] = int(f_width), int(f_height) session_settings.close() # de-init all running plugins for p in g_pool.plugins: p.alive = False g_pool.plugins.clean() g_pool.gui.terminate() glfw.destroy_window(main_window) except Exception: import traceback trace = traceback.format_exc() logger.error("Process Player crashed with trace:\n{}".format(trace)) finally: logger.info("Process shutting down.") ipc_pub.notify({"subject": "player_process.stopped"}) sleep(1.0)
sys.exit() glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) # Create a windowed mode window and its OpenGL context window = glfw.create_window(500, 500, "Scene 1", None, None) if not window: glfw.terminate() sys.exit() # Make the window's context current glfw.make_context_current(window) # Get window size width, height = glfw.get_framebuffer_size(window) def on_resize(window, width, height): gui.setWindowHeight(height) gui.setWindowWidth(width) pass # Install a window size handler glfw.set_window_size_callback(window, on_resize) def on_mouse(window, button, action, mods): pass glfw.set_mouse_button_callback(window, on_mouse) old_time = time.time()
def runProgram(title, startWidth, startHeight, renderFrame, initResources=None, drawUi=None, update=None): global g_simpleShader global g_vertexArrayObject global g_vertexDataBuffer global g_mousePos global g_coordinateSystemModel global g_numMsaaSamples global g_currentMsaaSamples if not glfw.init(): sys.exit(1) window, impl = initGlFwAndResources(title, startWidth, startHeight, initResources) currentTime = glfw.get_time() prevMouseX, prevMouseY = glfw.get_cursor_pos(window) while not glfw.window_should_close(window): prevTime = currentTime currentTime = glfw.get_time() dt = currentTime - prevTime keyStateMap = {} for name, id in g_glfwKeymap.items(): keyStateMap[name] = glfw.get_key(window, id) == glfw.PRESS for name, id in g_glfwMouseMap.items(): keyStateMap[name] = glfw.get_mouse_button(window, id) == glfw.PRESS mouseX, mouseY = glfw.get_cursor_pos(window) g_mousePos = [mouseX, mouseY] # Udpate 'game logic' if update: imIo = imgui.get_io() mouseDelta = [mouseX - prevMouseX, mouseY - prevMouseY] if imIo.want_capture_mouse: mouseDelta = [0, 0] update(dt, keyStateMap, mouseDelta) prevMouseX, prevMouseY = mouseX, mouseY width, height = glfw.get_framebuffer_size(window) imgui.new_frame() imgui.set_next_window_position(5.0, 5.0) imgui.set_next_window_size(400.0, 620.0, imgui.FIRST_USE_EVER) imgui.begin("UI", 0) if drawUi: drawUi(width, height) drawWidth = width uiWidth = 0 drawWidth -= uiWidth renderFrame(uiWidth, drawWidth, height) #drawCoordinateSystem() #mgui.show_test_window() imgui.end() imgui.render() # Swap front and back buffers glfw.swap_buffers(window) # Poll for and process events glfw.poll_events() impl.process_inputs() glfw.terminate()
def __init__(self, win, *args, **kwargs): """Set up the backend window according the params of the PsychoPy win Before PsychoPy 1.90.0 this code was executed in Window._setupPygame() Parameters ---------- win : psychopy.visual.Window instance PsychoPy Window (usually not fully created yet). share : psychopy.visual.Window instance PsychoPy Window to share a context with bpc : array_like Bits per color (R, G, B). refreshHz : int Refresh rate in Hertz. depthBits : int, Framebuffer (back buffer) depth bits. stencilBits : int Framebuffer (back buffer) stencil bits. swapInterval : int Screen updates before swapping buffers. winTitle : str Optional window title string. *args Additional position arguments. **kwargs Additional keyword arguments. """ BaseBackend.__init__(self, win) # window to share a context with share_win = kwargs.get('share', None) if share_win is not None: if share_win.winType == 'glfw': share_context = share_win.winHandle else: logging.warning( 'Cannot share a context with a non-GLFW window. Disabling.' ) share_context = None else: share_context = None if sys.platform == 'darwin' and not win.useRetina and pyglet.version >= "1.3": raise ValueError("As of PsychoPy 1.85.3 OSX windows should all be " "set to useRetina=True (or remove the argument). " "Pyglet 1.3 appears to be forcing " "us to use retina on any retina-capable screen " "so setting to False has no effect.") # window framebuffer configuration win.bpc = kwargs.get('bpc', (8, 8, 8)) # nearly all displays use 8 bpc win.refreshHz = int(kwargs.get('refreshHz', 60)) win.depthBits = int(kwargs.get('depthBits', 8)) win.stencilBits = int(kwargs.get('stencilBits', 8)) # TODO - make waitBlanking set this too, independent right now win.swapInterval = int(kwargs.get('swapInterval', 1)) # vsync ON if 1 # get monitors, with GLFW the primary display is ALWAYS at index 0 allScrs = glfw.get_monitors() if len(allScrs) < int(win.screen) + 1: logging.warn("Requested an unavailable screen number - " "using first available.") win.screen = 0 this_screen = allScrs[win.screen] if win.autoLog: logging.info('configured GLFW screen %i' % win.screen) # find a matching video mode (can we even support this configuration?) vidmode_is_supported = False for vidmode in glfw.get_video_modes(this_screen): _size, _bpc, _hz = vidmode if win._isFullScr: # size and refresh rate are ignored if windowed has_size = _size == tuple(win.size) has_hz = _hz == win.refreshHz else: has_size = has_hz = True has_bpc = _bpc == tuple(win.bpc) if has_size and has_bpc and has_hz: vidmode_is_supported = True break _size, _bpc, _hz = glfw.get_video_mode(this_screen) if not vidmode_is_supported: # the requested video mode is not supported, use current logging.warning( ("The specified video mode is not supported by this display, " "using native mode ...")) logging.warning( ("Overriding user video settings: size {} -> {}, bpc {} -> " "{}, refreshHz {} -> {}".format(tuple(win.size), _size, tuple(win.bpc), _bpc, win.refreshHz, _hz))) # change the window settings win.bpc = _bpc win.refreshHz = _hz win.size = _size if win._isFullScr: use_display = this_screen else: use_display = None # configure stereo use_stereo = 0 if win.stereo: # provide warning if stereo buffers are requested but unavailable if not glfw.extension_supported('GL_STEREO'): logging.warning( 'A stereo window was requested but the graphics ' 'card does not appear to support GL_STEREO') win.stereo = False else: use_stereo = 1 # setup multisampling # This enables multisampling on the window backbuffer, not on other # framebuffers. msaa_samples = 0 if win.multiSample: max_samples = (GL.GLint)() GL.glGetIntegerv(GL.GL_MAX_SAMPLES, max_samples) if (win.numSamples & (win.numSamples - 1)) != 0: # power of two? logging.warning( 'Invalid number of MSAA samples provided, must be ' 'power of two. Disabling.') elif 0 > win.numSamples > max_samples.value: # check if within range logging.warning( 'Invalid number of MSAA samples provided, outside of valid ' 'range. Disabling.') else: msaa_samples = win.numSamples win.multiSample = msaa_samples > 0 # disable stencil buffer if win.allowStencil: win.stencilBits = 0 # set buffer configuration hints glfw.window_hint(glfw.RED_BITS, win.bpc[0]) glfw.window_hint(glfw.GREEN_BITS, win.bpc[1]) glfw.window_hint(glfw.BLUE_BITS, win.bpc[2]) glfw.window_hint(glfw.REFRESH_RATE, win.refreshHz) glfw.window_hint(glfw.STEREO, use_stereo) glfw.window_hint(glfw.SAMPLES, msaa_samples) glfw.window_hint(glfw.STENCIL_BITS, win.stencilBits) glfw.window_hint(glfw.DEPTH_BITS, win.depthBits) # window appearance and behaviour hints if not win.allowGUI: glfw.window_hint(glfw.DECORATED, 0) glfw.window_hint(glfw.AUTO_ICONIFY, 0) # window title title_text = str(kwargs.get('winTitle', "PsychoPy (GLFW)")) # create the window self.winHandle = glfw.create_window(width=win.size[0], height=win.size[1], title=title_text, monitor=use_display, share=share_context) # set the window icon glfw.set_window_icon(self.winHandle, 1, _WINDOW_ICON_) # The window's user pointer maps the Python Window object to its GLFW # representation. glfw.set_window_user_pointer(self.winHandle, win) glfw.make_context_current(self.winHandle) # ready to use # set the window size to the framebuffer size win.size = np.array(glfw.get_framebuffer_size(self.winHandle)) if win.useFBO: # check for necessary extensions if not glfw.extension_supported('GL_EXT_framebuffer_object'): msg = ("Trying to use a framebuffer object but " "GL_EXT_framebuffer_object is not supported. Disabled") logging.warn(msg) win.useFBO = False if not glfw.extension_supported('GL_ARB_texture_float'): msg = ("Trying to use a framebuffer object but " "GL_ARB_texture_float is not supported. Disabling") logging.warn(msg) win.useFBO = False # Assign event callbacks, these are dispatched when 'poll_events' is # called. glfw.set_mouse_button_callback(self.winHandle, event._onGLFWMouseButton) glfw.set_scroll_callback(self.winHandle, event._onGLFWMouseScroll) glfw.set_key_callback(self.winHandle, event._onGLFWKey) glfw.set_char_mods_callback(self.winHandle, event._onGLFWText) # enable vsync, GLFW has additional setting for this that might be # useful. glfw.swap_interval(win.swapInterval) # give the window class GLFW specific methods win.setMouseType = self.setMouseType if not win.allowGUI: self.setMouseVisibility(False) #glfw.set_window_size_callback(self.winHandle, _onResize) #self.winHandle.on_resize = _onResize # avoid circular reference # TODO - handle window resizing # Set the position of the window if not fullscreen. if not win.pos: # work out where the centre should be win.pos = [(_size[0] - win.size[0]) / 2.0, (_size[1] - win.size[1]) / 2.0] if not win._isFullScr: # get the virtual position of the monitor, apply offset to pos _px, _py = glfw.get_monitor_pos(this_screen) glfw.set_window_pos(self.winHandle, int(win.pos[0] + _px), int(win.pos[1] + _py))
def __init__( self, module, width, height, caption, scale, palette, fps, border_width, border_color, ): if glfw.get_version() < tuple(map(int, GLFW_VERSION.split("."))): raise RuntimeError( "glfw version is lower than {}".format(GLFW_VERSION)) if width > APP_SCREEN_MAX_SIZE or height > APP_SCREEN_MAX_SIZE: raise ValueError("screen size is larger than {}x{}".format( APP_SCREEN_MAX_SIZE, APP_SCREEN_MAX_SIZE)) self._module = module self._palette = palette[:] self._pil_palette = self._get_pil_palette(palette) self._fps = fps self._border_width = border_width self._border_color = border_color self._next_update_time = 0 self._one_frame_time = 1 / fps self._key_state = {} self._update = None self._draw = None self._capture_start = 0 self._capture_index = 0 self._capture_images = [None] * APP_GIF_CAPTURE_COUNT self._perf_monitor_is_enabled = False self._perf_fps_count = 0 self._perf_fps_start_time = 0 self._perf_fps = 0 self._perf_update_count = 0 self._perf_update_total_time = 0 self._perf_update_time = 0 self._perf_draw_count = 0 self._perf_draw_total_time = 0 self._perf_draw_time = 0 module.width = width module.height = height module.mouse_x = 0 module.mouse_y = 0 module.frame_count = 0 # initialize window if not glfw.init(): exit() monitor = glfw.get_primary_monitor() display_width, display_height = glfw.get_video_mode(monitor)[0] if scale == 0: scale = max( min( (display_width // width) - APP_SCREEN_SCALE_CUTDOWN, (display_height // height) - APP_SCREEN_SCALE_CUTDOWN, ), APP_SCREEN_SCALE_MINIMUM, ) window_width = width * scale + border_width window_height = height * scale + border_width self._window = glfw.create_window(window_width, window_height, caption, None, None) if not self._window: glfw.terminate() exit() glfw.set_window_pos( self._window, (display_width - window_width) // 2, (display_height - window_height) // 2, ) glfw.make_context_current(self._window) glfw.set_window_size_limits(self._window, width, height, glfw.DONT_CARE, glfw.DONT_CARE) self._hidpi_scale = (glfw.get_framebuffer_size(self._window)[0] / glfw.get_window_size(self._window)[0]) self._update_viewport() glfw.set_key_callback(self._window, self._key_callback) glfw.set_cursor_pos_callback(self._window, self._cursor_pos_callback) glfw.set_mouse_button_callback(self._window, self._mouse_button_callback) glfw.set_window_icon(self._window, 1, [self._get_icon_image()]) # initialize renderer self._renderer = Renderer(width, height) # initialize audio player self._audio_player = AudioPlayer() # export module functions module.btn = self.btn module.btnp = self.btnp module.btnr = self.btnr module.run = self.run module.run_with_profiler = self.run_with_profiler module.quit = self.quit module.save = self.save module.load = self.load module.image = self._renderer.image module.tilemap = self._renderer.tilemap module.clip = self._renderer.draw_command.clip module.pal = self._renderer.draw_command.pal module.cls = self._renderer.draw_command.cls module.pix = self._renderer.draw_command.pix module.line = self._renderer.draw_command.line module.rect = self._renderer.draw_command.rect module.rectb = self._renderer.draw_command.rectb module.circ = self._renderer.draw_command.circ module.circb = self._renderer.draw_command.circb module.blt = self._renderer.draw_command.blt module.bltm = self._renderer.draw_command.bltm module.text = self._renderer.draw_command.text module.sound = self._audio_player.sound module.play = self._audio_player.play # module.playm = self._audio_player.playm module.stop = self._audio_player.stop
def __init__(self): if not glfw.init(): return glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 2) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, GL_TRUE) window = glfw.create_window(self.WIDTH, self.HEIGHT, self.TITLE, None, None) glfw.set_window_size_limits(window, 320, 480, glfw.DONT_CARE, glfw.DONT_CARE) if not window: glfw.terminate() return glfw.make_context_current(window) glfw.set_key_callback(window, self.key_callback) glfw.set_window_size_callback(window, self.reshape) width, height = glfw.get_framebuffer_size(window) glViewport(0, 0, width, height) aspect_ratio = width / height glClearColor(0.2, 0.3, 0.2, 1.0) glEnable(GL_DEPTH_TEST) self.ball = Ball(TEXTILE_TEXTURE) ball_shader = Shader(BASE_VS, BASE_FS) self.ball.prep(ball_shader, aspect_ratio, 0.5, 85) self.platform = Platform(BUCKET_TEXTURE) shader = Shader(BASE_VS, BASE_FS) self.platform.prep(shader, aspect_ratio, 1.0, 85) self.hearts = [] for i in range(0, self.MAX_FAIL): heart = LiveHeart([-3.0 + i * 0.5, 5.5, 0.0]) heart_shader = Shader(HEART_VS, HEART_FS) heart.prep(heart_shader, aspect_ratio, 0.3, 85) self.hearts.append(heart) self.bg = Background(WOOD_TEXTURE) bg_shader = Shader(BASE_VS, BASE_FS) self.bg.prep(bg_shader, aspect_ratio, 11.0, 85) while not glfw.window_should_close(window): glClearColor(0.0, 0.3, 0.3, 1.0) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glDisable(GL_DEPTH_TEST) self.bg.draw() glEnable(GL_DEPTH_TEST) self.platform.draw(self.game_status_play) self.ball.draw(self.game_status_play) if self.collision_detect(): if self.fails == self.MAX_FAIL: self.game_status_play = False for heart in self.hearts: heart.draw() glfw.swap_buffers(window) glfw.poll_events() glfw.terminate()
def __init__(self, module, width, height, caption, scale, palette, fps, border_width, border_color): self._module = module self._palette = palette[:] self._pil_palette = self._get_pil_palette(palette) self._fps = fps self._border_width = border_width self._border_color = border_color self._next_update_time = 0 self._one_frame_time = 1 / fps self._key_state = {} self._update = None self._draw = None self._capture_start = 0 self._capture_index = 0 self._capture_images = [None] * APP_SCREEN_CAPTURE_COUNT self._perf_monitor_is_enabled = False self._perf_fps_count = 0 self._perf_fps_start_time = 0 self._perf_fps = 0 self._perf_update_count = 0 self._perf_update_total_time = 0 self._perf_update_time = 0 self._perf_draw_count = 0 self._perf_draw_total_time = 0 self._perf_draw_time = 0 module.width = width module.height = height module.mouse_x = 0 module.mouse_y = 0 module.frame_count = 0 # initialize window if not glfw.init(): exit() window_width = width * scale + border_width window_height = height * scale + border_width self._window = glfw.create_window(window_width, window_height, caption, None, None) if not self._window: glfw.terminate() exit() glfw.make_context_current(self._window) glfw.set_window_size_limits(self._window, width, height, glfw.DONT_CARE, glfw.DONT_CARE) self._hidpi_scale = (glfw.get_framebuffer_size(self._window)[0] / glfw.get_window_size(self._window)[0]) self._update_viewport() glfw.set_key_callback(self._window, self._key_callback) glfw.set_cursor_pos_callback(self._window, self._cursor_pos_callback) glfw.set_mouse_button_callback(self._window, self._mouse_button_callback) glfw.set_window_icon(self._window, 1, [self._get_icon_image()]) # initialize renderer self._renderer = Renderer(width, height) # initialize audio player self._audio_player = AudioPlayer() # export module functions module.btn = self.btn module.btnp = self.btnp module.btnr = self.btnr module.run = self.run module.quit = self.quit module.image = self._renderer.image module.clip = self._renderer.draw_command.clip module.pal = self._renderer.draw_command.pal module.cls = self._renderer.draw_command.cls module.pix = self._renderer.draw_command.pix module.line = self._renderer.draw_command.line module.rect = self._renderer.draw_command.rect module.rectb = self._renderer.draw_command.rectb module.circ = self._renderer.draw_command.circ module.circb = self._renderer.draw_command.circb module.blt = self._renderer.draw_command.blt module.text = self._renderer.draw_command.text module.sound = self._audio_player.sound module.play = self._audio_player.play module.stop = self._audio_player.stop
def get_physical_size(self): psize = glfw.get_framebuffer_size(self.__window) return int(psize[0]), int(psize[1])
def main(): useLiveCamera = True #gc.disable() # # transform to convert the image to tensor # transform = transforms.Compose([ # transforms.ToTensor() # ]) # # initialize the model # model = torchvision.models.detection.keypointrcnn_resnet50_fpn(pretrained=True, # num_keypoints=17) # # set the computation device # device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # # load the modle on to the computation device and set to eval mode # model.to(device).eval() # initialize glfw if not glfw.init(): return glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) #creating the window window = glfw.create_window(1600, 900, "PyGLFusion", None, None) if not window: glfw.terminate() return glfw.make_context_current(window) imgui.create_context() impl = GlfwRenderer(window) # rendering glClearColor(0.2, 0.3, 0.2, 1.0) # positions texture coords quad = [ -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0 ] quad = np.array(quad, dtype=np.float32) indices = [0, 1, 2, 2, 3, 0] indices = np.array(indices, dtype=np.uint32) screenVertex_shader = (Path(__file__).parent / 'shaders/ScreenQuad.vert').read_text() screenFragment_shader = (Path(__file__).parent / 'shaders/ScreenQuad.frag').read_text() renderShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(screenVertex_shader, GL_VERTEX_SHADER), OpenGL.GL.shaders.compileShader(screenFragment_shader, GL_FRAGMENT_SHADER)) # set up VAO and VBO for full screen quad drawing calls VAO = glGenVertexArrays(1) glBindVertexArray(VAO) VBO = glGenBuffers(1) glBindBuffer(GL_ARRAY_BUFFER, VBO) glBufferData(GL_ARRAY_BUFFER, 80, quad, GL_STATIC_DRAW) EBO = glGenBuffers(1) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO) glBufferData(GL_ELEMENT_ARRAY_BUFFER, 24, indices, GL_STATIC_DRAW) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 20, ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 20, ctypes.c_void_p(12)) glEnableVertexAttribArray(1) # shaders bilateralFilter_shader = (Path(__file__).parent / 'shaders/bilateralFilter.comp').read_text() bilateralFilterShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(bilateralFilter_shader, GL_COMPUTE_SHADER)) alignDepthColor_shader = (Path(__file__).parent / 'shaders/alignDepthColor.comp').read_text() alignDepthColorShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(alignDepthColor_shader, GL_COMPUTE_SHADER)) depthToVertex_shader = (Path(__file__).parent / 'shaders/depthToVertex.comp').read_text() depthToVertexShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(depthToVertex_shader, GL_COMPUTE_SHADER)) vertexToNormal_shader = (Path(__file__).parent / 'shaders/vertexToNormal.comp').read_text() vertexToNormalShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(vertexToNormal_shader, GL_COMPUTE_SHADER)) raycast_shader = (Path(__file__).parent / 'shaders/raycast.comp').read_text() raycastShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(raycast_shader, GL_COMPUTE_SHADER)) integrate_shader = (Path(__file__).parent / 'shaders/integrate.comp').read_text() integrateShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(integrate_shader, GL_COMPUTE_SHADER)) trackP2P_shader = (Path(__file__).parent / 'shaders/p2pTrack.comp').read_text() trackP2PShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(trackP2P_shader, GL_COMPUTE_SHADER)) reduceP2P_shader = (Path(__file__).parent / 'shaders/p2pReduce.comp').read_text() reduceP2PShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(reduceP2P_shader, GL_COMPUTE_SHADER)) trackP2V_shader = (Path(__file__).parent / 'shaders/p2vTrack.comp').read_text() trackP2VShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(trackP2V_shader, GL_COMPUTE_SHADER)) reduceP2V_shader = (Path(__file__).parent / 'shaders/p2vReduce.comp').read_text() reduceP2VShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(reduceP2V_shader, GL_COMPUTE_SHADER)) LDLT_shader = (Path(__file__).parent / 'shaders/LDLT.comp').read_text() LDLTShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(LDLT_shader, GL_COMPUTE_SHADER)) # Splatter globalMapUpdate_shader = (Path(__file__).parent / 'shaders/GlobalMapUpdate.comp').read_text() globalMapUpdateShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(globalMapUpdate_shader, GL_COMPUTE_SHADER)) indexMapGenVert_shader = (Path(__file__).parent / 'shaders/IndexMapGeneration.vert').read_text() indexMapGenFrag_shader = (Path(__file__).parent / 'shaders/IndexMapGeneration.frag').read_text() IndexMapGenerationShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(indexMapGenVert_shader, GL_VERTEX_SHADER), OpenGL.GL.shaders.compileShader(indexMapGenFrag_shader, GL_FRAGMENT_SHADER)) SurfaceSplattingVert_shader = ( Path(__file__).parent / 'shaders/SurfaceSplatting.vert').read_text() SurfaceSplattingFrag_shader = ( Path(__file__).parent / 'shaders/SurfaceSplatting.frag').read_text() SurfaceSplattingShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(SurfaceSplattingVert_shader, GL_VERTEX_SHADER), OpenGL.GL.shaders.compileShader(SurfaceSplattingFrag_shader, GL_FRAGMENT_SHADER)) UnnecessaryPointRemoval_shader = ( Path(__file__).parent / 'shaders/UnnecessaryPointRemoval.comp').read_text() UnnecessaryPointRemovalShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(UnnecessaryPointRemoval_shader, GL_COMPUTE_SHADER)) # P2V expm_shader = (Path(__file__).parent / 'shaders/expm.comp').read_text() expmShader = OpenGL.GL.shaders.compileProgram( OpenGL.GL.shaders.compileShader(expm_shader, GL_COMPUTE_SHADER)) d2c, c2d, K, invK, colK = camera.start(useLiveCamera) shaderDict = { 'renderShader': renderShader, 'bilateralFilterShader': bilateralFilterShader, 'alignDepthColorShader': alignDepthColorShader, 'depthToVertexShader': depthToVertexShader, 'vertexToNormalShader': vertexToNormalShader, 'raycastVolumeShader': raycastShader, 'integrateVolumeShader': integrateShader, 'trackP2PShader': trackP2PShader, 'reduceP2PShader': reduceP2PShader, 'trackP2VShader': trackP2VShader, 'reduceP2VShader': reduceP2VShader, 'LDLTShader': LDLTShader, 'globalMapUpdate': globalMapUpdateShader, 'indexMapGeneration': IndexMapGenerationShader, 'surfaceSplatting': SurfaceSplattingShader, 'unnecessaryPointRemoval': UnnecessaryPointRemovalShader, 'expm': expmShader } bufferDict = { 'p2pReduction': -1, 'p2pRedOut': -1, 'p2vReduction': -1, 'p2vRedOut': -1, 'test': -1, 'outBuf': -1, 'poseBuffer': -1, 'globalMap0': -1, 'globalMap1': -1, 'atomic0': -1, 'atomic1': -1 } textureDict = { 'rawColor': -1, 'lastColor': -1, 'nextColor': -1, 'rawDepth': -1, 'filteredDepth': -1, 'lastDepth': -1, 'nextDepth': -1, 'refVertex': -1, 'refNormal': -1, 'virtualVertex': -1, 'virtualNormal': -1, 'virtualDepth': -1, 'virtualColor': -1, 'mappingC2D': -1, 'mappingD2C': -1, 'xyLUT': -1, 'tracking': -1, 'volume': -1, 'indexMap': -1 } fboDict = {'indexMap': -1, 'virtualFrame': -1} # 'iters' : (2, 5, 10), fusionConfig = { 'volSize': (128, 128, 128), 'volDim': (1.0, 1.0, 1.0), 'iters': (2, 2, 2), 'initOffset': (0, 0, 0), 'maxWeight': 100.0, 'distThresh': 0.05, 'normThresh': 0.9, 'nearPlane': 0.1, 'farPlane': 4.0, 'maxMapSize': 5000000, 'c_stable': 10.0, 'sigma': 0.6 } cameraConfig = { 'depthWidth': 640, 'depthHeight': 576, 'colorWidth': 1920, 'colorHeight': 1080, 'd2c': d2c, 'c2d': c2d, 'depthScale': 0.001, 'K': K, 'invK': invK, 'colK': colK } textureDict = frame.generateTextures(textureDict, cameraConfig, fusionConfig) bufferDict = frame.generateBuffers(bufferDict, cameraConfig, fusionConfig) colorMat = np.zeros( (cameraConfig['colorHeight'], cameraConfig['colorWidth'], 3), dtype="uint8") useColorMat = False integrateFlag = True resetFlag = True initPose = glm.mat4() initPose[3, 0] = fusionConfig['volDim'][0] / 2.0 initPose[3, 1] = fusionConfig['volDim'][1] / 2.0 initPose[3, 2] = 0 blankResult = np.array([0, 0, 0, 0, 0, 0], dtype='float32') glBindBuffer(GL_SHADER_STORAGE_BUFFER, bufferDict['poseBuffer']) glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, 16 * 4, glm.value_ptr(initPose)) glBufferSubData(GL_SHADER_STORAGE_BUFFER, 16 * 4, 16 * 4, glm.value_ptr(glm.inverse(initPose))) glBufferSubData(GL_SHADER_STORAGE_BUFFER, 16 * 4 * 2, 16 * 4, glm.value_ptr(glm.mat4(1.0))) glBufferSubData(GL_SHADER_STORAGE_BUFFER, 16 * 4 * 3, 16 * 4, glm.value_ptr(glm.mat4(1.0))) glBufferSubData(GL_SHADER_STORAGE_BUFFER, 16 * 4 * 4, 6 * 4, blankResult) glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0) mouseX, mouseY = 0, 0 clickedPoint3D = glm.vec4(fusionConfig['volDim'][0] / 2.0, fusionConfig['volDim'][1] / 2.0, 0, 0) sliderDim = fusionConfig['volDim'][0] #[32 64 128 256 512] currentSize = math.log2(fusionConfig['volSize'][0]) - 5 volumeStatsChanged = False currPose = initPose # splatter stuff frameCount = 0 fboDict = frame.generateFrameBuffers(fboDict, textureDict, cameraConfig) initAtomicCount = np.array([0], dtype='uint32') mapSize = np.array([0], dtype='uint32') glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, bufferDict['atomic0']) glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, 4, initAtomicCount) glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0) glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, bufferDict['atomic1']) glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, 4, initAtomicCount) glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0) # aa = torch.tensor([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], dtype=torch.float32, device=torch.device('cuda')) # bb = torch.tensor([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], dtype=torch.float32, device=torch.device('cuda')) # #setup pycuda gl interop needs to be after openGL is init # import pycuda.gl.autoinit # import pycuda.gl # cuda_gl = pycuda.gl # cuda_driver = pycuda.driver # from pycuda.compiler import SourceModule # import pycuda # pycuda_source_ssbo = cuda_gl.RegisteredBuffer(int(bufferDict['test']), cuda_gl.graphics_map_flags.NONE) # sm = SourceModule(""" # __global__ void simpleCopy(float *inputArray, float *outputArray) { # unsigned int x = blockIdx.x*blockDim.x + threadIdx.x; # outputArray[x] = inputArray[x]; # inputArray[x] = 8008.135f; # } # """) # cuda_function = sm.get_function("simpleCopy") # mappingObj = pycuda_source_ssbo.map() # data, size = mappingObj.device_ptr_and_size() # cuda_function(np.intp(aa.data_ptr()), np.intp(data), block=(8, 1, 1)) # mappingObj.unmap() # glBindBuffer(GL_SHADER_STORAGE_BUFFER, bufferDict['test']) # tee = glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, 32) # glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0) # teeData = np.frombuffer(tee, dtype=np.float32) # print(teeData) # modTensor = aa.cpu().data.numpy() # print(modTensor) #fusionConfig['initOffset'] = (initPose[3,0], initPose[3,1], initPose[3,2]) # LUTs #createXYLUT(k4a, textureDict, cameraConfig) <-- bug in this person.init() while not glfw.window_should_close(window): glfw.poll_events() impl.process_inputs() imgui.new_frame() sTime = time.perf_counter() try: capture = camera.getFrames(useLiveCamera) if capture.color is not None: #if useLiveCamera == False: #if k4a.configuration["color_format"] == ImageFormat.COLOR_MJPG: # colorMat = cv2.imdecode(capture.color, cv2.IMREAD_COLOR) # useColorMat = True glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, textureDict['rawColor']) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, int(cameraConfig['colorWidth']), int(cameraConfig['colorHeight']), (GL_RGB, GL_RGBA)[useLiveCamera], GL_UNSIGNED_BYTE, (capture.color, colorMat)[useColorMat]) if capture.depth is not None: glActiveTexture(GL_TEXTURE1) glBindTexture(GL_TEXTURE_2D, textureDict['rawDepth']) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, int(cameraConfig['depthWidth']), int(cameraConfig['depthHeight']), GL_RED, GL_UNSIGNED_SHORT, capture.depth) except EOFError: break # #smallMat = cv2.pyrDown(colorMat) # start_time = time.time() # rotMat = cv2.flip(colorMat, 0) # pil_image = Image.fromarray(rotMat).convert('RGB') # image = transform(pil_image) # image = image.unsqueeze(0).to(device) # end_time = time.time() # print((end_time - start_time) * 1000.0) # with torch.no_grad(): # outputs = model(image) # output_image = utils.draw_keypoints(outputs, rotMat) # cv2.imshow('Face detection frame', output_image) # if cv2.waitKey(1) & 0xFF == ord('q'): # break person.getPose(textureDict, cameraConfig, capture.color) frame.bilateralFilter(shaderDict, textureDict, cameraConfig) frame.depthToVertex(shaderDict, textureDict, cameraConfig, fusionConfig) frame.alignDepthColor(shaderDict, textureDict, cameraConfig, fusionConfig) frame.vertexToNormal(shaderDict, textureDict, cameraConfig) frame.mipmapTextures(textureDict) #currPose = track.runP2P(shaderDict, textureDict, bufferDict, cameraConfig, fusionConfig, currPose, integrateFlag, resetFlag) currPose = track.runP2V(shaderDict, textureDict, bufferDict, cameraConfig, fusionConfig, currPose, integrateFlag, resetFlag) #mapSize = track.runSplatter(shaderDict, textureDict, bufferDict, fboDict, cameraConfig, fusionConfig, mapSize, frameCount, integrateFlag, resetFlag) frameCount += 1 if resetFlag == True: resetFlag = False integrateFlag = True imgui.begin("Menu", True) if imgui.button("Reset"): fusionConfig['volSize'] = (1 << (currentSize + 5), 1 << (currentSize + 5), 1 << (currentSize + 5)) fusionConfig['volDim'] = (sliderDim, sliderDim, sliderDim) currPose, integrateFlag, resetFlag = track.reset( textureDict, bufferDict, cameraConfig, fusionConfig, clickedPoint3D) volumeStatsChanged = False if imgui.button("Integrate"): integrateFlag = not integrateFlag imgui.same_line() imgui.checkbox("", integrateFlag) changedDim, sliderDim = imgui.slider_float("dim", sliderDim, min_value=0.01, max_value=5.0) clickedSize, currentSize = imgui.combo( "size", currentSize, ["32", "64", "128", "256", "512"]) if imgui.is_mouse_clicked(): if not imgui.is_any_item_active(): mouseX, mouseY = imgui.get_mouse_pos() w, h = glfw.get_framebuffer_size(window) xPos = ((mouseX % int(w / 3)) / (w / 3) * cameraConfig['depthWidth']) yPos = (mouseY / (h)) * cameraConfig['depthHeight'] clickedDepth = capture.depth[ int(yPos + 0.5), int(xPos + 0.5)] * cameraConfig['depthScale'] clickedPoint3D = clickedDepth * ( cameraConfig['invK'] * glm.vec4(xPos, yPos, 1.0, 0.0)) volumeStatsChanged = True if changedDim or clickedSize: volumeStatsChanged = True imgui.end() graphics.render(VAO, window, shaderDict, textureDict) imgui.render() impl.render(imgui.get_draw_data()) eTime = time.perf_counter() #print((eTime-sTime) * 1000, mapSize[0]) glfw.swap_buffers(window) glfw.terminate() if useLiveCamera == True: camera.stop()
def run(self): """Run the main game loop logic""" # Shorten the variables world = self.world rendering_system = self.rendering_system window = self.window impl = ImGuiGlfwRenderer(window) # set the variables from the world object world.terrain = Terrain() world.terrain.load("data/track_01_128.png", rendering_system) world.racer = Racer() world.racer.load("data/racer_02.obj", world.terrain) current_time = glfw.get_time() prev_mouse_x, prev_mouse_y = glfw.get_cursor_pos(window) while not glfw.window_should_close(window): prev_time = current_time current_time = glfw.get_time() dt = current_time - prev_time key_state_map = {} for item_name, item_id in GLFW_KEYMAP.items(): key_state_map[item_name] = glfw.get_key(window, item_id) == glfw.PRESS for item_name, item_id in GLFW_MOUSE_MAP.items(): key_state_map[item_name] = glfw.get_mouse_button( window, item_id) == glfw.PRESS imgui.new_frame() imgui.set_next_window_size(430.0, 450.0, imgui.FIRST_USE_EVER) imgui.begin("Tweak variables") mouse_x, mouse_y = glfw.get_cursor_pos(window) mouse_delta = [mouse_x - prev_mouse_x, mouse_y - prev_mouse_y] prev_mouse_x, prev_mouse_y = mouse_x, mouse_y # Update 'world logic' im_io = imgui.get_io() if im_io.want_capture_mouse: mouse_delta = [0, 0] update(world, rendering_system, dt, key_state_map, mouse_delta) width, height = glfw.get_framebuffer_size(window) renderFrame(world, rendering_system, width, height) # mgui.show_test_window() imgui.end() imgui.render() # Swap front and back buffers glfw.swap_buffers(window) # Poll for and process events glfw.poll_events() impl.process_inputs() # This is the end of the game. Do some cleanup glfw.destroy_window(window) glfw.terminate()
def __init__( self, module, width, height, caption, scale, palette, fps, border_width, border_color, ): if glfw.get_version() < tuple(map(int, GLFW_VERSION.split("."))): raise RuntimeError( "glfw version is lower than {}".format(GLFW_VERSION)) if width > APP_SCREEN_MAX_SIZE or height > APP_SCREEN_MAX_SIZE: raise ValueError("screen size is larger than {}x{}".format( APP_SCREEN_MAX_SIZE, APP_SCREEN_MAX_SIZE)) global pyxel pyxel = module self._palette = palette[:] self._fps = fps self._border_width = border_width self._border_color = border_color self._next_update_time = 0 self._one_frame_time = 1 / fps self._key_state = {} self._is_mouse_visible = False self._update = None self._draw = None self._capture_start = 0 self._capture_count = 0 self._capture_images = [None] * APP_GIF_CAPTURE_COUNT self._perf_monitor_is_enabled = False self._perf_fps_count = 0 self._perf_fps_start_time = 0 self._perf_fps = 0 self._perf_update_count = 0 self._perf_update_total_time = 0 self._perf_update_time = 0 self._perf_draw_count = 0 self._perf_draw_total_time = 0 self._perf_draw_time = 0 # exports variables pyxel._app = self pyxel.width = width pyxel.height = height pyxel.mouse_x = 0 pyxel.mouse_y = 0 pyxel.frame_count = 0 # initialize window if not glfw.init(): exit() monitor = glfw.get_primary_monitor() display_width, display_height = glfw.get_video_mode(monitor)[0] if scale == 0: scale = max( min( (display_width // width) - APP_SCREEN_SCALE_CUTDOWN, (display_height // height) - APP_SCREEN_SCALE_CUTDOWN, ), APP_SCREEN_SCALE_MINIMUM, ) window_width = width * scale + border_width window_height = height * scale + border_width self._window = glfw.create_window(window_width, window_height, caption, None, None) if not self._window: glfw.terminate() exit() glfw.set_window_pos( self._window, (display_width - window_width) // 2, (display_height - window_height) // 2, ) glfw.make_context_current(self._window) glfw.set_window_size_limits(self._window, width, height, glfw.DONT_CARE, glfw.DONT_CARE) self._hidpi_scale = (glfw.get_framebuffer_size(self._window)[0] / glfw.get_window_size(self._window)[0]) self._update_viewport() glfw.set_key_callback(self._window, self._key_callback) glfw.set_mouse_button_callback(self._window, self._mouse_button_callback) glfw.set_window_icon(self._window, 1, [utilities.get_icon_image()]) glfw.set_input_mode(self._window, glfw.CURSOR, glfw.CURSOR_HIDDEN) # initialize renderer self._renderer = Renderer(width, height) # initialize audio player self._audio_player = AudioPlayer() # export module functions pyxel.btn = self.btn pyxel.btnp = self.btnp pyxel.btnr = self.btnr pyxel.mouse = self.mouse pyxel.run = self.run pyxel.run_with_profiler = self.run_with_profiler pyxel.quit = self.quit pyxel.save = self.save pyxel.load = self.load pyxel.image = self._renderer.image pyxel.tilemap = self._renderer.tilemap pyxel.clip = self._renderer.draw_command.clip pyxel.pal = self._renderer.draw_command.pal pyxel.cls = self._renderer.draw_command.cls pyxel.pix = self._renderer.draw_command.pix pyxel.line = self._renderer.draw_command.line pyxel.rect = self._renderer.draw_command.rect pyxel.rectb = self._renderer.draw_command.rectb pyxel.circ = self._renderer.draw_command.circ pyxel.circb = self._renderer.draw_command.circb pyxel.blt = self._renderer.draw_command.blt pyxel.bltm = self._renderer.draw_command.bltm pyxel.text = self._renderer.draw_command.text pyxel.sound = self._audio_player.sound pyxel.music = self._audio_player.music pyxel.play = self._audio_player.play pyxel.playm = self._audio_player.playm pyxel.stop = self._audio_player.stop # initialize mouse cursor pyxel.image(3, system=True).set(MOUSE_CURSOR_IMAGE_X, MOUSE_CURSOR_IMAGE_Y, MOUSE_CURSOR_DATA)
def __init__( self, g_pool, window_size=window_size_default, window_position=None, gui_scale=1.0, ui_config={}, ): super().__init__(g_pool) self.texture = np.zeros((1, 1, 3), dtype=np.uint8) + 128 glfw.init() glfw.window_hint(glfw.SCALE_TO_MONITOR, glfw.TRUE) if g_pool.hide_ui: glfw.window_hint(glfw.VISIBLE, 0) # hide window main_window = glfw.create_window(*window_size, "Pupil Service", None, None) window_position_manager = gl_utils.WindowPositionManager() window_position = window_position_manager.new_window_position( window=main_window, default_position=window_position_default, previous_position=window_position, ) glfw.set_window_pos(main_window, *window_position) glfw.make_context_current(main_window) cygl.utils.init() g_pool.main_window = main_window g_pool.gui = ui.UI() g_pool.menubar = ui.Scrolling_Menu("Settings", pos=(0, 0), size=(0, 0), header_pos="headline") g_pool.gui.append(g_pool.menubar) # Callback functions def on_resize(window, w, h): # Always clear buffers on resize to make sure that there are no overlapping # artifacts from previous frames. gl_utils.glClear(gl_utils.GL_COLOR_BUFFER_BIT) gl_utils.glClearColor(0, 0, 0, 1) self.window_size = w, h self.content_scale = gl_utils.get_content_scale(window) g_pool.gui.scale = self.content_scale g_pool.gui.update_window(w, h) g_pool.gui.collect_menus() # Needed, to update the window buffer while resizing self.update_ui() def on_window_key(window, key, scancode, action, mods): g_pool.gui.update_key(key, scancode, action, mods) def on_window_char(window, char): g_pool.gui.update_char(char) def on_window_mouse_button(window, button, action, mods): g_pool.gui.update_button(button, action, mods) def on_pos(window, x, y): x, y = gl_utils.window_coordinate_to_framebuffer_coordinate( window, x, y, cached_scale=None) g_pool.gui.update_mouse(x, y) def on_scroll(window, x, y): g_pool.gui.update_scroll(x, y * scroll_factor) def set_window_size(): # Get default window size f_width, f_height = window_size_default # Get current display scale factor content_scale = gl_utils.get_content_scale(main_window) framebuffer_scale = gl_utils.get_framebuffer_scale(main_window) display_scale_factor = content_scale / framebuffer_scale # Scale the capture frame size by display scale factor f_width *= display_scale_factor f_height *= display_scale_factor # Set the newly calculated size (scaled capture frame size + scaled icon bar width) glfw.set_window_size(main_window, int(f_width), int(f_height)) def reset_restart(): logger.warning("Resetting all settings and restarting Capture.") glfw.set_window_should_close(main_window, True) self.notify_all({"subject": "clear_settings_process.should_start"}) self.notify_all({ "subject": "service_process.should_start", "delay": 2.0 }) g_pool.menubar.append(ui.Button("Reset window size", set_window_size)) pupil_remote_addr = "{}:{}".format( socket.gethostbyname(socket.gethostname()), g_pool.preferred_remote_port) g_pool.menubar.append( ui.Text_Input( "pupil_remote_addr", getter=lambda: pupil_remote_addr, setter=lambda x: None, label="Pupil Remote address", )) g_pool.menubar.append( ui.Switch( "eye0_process", label="Detect eye 0", setter=lambda alive: self.start_stop_eye(0, alive), getter=lambda: g_pool.eye_procs_alive[0].value, )) g_pool.menubar.append( ui.Switch( "eye1_process", label="Detect eye 1", setter=lambda alive: self.start_stop_eye(1, alive), getter=lambda: g_pool.eye_procs_alive[1].value, )) g_pool.menubar.append( ui.Info_Text("Service Version: {}".format(g_pool.version))) g_pool.menubar.append( ui.Button("Restart with default settings", reset_restart)) # Register callbacks main_window glfw.set_framebuffer_size_callback(main_window, on_resize) glfw.set_key_callback(main_window, on_window_key) glfw.set_char_callback(main_window, on_window_char) glfw.set_mouse_button_callback(main_window, on_window_mouse_button) glfw.set_cursor_pos_callback(main_window, on_pos) glfw.set_scroll_callback(main_window, on_scroll) g_pool.gui.configuration = ui_config gl_utils.basic_gl_setup() on_resize(g_pool.main_window, *glfw.get_framebuffer_size(main_window))
def __init__(self, win, *args, **kwargs): """Set up the backend window according the params of the PsychoPy win Before PsychoPy 1.90.0 this code was executed in Window._setupPygame() Parameters ---------- win : psychopy.visual.Window instance PsychoPy Window (usually not fully created yet). share : psychopy.visual.Window instance PsychoPy Window to share a context with bpc : array_like Bits per color (R, G, B). refreshHz : int Refresh rate in Hertz. depthBits : int, Framebuffer (back buffer) depth bits. swapInterval : int Swap interval for the current OpenGL context. stencilBits : int Framebuffer (back buffer) stencil bits. winTitle : str Optional window title string. *args Additional position arguments. **kwargs Additional keyword arguments. """ BaseBackend.__init__(self, win) # window to share a context with shareWin = kwargs.get('share', None) if shareWin is not None: if shareWin.winType == 'glfw': shareContext = shareWin.winHandle else: logging.warning( 'Cannot share a context with a non-GLFW window. Disabling.') shareContext = None else: shareContext = None if sys.platform=='darwin' and not win.useRetina and pyglet.version >= "1.3": raise ValueError("As of PsychoPy 1.85.3 OSX windows should all be " "set to useRetina=True (or remove the argument). " "Pyglet 1.3 appears to be forcing " "us to use retina on any retina-capable screen " "so setting to False has no effect.") # window framebuffer configuration win.bpc = kwargs.get('bpc', (8, 8, 8)) # nearly all displays use 8 bpc win.refreshHz = int(kwargs.get('refreshHz', 60)) win.depthBits = int(kwargs.get('depthBits', 8)) win.stencilBits = int(kwargs.get('stencilBits', 8)) # win.swapInterval = int(kwargs.get('swapInterval', 1)) # vsync ON if 1 # get monitors, with GLFW the primary display is ALWAYS at index 0 allScrs = glfw.get_monitors() if len(allScrs) < int(win.screen) + 1: logging.warn("Requested an unavailable screen number - " "using first available.") win.screen = 0 thisScreen = allScrs[win.screen] if win.autoLog: logging.info('configured GLFW screen %i' % win.screen) # find a matching video mode (can we even support this configuration?) isVidmodeSupported = False for vidmode in glfw.get_video_modes(thisScreen): size, bpc, hz = vidmode if win._isFullScr: # size and refresh rate are ignored if windowed hasSize = size == tuple(win.size) hasHz = hz == win.refreshHz else: hasSize = hasHz = True hasBpc = bpc == tuple(win.bpc) if hasSize and hasBpc and hasHz: isVidmodeSupported = True break nativeVidmode = glfw.get_video_mode(thisScreen) if not isVidmodeSupported: # the requested video mode is not supported, use current logging.warning( ("The specified video mode is not supported by this display, " "using native mode ...")) logging.warning( ("Overriding user video settings: size {} -> {}, bpc {} -> " "{}, refreshHz {} -> {}".format( tuple(win.size), nativeVidmode[0], tuple(win.bpc), nativeVidmode[1], win.refreshHz, nativeVidmode[2]))) # change the window settings win.size, win.bpc, win.refreshHz = nativeVidmode if win._isFullScr: useDisplay = thisScreen else: useDisplay = None # configure stereo useStereo = 0 if win.stereo: # provide warning if stereo buffers are requested but unavailable if not glfw.extension_supported('GL_STEREO'): logging.warning( 'A stereo window was requested but the graphics ' 'card does not appear to support GL_STEREO') win.stereo = False else: useStereo = 1 # setup multisampling # This enables multisampling on the window backbuffer, not on other # framebuffers. msaaSamples = 0 if win.multiSample: maxSamples = (GL.GLint)() GL.glGetIntegerv(GL.GL_MAX_SAMPLES, maxSamples) if (win.numSamples & (win.numSamples - 1)) != 0: # power of two? logging.warning( 'Invalid number of MSAA samples provided, must be ' 'power of two. Disabling.') elif 0 > win.numSamples > maxSamples.value: # check if within range logging.warning( 'Invalid number of MSAA samples provided, outside of valid ' 'range. Disabling.') else: msaaSamples = win.numSamples win.multiSample = msaaSamples > 0 # disable stencil buffer if not win.allowStencil: win.stencilBits = 0 # set buffer configuration hints glfw.window_hint(glfw.RED_BITS, win.bpc[0]) glfw.window_hint(glfw.GREEN_BITS, win.bpc[1]) glfw.window_hint(glfw.BLUE_BITS, win.bpc[2]) glfw.window_hint(glfw.REFRESH_RATE, win.refreshHz) glfw.window_hint(glfw.STEREO, useStereo) glfw.window_hint(glfw.SAMPLES, msaaSamples) glfw.window_hint(glfw.STENCIL_BITS, win.stencilBits) glfw.window_hint(glfw.DEPTH_BITS, win.depthBits) glfw.window_hint(glfw.AUTO_ICONIFY, 0) # window appearance and behaviour hints if not win.allowGUI: glfw.window_hint(glfw.DECORATED, 0) # create the window self.winHandle = glfw.create_window( width=win.size[0], height=win.size[1], title=str(kwargs.get('winTitle', "PsychoPy (GLFW)")), monitor=useDisplay, share=shareContext) # The window's user pointer maps the Python Window object to its GLFW # representation. glfw.set_window_user_pointer(self.winHandle, win) glfw.make_context_current(self.winHandle) # ready to use # set the position of the window if not fullscreen if not win._isFullScr: # if no window position is specified, centre it on-screen if win.pos is None: size, bpc, hz = nativeVidmode win.pos = [(size[0] - win.size[0]) / 2.0, (size[1] - win.size[1]) / 2.0] # get the virtual position of the monitor, apply offset to the # window position px, py = glfw.get_monitor_pos(thisScreen) glfw.set_window_pos(self.winHandle, int(win.pos[0] + px), int(win.pos[1] + py)) elif win._isFullScr and win.pos is not None: logging.warn("Ignoring window 'pos' in fullscreen mode.") # set the window icon glfw.set_window_icon(self.winHandle, 1, _WINDOW_ICON_) # set the window size to the framebuffer size win.size = np.array(glfw.get_framebuffer_size(self.winHandle)) if win.useFBO: # check for necessary extensions if not glfw.extension_supported('GL_EXT_framebuffer_object'): msg = ("Trying to use a framebuffer object but " "GL_EXT_framebuffer_object is not supported. Disabled") logging.warn(msg) win.useFBO = False if not glfw.extension_supported('GL_ARB_texture_float'): msg = ("Trying to use a framebuffer object but " "GL_ARB_texture_float is not supported. Disabling") logging.warn(msg) win.useFBO = False # Assign event callbacks, these are dispatched when 'poll_events' is # called. glfw.set_mouse_button_callback(self.winHandle, event._onGLFWMouseButton) glfw.set_scroll_callback(self.winHandle, event._onGLFWMouseScroll) glfw.set_key_callback(self.winHandle, event._onGLFWKey) glfw.set_char_mods_callback(self.winHandle, event._onGLFWText) # set swap interval to manual setting, independent of waitBlanking self.setSwapInterval(int(kwargs.get('swapInterval', 1))) # give the window class GLFW specific methods win.setMouseType = self.setMouseType if not win.allowGUI: self.setMouseVisibility(False)
def demo(): # Initialize the library if not glfw.init(): sys.exit() glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) # for osx glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, gl.GL_TRUE) # Create a windowed mode window and its OpenGL context window = glfw.create_window(1000, 1000, "pyNuklear demo - GLFW OpenGL3", None, None) if not window: glfw.terminate() sys.exit() # Make the window's context current glfw.make_context_current(window) ctx = nkglfw3.glfw3_init(window, nkglfw3.GLFW3_INSTALL_CALLBACKS) nuklear = nk.NuklearContext(ctx) fontAtlas = nkglfw3.FontAtlas() nkglfw3.glfw3_font_stash_begin(ctypes.byref(fontAtlas)) nkglfw3.glfw3_font_stash_end() # Install a key handler def on_key(window, key, scancode, action, mods): if key == glfw.KEY_ESCAPE and action == glfw.PRESS: glfwSetWindowShouldClose(window, 1) glfw.set_key_callback(window, on_key) gl.glClearColor(0.1, 0.18, 0.24, 1.0) gl.glEnable(gl.GL_DEPTH_TEST) gl.glClearDepth(1.0) gl.glDepthFunc(gl.GL_LEQUAL) class Camera: def __init__(self): self.x = 0.0 self.y = 0.0 self.z = 10.0 self.rotationX = 0.0 self.rotationY = 0.0 camera = Camera() triangle = Triangle() triangle.prepareToRender() # does python have static local variables? this declaration is way too far away from use #property = ctypes.c_int(20) # Loop until the user closes the window while not glfw.window_should_close(window): # Render here # Poll for and process events glfw.poll_events() nkglfw3.glfw3_new_frame() width, height = glfw.get_framebuffer_size(window) gl.glViewport(0, 0, width, height) gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) ms.setToIdentityMatrix(ms.MatrixStack.model) ms.setToIdentityMatrix(ms.MatrixStack.view) ms.setToIdentityMatrix(ms.MatrixStack.projection) # set the projection matrix to be perspective ms.perspective(fov=45.0, aspectRatio=width / height, nearZ=0.1, farZ=10000.0) # get input from keyboard for camera movement if not nuklear.item_is_any_active(): # set up Camera if glfw.get_key(window, glfw.KEY_RIGHT) == glfw.PRESS: camera.rotationY -= 0.03 if glfw.get_key(window, glfw.KEY_LEFT) == glfw.PRESS: camera.rotationY += 0.03 if glfw.get_key(window, glfw.KEY_UP) == glfw.PRESS: camera.x -= math.sin(camera.rotationY) camera.z -= math.cos(camera.rotationY) if glfw.get_key(window, glfw.KEY_DOWN) == glfw.PRESS: camera.x += math.sin(camera.rotationY) camera.z += math.cos(camera.rotationY) # move the camera to the correct position, which means # updating the view stack ms.rotateX(ms.MatrixStack.view, camera.rotationX) ms.rotateY(ms.MatrixStack.view, -camera.rotationY) ms.translate(ms.MatrixStack.view, -camera.x, -camera.y, -camera.z) # render the models triangle.render() MAX_VERTEX_BUFFER = 512 * 1024 MAX_ELEMENT_BUFFER = 128 * 1024 if (nuklear.begin(title="Demonstration", bounds=nk.Rect(10.0, 10.0, 230.0, 250.0), flags=nk.PanelFlags.WINDOW_BORDER.value | nk.PanelFlags.WINDOW_MOVABLE.value | nk.PanelFlags.WINDOW_SCALABLE.value | nk.PanelFlags.WINDOW_MINIMIZABLE.value | nk.PanelFlags.WINDOW_TITLE.value)): nuklear.layout_row_static(height=30.0, item_width=80, columns=5) if nuklear.button_label(title="button"): print('button pressed') nuklear.layout_row_dynamic(height=30.0, columns=2) try: op except Exception: op = 0 if nuklear.option_label(label="easy", active=op == 0): op = 0 if nuklear.option_label(label="hard", active=op == 1): op = 1 nuklear.layout_row_dynamic(height=25.0, columns=1) try: prop except Exception: prop = 20 prop = nuklear.property_int(name="Compression:", minV=0, val=prop, maxV=100, step=10, inc_per_pixel=1) nuklear.layout_row_dynamic(height=20.0, columns=1) nuklear.label(text="background:", alignment=nk.TextAlign.TEXT_LEFT) try: background except Exception: background = nk.ColorF(r=0.10, g=0.18, b=0.24, a=1.0) nuklear.layout_row_dynamic(height=25.0, columns=1) if nuklear.combo_begin_color(color=nuklear.rgb_cf(background), size=nk.Vec2(nuklear.widget_width(), 400)): nuklear.layout_row_dynamic(height=120.0, columns=1) background = nuklear.color_picker(color=background, format=nk.ColorFormat.RGBA) nuklear.layout_row_dynamic(height=25.0, columns=1) background.r = nuklear.propertyf(name="#R:", minVal=0.0, val=background.r, maxVal=1.0, step=0.01, inc_per_pixel=0.005) background.g = nuklear.propertyf(name="#G:", minVal=0.0, val=background.g, maxVal=1.0, step=0.01, inc_per_pixel=0.005) background.b = nuklear.propertyf(name="#B:", minVal=0.0, val=background.b, maxVal=1.0, step=0.01, inc_per_pixel=0.005) background.a = nuklear.propertyf(name="#A:", minVal=0.0, val=background.a, maxVal=1.0, step=0.01, inc_per_pixel=0.005) gl.glClearColor(background.r, background.g, background.b, background.a) nuklear.combo_end() nuklear.end() overview(nuklear) nkglfw3.glfw3_render(nk.AntiAliasing.ON.value, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER) # done with frame, flush and swap buffers # Swap front and back buffers glfw.swap_buffers(window) glfw.terminate()
def __init__(self, win, backendConf=None): """Set up the backend window according the params of the PsychoPy win Before PsychoPy 1.90.0 this code was executed in Window._setupPygame() Parameters ---------- win : `psychopy.visual.Window` instance PsychoPy Window (usually not fully created yet). backendConf : `dict` or `None` Backend configuration options. Options are specified as a dictionary where keys are option names and values are settings. For this backend the following options are available: * `share` (`psychopy.visual.Window instance`) PsychoPy Window to share a context with. * `refreshHz` (`int`) Refresh rate in Hertz. * `bpc` (`array_like`) Bits per color (R, G, B). * `swapInterval` (`int`) Swap interval for the current OpenGL context. * `depthBits` (`int`) Framebuffer (back buffer) depth bits. * `stencilBits` (`int`) Framebuffer (back buffer) stencil bits. * `winTitle` (`str`) Optional window title string. Examples -------- Create a window using the GLFW backend and specify custom options:: import psychopy.visual as visual options = {'bpc': (8, 8, 8), 'depthBits': 24, 'stencilBits': 8} win = visual.Window(winType='glfw', backendOptions=options) """ BaseBackend.__init__(self, win) # if `None`, change to `dict` to extract options backendConf = backendConf if backendConf is not None else {} if not isinstance(backendConf, dict): # type check on options raise TypeError( 'Object passed to `backendConf` must be type `dict`.') # window to share a context with shareWin = backendConf.get('share', None) if shareWin is not None: if shareWin.winType == 'glfw': shareContext = shareWin.winHandle else: logging.warning( 'Cannot share a context with a non-GLFW window. Disabling.') shareContext = None else: shareContext = None if sys.platform=='darwin' and not win.useRetina and pyglet.version >= "1.3": raise ValueError("As of PsychoPy 1.85.3 OSX windows should all be " "set to useRetina=True (or remove the argument). " "Pyglet 1.3 appears to be forcing " "us to use retina on any retina-capable screen " "so setting to False has no effect.") # window framebuffer configuration bpc = backendConf.get('bpc', (8, 8, 8)) if isinstance(bpc, int): win.bpc = (bpc, bpc, bpc) else: win.bpc = bpc win.refreshHz = int(backendConf.get('refreshHz', 60)) win.depthBits = int(backendConf.get('depthBits', 8)) win.stencilBits = int(backendConf.get('stencilBits', 8)) # win.swapInterval = int(backendConf.get('swapInterval', 1)) # vsync ON if 1 # get monitors, with GLFW the primary display is ALWAYS at index 0 allScrs = glfw.get_monitors() if len(allScrs) < int(win.screen) + 1: logging.warn("Requested an unavailable screen number - " "using first available.") win.screen = 0 thisScreen = allScrs[win.screen] if win.autoLog: logging.info('configured GLFW screen %i' % win.screen) # find a matching video mode (can we even support this configuration?) isVidmodeSupported = False for vidmode in glfw.get_video_modes(thisScreen): size, bpc, hz = vidmode if win._isFullScr: # size and refresh rate are ignored if windowed hasSize = size == tuple(win.size) hasHz = hz == win.refreshHz else: hasSize = hasHz = True hasBpc = bpc == tuple(win.bpc) if hasSize and hasBpc and hasHz: isVidmodeSupported = True break nativeVidmode = glfw.get_video_mode(thisScreen) if not isVidmodeSupported: # the requested video mode is not supported, use current logging.warning( ("The specified video mode is not supported by this display, " "using native mode ...")) actualWidth, actualHeight = nativeVidmode.size redBits, greenBits, blueBits = nativeVidmode.bits # change the window settings if win._isFullScr: logging.warning( ("Overriding user video settings: size {} -> {}, bpc {} -> " "{}, refreshHz {} -> {}".format( tuple(win.size), (actualWidth, actualHeight), tuple(win.bpc), (redBits, greenBits, blueBits), win.refreshHz, nativeVidmode.refresh_rate))) win.clientSize = np.array((actualWidth, actualHeight), int) else: logging.warning( ("Overriding user video settings: bpc {} -> " "{}, refreshHz {} -> {}".format( tuple(win.bpc), (redBits, greenBits, blueBits), win.refreshHz, nativeVidmode.refresh_rate))) win.bpc = (redBits, greenBits, blueBits) win.refreshHz = nativeVidmode.refresh_rate if win._isFullScr: useDisplay = thisScreen else: useDisplay = None # configure stereo useStereo = 0 if win.stereo: # provide warning if stereo buffers are requested but unavailable if not glfw.extension_supported('GL_STEREO'): logging.warning( 'A stereo window was requested but the graphics ' 'card does not appear to support GL_STEREO') win.stereo = False else: useStereo = 1 # setup multisampling # This enables multisampling on the window backbuffer, not on other # framebuffers. msaaSamples = 0 if win.multiSample: maxSamples = (GL.GLint)() GL.glGetIntegerv(GL.GL_MAX_SAMPLES, maxSamples) if (win.numSamples & (win.numSamples - 1)) != 0: # power of two? logging.warning( 'Invalid number of MSAA samples provided, must be ' 'power of two. Disabling.') elif 0 > win.numSamples > maxSamples.value: # check if within range logging.warning( 'Invalid number of MSAA samples provided, outside of valid ' 'range. Disabling.') else: msaaSamples = win.numSamples win.multiSample = msaaSamples > 0 # disable stencil buffer if not win.allowStencil: win.stencilBits = 0 # set buffer configuration hints glfw.window_hint(glfw.RED_BITS, win.bpc[0]) glfw.window_hint(glfw.GREEN_BITS, win.bpc[1]) glfw.window_hint(glfw.BLUE_BITS, win.bpc[2]) glfw.window_hint(glfw.REFRESH_RATE, win.refreshHz) glfw.window_hint(glfw.STEREO, useStereo) glfw.window_hint(glfw.SAMPLES, msaaSamples) glfw.window_hint(glfw.STENCIL_BITS, win.stencilBits) glfw.window_hint(glfw.DEPTH_BITS, win.depthBits) glfw.window_hint(glfw.AUTO_ICONIFY, 0) # window appearance and behaviour hints if not win.allowGUI: glfw.window_hint(glfw.DECORATED, 0) # create the window self.winHandle = glfw.create_window( width=win.clientSize[0], height=win.clientSize[1], title=str(backendConf.get('winTitle', "PsychoPy (GLFW)")), monitor=useDisplay, share=shareContext) # The window's user pointer maps the Python Window object to its GLFW # representation. glfw.set_window_user_pointer(self.winHandle, win) glfw.make_context_current(self.winHandle) # ready to use # set the position of the window if not fullscreen if not win._isFullScr: # if no window position is specified, centre it on-screen if win.pos is None: size, bpc, hz = nativeVidmode win.pos = [(size[0] - win.clientSize[0]) / 2.0, (size[1] - win.clientSize[1]) / 2.0] # get the virtual position of the monitor, apply offset to the # window position px, py = glfw.get_monitor_pos(thisScreen) glfw.set_window_pos(self.winHandle, int(win.pos[0] + px), int(win.pos[1] + py)) elif win._isFullScr and win.pos is not None: logging.warn("Ignoring window 'pos' in fullscreen mode.") # set the window icon if hasattr(glfw, 'set_window_icon'): glfw.set_window_icon(self.winHandle, 1, _WINDOW_ICON_) # set the window size to the framebuffer size self._frameBufferSize = np.array(glfw.get_framebuffer_size(self.winHandle)) if win.useFBO: # check for necessary extensions if not glfw.extension_supported('GL_EXT_framebuffer_object'): msg = ("Trying to use a framebuffer object but " "GL_EXT_framebuffer_object is not supported. Disabled") logging.warn(msg) win.useFBO = False if not glfw.extension_supported('GL_ARB_texture_float'): msg = ("Trying to use a framebuffer object but " "GL_ARB_texture_float is not supported. Disabling") logging.warn(msg) win.useFBO = False # Assign event callbacks, these are dispatched when 'poll_events' is # called. glfw.set_mouse_button_callback(self.winHandle, self.onMouseButton) glfw.set_cursor_pos_callback(self.winHandle, self.onMouseMove) glfw.set_cursor_enter_callback(self.winHandle, self.onMouseEnter) glfw.set_scroll_callback(self.winHandle, self.onMouseScroll) glfw.set_key_callback(self.winHandle, event._onGLFWKey) glfw.set_char_mods_callback(self.winHandle, event._onGLFWText) # set swap interval to manual setting, independent of waitBlanking self.setSwapInterval(int(backendConf.get('swapInterval', 1))) # give the window class GLFW specific methods win.setMouseType = self.setMouseType if not win.allowGUI: self.setMouseVisibility(False)
def size(self): return glfw.get_framebuffer_size(self._wnd)
def world( timebase, eye_procs_alive, ipc_pub_url, ipc_sub_url, ipc_push_url, user_dir, version, preferred_remote_port, hide_ui, debug, ): """Reads world video and runs plugins. Creates a window, gl context. Grabs images from a capture. Maps pupil to gaze data Can run various plug-ins. Reacts to notifications: ``eye_process.started`` ``start_plugin`` ``should_stop`` Emits notifications: ``eye_process.should_start`` ``eye_process.should_stop`` ``world_process.started`` ``world_process.stopped`` ``recording.should_stop``: Emits on camera failure ``launcher_process.should_stop`` Emits data: ``gaze``: Gaze data from current gaze mapping plugin.`` ``*``: any other plugin generated data in the events that it not [dt,pupil,gaze]. """ # We defer the imports because of multiprocessing. # Otherwise the world process each process also loads the other imports. # This is not harmful but unnecessary. # general imports from time import sleep import logging # networking import zmq import zmq_tools # zmq ipc setup zmq_ctx = zmq.Context() ipc_pub = zmq_tools.Msg_Dispatcher(zmq_ctx, ipc_push_url) notify_sub = zmq_tools.Msg_Receiver(zmq_ctx, ipc_sub_url, topics=("notify",)) # log setup logging.getLogger("OpenGL").setLevel(logging.ERROR) logger = logging.getLogger() logger.handlers = [] logger.setLevel(logging.NOTSET) logger.addHandler(zmq_tools.ZMQ_handler(zmq_ctx, ipc_push_url)) # create logger for the context of this function logger = logging.getLogger(__name__) def launch_eye_process(eye_id, delay=0): n = { "subject": "eye_process.should_start.{}".format(eye_id), "eye_id": eye_id, "delay": delay, } ipc_pub.notify(n) def stop_eye_process(eye_id): n = { "subject": "eye_process.should_stop.{}".format(eye_id), "eye_id": eye_id, "delay": 0.2, } ipc_pub.notify(n) def start_stop_eye(eye_id, make_alive): if make_alive: launch_eye_process(eye_id) else: stop_eye_process(eye_id) def detection_enabled_getter() -> bool: return g_pool.pupil_detection_enabled def detection_enabled_setter(is_on: bool): g_pool.pupil_detection_enabled = is_on n = {"subject": "set_pupil_detection_enabled", "value": is_on} ipc_pub.notify(n) try: from background_helper import IPC_Logging_Task_Proxy IPC_Logging_Task_Proxy.push_url = ipc_push_url from tasklib.background.patches import IPCLoggingPatch IPCLoggingPatch.ipc_push_url = ipc_push_url from OpenGL.GL import GL_COLOR_BUFFER_BIT # display import glfw glfw.ERROR_REPORTING = "raise" from version_utils import parse_version from pyglui import ui, cygl, __version__ as pyglui_version assert parse_version(pyglui_version) >= parse_version( "1.27" ), "pyglui out of date, please upgrade to newest version" from pyglui.cygl.utils import Named_Texture import gl_utils # helpers/utils from file_methods import Persistent_Dict from methods import normalize, denormalize, delta_t, get_system_info, timer from uvc import get_time_monotonic logger.info("Application Version: {}".format(version)) logger.info("System Info: {}".format(get_system_info())) logger.debug(f"Debug flag: {debug}") import audio # Plug-ins from plugin import ( Plugin, System_Plugin_Base, Plugin_List, import_runtime_plugins, ) from plugin_manager import Plugin_Manager from calibration_choreography import ( available_calibration_choreography_plugins, CalibrationChoreographyPlugin, patch_loaded_plugins_with_choreography_plugin, ) available_choreography_plugins = available_calibration_choreography_plugins() from gaze_mapping import registered_gazer_classes from gaze_mapping.gazer_base import GazerBase from pupil_detector_plugins.detector_base_plugin import PupilDetectorPlugin from fixation_detector import Fixation_Detector from recorder import Recorder from display_recent_gaze import Display_Recent_Gaze from time_sync import Time_Sync from network_api import NetworkApiPlugin from pupil_groups import Pupil_Groups from surface_tracker import Surface_Tracker_Online from log_display import Log_Display from annotations import Annotation_Capture from log_history import Log_History from blink_detection import Blink_Detection from video_capture import ( source_classes, manager_classes, Base_Manager, Base_Source, ) from pupil_data_relay import Pupil_Data_Relay from remote_recorder import Remote_Recorder from accuracy_visualizer import Accuracy_Visualizer from system_graphs import System_Graphs from camera_intrinsics_estimation import Camera_Intrinsics_Estimation from hololens_relay import Hololens_Relay from head_pose_tracker.online_head_pose_tracker import Online_Head_Pose_Tracker # UI Platform tweaks if platform.system() == "Linux": scroll_factor = 10.0 window_position_default = (30, 30) elif platform.system() == "Windows": scroll_factor = 10.0 window_position_default = (8, 90) else: scroll_factor = 1.0 window_position_default = (0, 0) process_was_interrupted = False def interrupt_handler(sig, frame): import traceback trace = traceback.format_stack(f=frame) logger.debug(f"Caught signal {sig} in:\n" + "".join(trace)) nonlocal process_was_interrupted process_was_interrupted = True signal.signal(signal.SIGINT, interrupt_handler) icon_bar_width = 50 window_size = None camera_render_size = None content_scale = 1.0 # g_pool holds variables for this process they are accessible to all plugins g_pool = SimpleNamespace() g_pool.debug = debug g_pool.app = "capture" g_pool.process = "world" g_pool.user_dir = user_dir g_pool.version = version g_pool.timebase = timebase g_pool.zmq_ctx = zmq_ctx g_pool.ipc_pub = ipc_pub g_pool.ipc_pub_url = ipc_pub_url g_pool.ipc_sub_url = ipc_sub_url g_pool.ipc_push_url = ipc_push_url g_pool.eye_procs_alive = eye_procs_alive g_pool.preferred_remote_port = preferred_remote_port def get_timestamp(): return get_time_monotonic() - g_pool.timebase.value g_pool.get_timestamp = get_timestamp g_pool.get_now = get_time_monotonic # manage plugins runtime_plugins = import_runtime_plugins( os.path.join(g_pool.user_dir, "plugins") ) runtime_plugins = [ p for p in runtime_plugins if not issubclass(p, PupilDetectorPlugin) ] user_plugins = [ Pupil_Groups, NetworkApiPlugin, Time_Sync, Surface_Tracker_Online, Annotation_Capture, Log_History, Fixation_Detector, Blink_Detection, Remote_Recorder, Accuracy_Visualizer, Camera_Intrinsics_Estimation, Hololens_Relay, Online_Head_Pose_Tracker, ] system_plugins = ( [ Log_Display, Display_Recent_Gaze, Recorder, Pupil_Data_Relay, Plugin_Manager, System_Graphs, ] + manager_classes + source_classes ) plugins = ( system_plugins + user_plugins + runtime_plugins + available_choreography_plugins + registered_gazer_classes() ) user_plugins += [ p for p in runtime_plugins if not isinstance( p, ( Base_Manager, Base_Source, System_Plugin_Base, CalibrationChoreographyPlugin, GazerBase, ), ) ] g_pool.plugin_by_name = {p.__name__: p for p in plugins} default_capture_name = "UVC_Source" default_capture_settings = { "preferred_names": [ "Pupil Cam1 ID2", "Logitech Camera", "(046d:081d)", "C510", "B525", "C525", "C615", "C920", "C930e", ], "frame_size": (1280, 720), "frame_rate": 30, } default_plugins = [ (default_capture_name, default_capture_settings), ("Pupil_Data_Relay", {}), ("UVC_Manager", {}), ("NDSI_Manager", {}), ("HMD_Streaming_Manager", {}), ("File_Manager", {}), ("Log_Display", {}), ("Dummy_Gaze_Mapper", {}), ("Display_Recent_Gaze", {}), # Calibration choreography plugin is added below by calling # patch_loaded_plugins_with_choreography_plugin ("Recorder", {}), ("NetworkApiPlugin", {}), ("Fixation_Detector", {}), ("Blink_Detection", {}), ("Accuracy_Visualizer", {}), ("Plugin_Manager", {}), ("System_Graphs", {}), ] def consume_events_and_render_buffer(): gl_utils.glViewport(0, 0, *camera_render_size) for p in g_pool.plugins: p.gl_display() gl_utils.glViewport(0, 0, *window_size) try: clipboard = glfw.get_clipboard_string(main_window).decode() except (AttributeError, glfw.GLFWError): # clipboard is None, might happen on startup clipboard = "" g_pool.gui.update_clipboard(clipboard) user_input = g_pool.gui.update() if user_input.clipboard != clipboard: # only write to clipboard if content changed glfw.set_clipboard_string(main_window, user_input.clipboard) for button, action, mods in user_input.buttons: x, y = glfw.get_cursor_pos(main_window) pos = gl_utils.window_coordinate_to_framebuffer_coordinate( main_window, x, y, cached_scale=None ) pos = normalize(pos, camera_render_size) # Position in img pixels pos = denormalize(pos, g_pool.capture.frame_size) for plugin in g_pool.plugins: if plugin.on_click(pos, button, action): break for key, scancode, action, mods in user_input.keys: for plugin in g_pool.plugins: if plugin.on_key(key, scancode, action, mods): break for char_ in user_input.chars: for plugin in g_pool.plugins: if plugin.on_char(char_): break glfw.swap_buffers(main_window) # Callback functions def on_resize(window, w, h): nonlocal window_size nonlocal camera_render_size nonlocal content_scale if w == 0 or h == 0: return # Always clear buffers on resize to make sure that there are no overlapping # artifacts from previous frames. gl_utils.glClear(GL_COLOR_BUFFER_BIT) gl_utils.glClearColor(0, 0, 0, 1) content_scale = gl_utils.get_content_scale(window) framebuffer_scale = gl_utils.get_framebuffer_scale(window) g_pool.gui.scale = content_scale window_size = w, h camera_render_size = w - int(icon_bar_width * g_pool.gui.scale), h g_pool.gui.update_window(*window_size) g_pool.gui.collect_menus() for p in g_pool.plugins: p.on_window_resize(window, *camera_render_size) # Minimum window size required, otherwise parts of the UI can cause openGL # issues with permanent effects. Depends on the content scale, which can # potentially be dynamically modified, so we re-adjust the size limits every # time here. min_size = int(2 * icon_bar_width * g_pool.gui.scale / framebuffer_scale) glfw.set_window_size_limits( window, min_size, min_size, glfw.DONT_CARE, glfw.DONT_CARE, ) # Needed, to update the window buffer while resizing consume_events_and_render_buffer() def on_window_key(window, key, scancode, action, mods): g_pool.gui.update_key(key, scancode, action, mods) def on_window_char(window, char): g_pool.gui.update_char(char) def on_window_mouse_button(window, button, action, mods): g_pool.gui.update_button(button, action, mods) def on_pos(window, x, y): x, y = gl_utils.window_coordinate_to_framebuffer_coordinate( window, x, y, cached_scale=None ) g_pool.gui.update_mouse(x, y) pos = x, y pos = normalize(pos, camera_render_size) # Position in img pixels pos = denormalize(pos, g_pool.capture.frame_size) for p in g_pool.plugins: p.on_pos(pos) def on_scroll(window, x, y): g_pool.gui.update_scroll(x, y * scroll_factor) def on_drop(window, paths): for plugin in g_pool.plugins: if plugin.on_drop(paths): break tick = delta_t() def get_dt(): return next(tick) # load session persistent settings session_settings = Persistent_Dict( os.path.join(g_pool.user_dir, "user_settings_world") ) if parse_version(session_settings.get("version", "0.0")) != g_pool.version: logger.info( "Session setting are from a different version of this app. I will not use those." ) session_settings.clear() g_pool.min_data_confidence = 0.6 g_pool.min_calibration_confidence = session_settings.get( "min_calibration_confidence", 0.8 ) g_pool.pupil_detection_enabled = session_settings.get( "pupil_detection_enabled", True ) g_pool.active_gaze_mapping_plugin = None g_pool.capture = None audio.set_audio_mode( session_settings.get("audio_mode", audio.get_default_audio_mode()) ) def handle_notifications(noti): subject = noti["subject"] if subject == "set_pupil_detection_enabled": g_pool.pupil_detection_enabled = noti["value"] elif subject == "start_plugin": try: g_pool.plugins.add( g_pool.plugin_by_name[noti["name"]], args=noti.get("args", {}) ) except KeyError as err: logger.error(f"Attempt to load unknown plugin: {err}") elif subject == "stop_plugin": for p in g_pool.plugins: if p.class_name == noti["name"]: p.alive = False g_pool.plugins.clean() elif subject == "eye_process.started": noti = { "subject": "set_pupil_detection_enabled", "value": g_pool.pupil_detection_enabled, } ipc_pub.notify(noti) elif subject == "set_min_calibration_confidence": g_pool.min_calibration_confidence = noti["value"] elif subject.startswith("meta.should_doc"): ipc_pub.notify( {"subject": "meta.doc", "actor": g_pool.app, "doc": world.__doc__} ) for p in g_pool.plugins: if ( p.on_notify.__doc__ and p.__class__.on_notify != Plugin.on_notify ): ipc_pub.notify( { "subject": "meta.doc", "actor": p.class_name, "doc": p.on_notify.__doc__, } ) elif subject == "world_process.adapt_window_size": set_window_size() elif subject == "world_process.should_stop": glfw.set_window_should_close(main_window, True) width, height = session_settings.get( "window_size", (1280 + icon_bar_width, 720) ) # window and gl setup glfw.init() glfw.window_hint(glfw.SCALE_TO_MONITOR, glfw.TRUE) if hide_ui: glfw.window_hint(glfw.VISIBLE, 0) # hide window main_window = glfw.create_window( width, height, "Pupil Capture - World", None, None ) window_position_manager = gl_utils.WindowPositionManager() window_pos = window_position_manager.new_window_position( window=main_window, default_position=window_position_default, previous_position=session_settings.get("window_position", None), ) glfw.set_window_pos(main_window, window_pos[0], window_pos[1]) glfw.make_context_current(main_window) cygl.utils.init() g_pool.main_window = main_window def reset_restart(): logger.warning("Resetting all settings and restarting Capture.") glfw.set_window_should_close(main_window, True) ipc_pub.notify({"subject": "clear_settings_process.should_start"}) ipc_pub.notify({"subject": "world_process.should_start", "delay": 2.0}) def toggle_general_settings(collapsed): # this is the menu toggle logic. # Only one menu can be open. # If no menu is opened, the menubar should collapse. g_pool.menubar.collapsed = collapsed for m in g_pool.menubar.elements: m.collapsed = True general_settings.collapsed = collapsed # setup GUI g_pool.gui = ui.UI() g_pool.menubar = ui.Scrolling_Menu( "Settings", pos=(-400, 0), size=(-icon_bar_width, 0), header_pos="left" ) g_pool.iconbar = ui.Scrolling_Menu( "Icons", pos=(-icon_bar_width, 0), size=(0, 0), header_pos="hidden" ) g_pool.quickbar = ui.Stretching_Menu("Quick Bar", (0, 100), (120, -100)) g_pool.gui.append(g_pool.menubar) g_pool.gui.append(g_pool.iconbar) g_pool.gui.append(g_pool.quickbar) general_settings = ui.Growing_Menu("General", header_pos="headline") def set_window_size(): # Get current capture frame size f_width, f_height = g_pool.capture.frame_size # Get current display scale factor content_scale = gl_utils.get_content_scale(main_window) framebuffer_scale = gl_utils.get_framebuffer_scale(main_window) display_scale_factor = content_scale / framebuffer_scale # Scale the capture frame size by display scale factor f_width *= display_scale_factor f_height *= display_scale_factor # Increas the width to account for the added scaled icon bar width f_width += icon_bar_width * display_scale_factor # Set the newly calculated size (scaled capture frame size + scaled icon bar width) glfw.set_window_size(main_window, int(f_width), int(f_height)) general_settings.append(ui.Button("Reset window size", set_window_size)) general_settings.append( ui.Selector( "Audio mode", None, getter=audio.get_audio_mode, setter=audio.set_audio_mode, selection=audio.get_audio_mode_list(), ) ) general_settings.append( ui.Switch( "pupil_detection_enabled", label="Pupil detection", getter=detection_enabled_getter, setter=detection_enabled_setter, ) ) general_settings.append( ui.Switch( "eye0_process", label="Detect eye 0", setter=lambda alive: start_stop_eye(0, alive), getter=lambda: eye_procs_alive[0].value, ) ) general_settings.append( ui.Switch( "eye1_process", label="Detect eye 1", setter=lambda alive: start_stop_eye(1, alive), getter=lambda: eye_procs_alive[1].value, ) ) general_settings.append( ui.Info_Text("Capture Version: {}".format(g_pool.version)) ) general_settings.append( ui.Button("Restart with default settings", reset_restart) ) g_pool.menubar.append(general_settings) icon = ui.Icon( "collapsed", general_settings, label=chr(0xE8B8), on_val=False, off_val=True, setter=toggle_general_settings, label_font="pupil_icons", ) icon.tooltip = "General Settings" g_pool.iconbar.append(icon) user_plugin_separator = ui.Separator() user_plugin_separator.order = 0.35 g_pool.iconbar.append(user_plugin_separator) loaded_plugins = session_settings.get("loaded_plugins", default_plugins) # Resolve the active calibration choreography plugin loaded_plugins = patch_loaded_plugins_with_choreography_plugin( loaded_plugins, app=g_pool.app ) session_settings["loaded_plugins"] = loaded_plugins # plugins that are loaded based on user settings from previous session g_pool.plugins = Plugin_List(g_pool, loaded_plugins) if not g_pool.capture: # Make sure we always have a capture running. Important if there was no # capture stored in session settings. g_pool.plugins.add( g_pool.plugin_by_name[default_capture_name], default_capture_settings ) # Register callbacks main_window glfw.set_framebuffer_size_callback(main_window, on_resize) glfw.set_key_callback(main_window, on_window_key) glfw.set_char_callback(main_window, on_window_char) glfw.set_mouse_button_callback(main_window, on_window_mouse_button) glfw.set_cursor_pos_callback(main_window, on_pos) glfw.set_scroll_callback(main_window, on_scroll) glfw.set_drop_callback(main_window, on_drop) # gl_state settings gl_utils.basic_gl_setup() g_pool.image_tex = Named_Texture() toggle_general_settings(True) # now that we have a proper window we can load the last gui configuration g_pool.gui.configuration = session_settings.get("ui_config", {}) # If previously selected plugin was not loaded this time, we will have an # expanded menubar without any menu selected. We need to ensure the menubar is # collapsed in this case. if all(submenu.collapsed for submenu in g_pool.menubar.elements): g_pool.menubar.collapsed = True # create a timer to control window update frequency window_update_timer = timer(1 / 60) def window_should_update(): return next(window_update_timer) # trigger setup of window and gl sizes on_resize(main_window, *glfw.get_framebuffer_size(main_window)) if session_settings.get("eye1_process_alive", True): launch_eye_process(1, delay=0.6) if session_settings.get("eye0_process_alive", True): launch_eye_process(0, delay=0.3) ipc_pub.notify({"subject": "world_process.started"}) logger.warning("Process started.") if platform.system() == "Darwin": # On macOS, calls to glfw.swap_buffers() deliberately take longer in case of # occluded windows, based on the swap interval value. This causes an FPS drop # and leads to problems when recording. To side-step this behaviour, the swap # interval is set to zero. # # Read more about window occlusion on macOS here: # https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/WorkWhenVisible.html glfw.swap_interval(0) # Event loop while not glfw.window_should_close(main_window) and not process_was_interrupted: # fetch newest notifications new_notifications = [] while notify_sub.new_data: t, n = notify_sub.recv() new_notifications.append(n) # notify each plugin if there are new notifications: for n in new_notifications: handle_notifications(n) for p in g_pool.plugins: p.on_notify(n) # a dictionary that allows plugins to post and read events events = {} # report time between now and the last loop interation events["dt"] = get_dt() # allow each Plugin to do its work. for p in g_pool.plugins: p.recent_events(events) # check if a plugin need to be destroyed g_pool.plugins.clean() # "blacklisted" events that were already sent del events["pupil"] del events["gaze"] # delete if exists. More expensive than del, so only use it when key might not exist events.pop("annotation", None) # send new events to ipc: if "frame" in events: del events["frame"] # send explicitly with frame publisher if "depth_frame" in events: del events["depth_frame"] if "audio_packets" in events: del events["audio_packets"] del events["dt"] # no need to send this for data in events.values(): assert isinstance(data, (list, tuple)) for d in data: ipc_pub.send(d) glfw.make_context_current(main_window) # render visual feedback from loaded plugins glfw.poll_events() if window_should_update() and gl_utils.is_window_visible(main_window): gl_utils.glViewport(0, 0, *camera_render_size) for p in g_pool.plugins: p.gl_display() gl_utils.glViewport(0, 0, *window_size) try: clipboard = glfw.get_clipboard_string(main_window).decode() except (AttributeError, glfw.GLFWError): # clipboard is None, might happen on startup clipboard = "" g_pool.gui.update_clipboard(clipboard) user_input = g_pool.gui.update() if user_input.clipboard != clipboard: # only write to clipboard if content changed glfw.set_clipboard_string(main_window, user_input.clipboard) for button, action, mods in user_input.buttons: x, y = glfw.get_cursor_pos(main_window) pos = gl_utils.window_coordinate_to_framebuffer_coordinate( main_window, x, y, cached_scale=None ) pos = normalize(pos, camera_render_size) # Position in img pixels pos = denormalize(pos, g_pool.capture.frame_size) for plugin in g_pool.plugins: if plugin.on_click(pos, button, action): break for key, scancode, action, mods in user_input.keys: for plugin in g_pool.plugins: if plugin.on_key(key, scancode, action, mods): break for char_ in user_input.chars: for plugin in g_pool.plugins: if plugin.on_char(char_): break glfw.swap_buffers(main_window) session_settings["loaded_plugins"] = g_pool.plugins.get_initializers() session_settings["ui_config"] = g_pool.gui.configuration session_settings["version"] = str(g_pool.version) session_settings["eye0_process_alive"] = eye_procs_alive[0].value session_settings["eye1_process_alive"] = eye_procs_alive[1].value session_settings[ "min_calibration_confidence" ] = g_pool.min_calibration_confidence session_settings["pupil_detection_enabled"] = g_pool.pupil_detection_enabled session_settings["audio_mode"] = audio.get_audio_mode() if not hide_ui: glfw.restore_window(main_window) # need to do this for windows os session_settings["window_position"] = glfw.get_window_pos(main_window) session_window_size = glfw.get_window_size(main_window) if 0 not in session_window_size: f_width, f_height = session_window_size if platform.system() in ("Windows", "Linux"): f_width, f_height = ( f_width / content_scale, f_height / content_scale, ) session_settings["window_size"] = int(f_width), int(f_height) session_settings.close() # de-init all running plugins for p in g_pool.plugins: p.alive = False g_pool.plugins.clean() g_pool.gui.terminate() glfw.destroy_window(main_window) glfw.terminate() except Exception: import traceback trace = traceback.format_exc() logger.error("Process Capture crashed with trace:\n{}".format(trace)) finally: # shut down eye processes: stop_eye_process(0) stop_eye_process(1) logger.info("Process shutting down.") ipc_pub.notify({"subject": "world_process.stopped"}) sleep(1.0)
def start(self): if not glfw.init(): print("Could not initialize OpenGL context") exit(1) glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) #glfw.window_hint(glfw.RESIZABLE, self.resizable) glfw.window_hint(glfw.DOUBLEBUFFER, True) glfw.window_hint(glfw.DEPTH_BITS, 24) #glfw.window_hint(glfw.SAMPLES, 1) glfw.window_hint(glfw.DECORATED, False) monitor = None ''' if self.fullscreen: # Use the primary monitors current resolution monitor = glfw.get_primary_monitor() self.width, self.height = mode.size.width, mode.size.height mode = glfw.get_video_mode(monitor) ''' self.window = glfw.create_window(self.width, self.height, self.window_name, monitor, None) if not self.window: glfw.terminate() raise ValueError("Failed to create window") ''' if not self.cursor: glfw.set_input_mode(self.window, glfw.CURSOR, glfw.CURSOR_DISABLED) ''' glfw.set_window_pos(self.window, 40, 40) # Get the actual buffer size of the window # This is important for some displays like Apple's Retina as reported window sizes are virtual self.buffer_width, self.buffer_height = glfw.get_framebuffer_size(self.window) #print("Frame buffer size:", self.buffer_width, self.buffer_height) #print("Actual window size:", glfw.get_window_size(self.window)) glfw.make_context_current(self.window) # The number of screen updates to wait from the time glfwSwapBuffers # was called before swapping the buffers and returning if self.bVsync: glfw.swap_interval(1) glfw.set_key_callback(self.window, self.key_event_callback) #glfw.set_cursor_pos_callback(self.window, self.mouse_event_callback) #glfw.set_window_size_callback(self.window, self.window_resize_callback) # Create mederngl context from existing context self.ctx = moderngl.create_context(require=330) self.fbo = self.ctx.screen #self.ctx.viewport = self.window.viewport #self.set_default_viewport() #print("Wow ! GL_SHADING_LANGUAGE_VERSION :", gl.glGetString(gl.GL_SHADING_LANGUAGE_VERSION)) ''' self.proj = Matrix44.perspective_projection(45.0, float(self.width)/float(self.height), 0.1, 1000.0) self.lookat = Matrix44.look_at( (0.0, 0.0, 10.0), (0.0, 0.0, 0.0), (0.0, -1.0, 0.0), ) ''' left = 0 #-float(self.width) right = float(self.width) top = 0 #float(self.height) bottom = -float(self.height) near = 1.0 far = 1000.0 self.proj = Matrix44.orthogonal_projection(left, right, bottom, top, near, far) self.lookat = Matrix44.look_at( (0.0, 0.0, -10.0), (0.0, 0.0, 0.0), (0.0, -1.0, 0.0), ) self.prog = self.ctx.program( vertex_shader=''' #version 330 uniform mat4 MVP; //in vec3 in_vert; in vec2 in_vert; in vec2 in_text; out vec2 v_text; void main() { //gl_Position = MVP * vec4(in_vert, 1.0); gl_Position = MVP * vec4(in_vert, 0.0, 1.0); v_text = in_text; } ''', fragment_shader=''' #version 330 uniform sampler2D Texture; in vec2 v_text; out vec4 f_color; void main() { //f_color = vec4(0.3, 0.5, 1.0, 1.0); f_color = vec4(texture(Texture, v_text).rgb, 1.0); } ''', ) self.mvp = self.prog['MVP'] img_left = Image.open(local('assets', 'l.png')).convert('RGB') self.texture_left = self.ctx.texture(img_left.size, 3, img_left.tobytes()) #self.texture_left.build_mipmaps() #img_right = Image.open(local('assets', 'r.png')).convert('RGB') #self.texture_right = self.ctx.texture(img_right.size, 3, img_right.tobytes()) #self.texture_right.build_mipmaps() texSize = (1024,1024) self.texture_left = self.ctx.texture((1024,1024), 3) depth_attachment_left = self.ctx.depth_renderbuffer(texSize) self.fbo_left = self.ctx.framebuffer(self.texture_left, depth_attachment_left) self.texture_right = self.ctx.texture((1024,1024), 3) depth_attachment_right = self.ctx.depth_renderbuffer(texSize) self.fbo_right = self.ctx.framebuffer(self.texture_right, depth_attachment_right) vertices_left_quad = np.array([ 0.0, 0.0, 0.0,1.0, 0.0, self.height, 0.0,0.0, self.width/2, 0.0, 1.0,1.0, self.width/2, self.height, 1.0,0.0 ]) self.vbo_left_quad = self.ctx.buffer(vertices_left_quad.astype('f4').tobytes()) self.vao_left_quad = self.ctx.simple_vertex_array(self.prog, self.vbo_left_quad, 'in_vert', 'in_text') vertices_right_quad = np.array([ self.width/2, 0.0, 0.0,1.0, self.width/2, self.height, 0.0,0.0, self.width, 0.0, 1.0,1.0, self.width, self.height, 1.0,0.0 ]) self.vbo_right_quad = self.ctx.buffer(vertices_right_quad.astype('f4').tobytes()) self.vao_right_quad = self.ctx.simple_vertex_array(self.prog, self.vbo_right_quad, 'in_vert', 'in_text') ##### # Persp scene self.proj_sample = Matrix44.perspective_projection(45.0, self.width / self.height, 0.1, 1000.0) self.proj_sample_stereo = Matrix44.perspective_projection(45.0, (self.width/2) / self.height, 0.1, 1000.0) self.lookat_sample = Matrix44.look_at( (50.0, 20.0, 30.0), (0.0, 0.0, 10.0), (0.0, 0.0, 1.0), ) self.prog_sample = self.ctx.program( vertex_shader=''' #version 330 uniform mat4 MVP; in vec3 in_vert; in vec3 in_norm; in vec2 in_text; out vec3 v_vert; out vec3 v_norm; out vec2 v_text; void main() { gl_Position = MVP * vec4(in_vert, 1.0); v_vert = in_vert; v_norm = in_norm; v_text = in_text; } ''', fragment_shader=''' #version 330 uniform vec3 Light; uniform vec3 Color; uniform bool UseTexture; uniform sampler2D Texture; in vec3 v_vert; in vec3 v_norm; in vec2 v_text; out vec4 f_color; void main() { float lum = clamp(dot(normalize(Light - v_vert), normalize(v_norm)), 0.0, 1.0) * 0.8 + 0.2; if (UseTexture) { f_color = vec4(texture(Texture, v_text).rgb * lum, 1.0); } else { f_color = vec4(Color * lum, 1.0); } } ''', ) self.objects = {} for name in ['ground', 'grass', 'billboard', 'billboard-holder', 'billboard-image']: obj = Obj.open(local('assets', 'scene-1-%s.obj' % name)) vbo = self.ctx.buffer(obj.pack('vx vy vz nx ny nz tx ty')) vao = self.ctx.simple_vertex_array(self.prog_sample, vbo, 'in_vert', 'in_norm', 'in_text') self.objects[name] = vao img = Image.open(local('assets', 'infographic-1.jpg')).transpose(Image.FLIP_TOP_BOTTOM).convert('RGB') self.texture_sample = self.ctx.texture(img.size, 3, img.tobytes()) self.texture_sample.build_mipmaps() self.mvp_sample = self.prog_sample['MVP'] self.bUseTexture_sample = self.prog_sample['UseTexture'] self.light_sample = self.prog_sample['Light'] self.color_sample = self.prog_sample['Color']