def __init__(self, parent=None, fps=24, state=None): """ :param parent: parent Qt object :param fps: frames per second (default 24) :param state: GLState object (for shared states) """ self.camera = None format = QtOpenGL.QGLFormat() format.setDirectRendering(True) format.setSampleBuffers(True) self.state = state or GLState() self.state.signal_state_change.connect(self.handle_state_change) super(GLWidget, self).__init__(format, parent) self.setAutoBufferSwap(True) self.setMouseTracking(True) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setCursor(QtCore.Qt.OpenHandCursor) # save the parent object self._main = parent # frames per second value self.__time = 0 self.__frame = 0 self.__fps = fps self.__playing = False # various matrices and vectors self.__bounds_default = imath.Box3d((-5, -5, -5), (5, 5, 5)) self.__bounds = None self.__radius = 5.0 self.__last_pok = False self.__last_p2d = QtCore.QPoint() self.__last_p3d = [1.0, 0.0, 0.0] self.__rotating = False # for animated scenes self.timer = QtCore.QTimer(self) # default camera self.camera = GLCamera(self) self.state.add_camera(self.camera) self.frame()
def handle_camera_action(self, action): """ New camera menu handler. """ action_name = str(action.text().toAscii()) if action_name == "New": text, ok = QtGui.QInputDialog.getText(self, "New Camera", "Camera Name:", QtGui.QLineEdit.Normal) if ok and not text.isEmpty(): name = str(text.toAscii()) camera = GLCamera(self, name) self.add_camera(camera) self.set_camera(name)
def __init__(self, parent=None, fps=24, state=None): """ :param parent: parent Qt object :param fps: frames per second (default 24) :param state: GLState object (for shared states) """ self.camera = None format = QtOpenGL.QGLFormat() format.setDirectRendering(True) format.setSampleBuffers(True) self.state = state or GLState() self.state.signal_state_change.connect(self.handle_state_change) super(GLWidget, self).__init__(format, parent) self.setAutoBufferSwap(True) self.setMouseTracking(True) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setCursor(QtCore.Qt.OpenHandCursor) # save the parent object self._main = parent # frames per second value self.__time = 0 self.__frame = 0 self.__fps = fps self.__playing = False # various matrices and vectors self.__bounds_default = imath.Box3d((-5,-5,-5), (5,5,5)) self.__bounds = None self.__radius = 5.0 self.__last_pok = False self.__last_p2d = QtCore.QPoint() self.__last_p3d = [1.0, 0.0, 0.0] self.__rotating = False # for animated scenes self.timer = QtCore.QTimer(self) # default camera self.camera = GLCamera(self) self.state.add_camera(self.camera) self.frame()
class GLWidget(QtOpenGL.QGLWidget): """ AbcView OpenGL Widget. Basic usage :: >>> viewer = GLWidget() >>> viewer.add_file("file.abc") """ signal_scene_opened = QtCore.pyqtSignal(GLScene) signal_scene_removed = QtCore.pyqtSignal(GLScene) signal_scene_error = QtCore.pyqtSignal(str) signal_scene_drawn = QtCore.pyqtSignal() signal_play_fwd = QtCore.pyqtSignal() signal_play_stop = QtCore.pyqtSignal() signal_current_time = QtCore.pyqtSignal(float) signal_current_frame = QtCore.pyqtSignal(int) signal_set_camera = QtCore.pyqtSignal(GLCamera) signal_new_camera = QtCore.pyqtSignal(GLCamera) signal_camera_updated = QtCore.pyqtSignal(GLCamera) def __init__(self, parent=None, fps=24, state=None): """ :param parent: parent Qt object :param fps: frames per second (default 24) :param state: GLState object (for shared states) """ self.camera = None format = QtOpenGL.QGLFormat() format.setDirectRendering(True) format.setSampleBuffers(True) self.state = state or GLState() self.state.signal_state_change.connect(self.handle_state_change) super(GLWidget, self).__init__(format, parent) self.setAutoBufferSwap(True) self.setMouseTracking(True) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setCursor(QtCore.Qt.OpenHandCursor) # save the parent object self._main = parent # frames per second value self.__time = 0 self.__frame = 0 self.__fps = fps self.__playing = False # various matrices and vectors self.__bounds_default = imath.Box3d((-5,-5,-5), (5,5,5)) self.__bounds = None self.__radius = 5.0 self.__last_pok = False self.__last_p2d = QtCore.QPoint() self.__last_p3d = [1.0, 0.0, 0.0] self.__rotating = False # for animated scenes self.timer = QtCore.QTimer(self) # default camera self.camera = GLCamera(self) self.state.add_camera(self.camera) self.frame() def clear(self): self.frame() self.updateGL() def add_file(self, filepath): self.add_scene(GLScene(filepath)) def add_scene(self, scene): """ Adds a scene to the viewer session. :param scene: GLScene object """ self.state.add_scene(scene) self.signal_scene_opened.emit(scene) self.updateGL() def remove_scene(self, scene): """ Removes a given GLScene object from the master scene. :param scene: GLScene to remove. """ self.state.remove_scene(scene) self.signal_scene_removed.emit(scene) self.updateGL() def add_camera(self, camera): """ :param camera: GLCamera object """ log.debug("GLWidget.add_camera: %s" % camera) self.state.add_camera(camera) self.signal_new_camera.emit(camera) def remove_camera(self, camera): """ :param camera: GLCamera object to remove """ self.state.remove_camera(camera) @update_camera def set_camera(self, camera="interactive"): """ Sets the scene camera from a given camera name string :param camera: Name of camera or GLCamera object """ if type(camera) in [str, unicode]: if "/" in camera: camera = os.path.split("/")[-1] if camera not in [cam.name for cam in self.state.cameras]: log.warn("camera not found: %s" % camera) return self.camera = self.state.get_camera_by_name(camera) else: self.camera = camera self.resizeGL(self.width(), self.height()) self.signal_set_camera.emit(self.camera) def _get_time(self): return self.__time def _set_time(self, new_time): self.__time = new_time self.__frame = new_time * self.fps for scene in self.state.scenes: if scene.visible: scene.set_time(new_time) if self.camera and self.camera.auto_frame: self.frame() self.signal_current_time.emit(new_time) self.signal_current_frame.emit(int(round(new_time * self.fps))) self.updateGL() current_time = property(_get_time, _set_time, doc="set/get current time") def _get_frame(self): return self.__frame def _set_frame(self, frame): if frame > self.frame_range()[1]: frame = self.frame_range()[0] elif frame < self.frame_range()[0]: frame = self.frame_range()[1] frame = frame / float(self.fps) self.current_time = frame current_frame = property(_get_frame, _set_frame, doc="set/get current frame") def is_playing(self): return self.__playing def play(self): """ plays loaded scenes by activating timer and setting callback """ self.timer.setInterval(1.0 / (float(self.fps))) self.connect(self.timer, QtCore.SIGNAL("timeout ()"), self._play_fwd_cb) self.timer.start() self.signal_play_fwd.emit() def _play_fwd_cb(self): """ play callback, sets current time for all scenes """ self.__playing = True min_time, max_time = self.time_range() self.current_time += 1.0 / float(self.fps) if self.current_time > max_time: self.current_time = min_time def stop(self): """ stops scene playback """ self.__playing = False self.disconnect(self.timer, QtCore.SIGNAL("timeout ()"), self._play_fwd_cb) self.connect(self.timer, QtCore.SIGNAL("timeout ()"), self._play_stop_cb) self.updateGL() def _play_stop_cb(self): self.signal_play_stop.emit() def _get_fps(self): return self.__fps def _set_fps(self, fps): self.__fps = fps fps = property(_get_fps, _set_fps, doc="frames per second value") def aspect_ratio(self): """ Returns current aspect ration of the viewer. """ return self.width() / float(self.height()) def time_range(self): """ Returns total time range in seconds. """ min = None max = None if self.state.scenes: for scene in self.state.scenes: if min is None or scene.min_time() < min: min = scene.min_time() if max is None or scene.max_time() > max: max = scene.max_time() else: min, max = 0, 0 return (min, max) def frame_range(self): """ Returns total frame range. """ (min, max) = self.time_range() return (min * self.fps, max * self.fps) def _get_bounds(self): #TODO: ugly code needs refactor if self.state.scenes: bounds = None for scene in self.state.scenes: if not scene.loaded: continue if bounds is None or scene.bounds().max() > bounds.max(): bounds = scene.bounds() min = bounds.min() max = bounds.max() if scene.properties.get("translate"): max = max * imath.V3d(*scene.translate) min = min * imath.V3d(*scene.translate) if scene.properties.get("scale"): max = max * imath.V3d(*scene.scale) min = min * imath.V3d(*scene.scale) bounds = imath.Box3d(min, max) if bounds is None: return self.__bounds_default self.__bounds = bounds return self.__bounds else: return self.__bounds_default def _set_bounds(self, bounds): self.__bounds = bounds bounds = property(_get_bounds, _set_bounds, doc="scene bounding box") @update_camera def frame(self, bounds=None): """ Frames the viewer's active camera on the bounds of the currently loaded and visible scenes. :param bounds: imath.Box3d bounds object. """ if bounds is None: bounds = self.bounds self.camera.frame(bounds) def split(self, orientation=QtCore.Qt.Vertical, wipe=False): """ Splist the viewer into two separate widgets according to the orientation param. """ if not self.parent(): return item = self.parent().layout().itemAt(0) splitter = GLSplitter(orientation, wipe) self.parent().layout().addWidget(splitter) group1 = QtGui.QGroupBox() group1.setLayout(QtGui.QVBoxLayout()) group1.layout().setSpacing(0) group1.layout().setMargin(0) group1.layout().addWidget(item.widget()) group2 = QtGui.QGroupBox() group2.setLayout(QtGui.QVBoxLayout()) group2.layout().setSpacing(0) group2.layout().setMargin(0) new_viewer = GLWidget(self._main, state=self.state) group2.layout().addWidget(new_viewer) splitter.addWidget(group1) splitter.addWidget(group2) def split_vert(self): """ Splits the viewer vertically. """ self.split(QtCore.Qt.Horizontal) def split_horz(self): """ Splits the viewer horizontally. """ self.split(QtCore.Qt.Vertical) #def wipe_horz(self): # self.split(QtCore.Qt.Horizontal, wipe=True) #TODO: support viewer pop-outs def unsplit(self): """ Unsplits and deletes current viewer """ if not self.parent(): return splitter = self.parent().parent() # should be exactly two groups per splitter index = splitter.indexOf(self.parent()) index_other = 1 * (1 - index) group = splitter.widget(index) group_other = splitter.widget(index_other) # disconnect signals #self.state.signal_state_change.disconnect() splitter.parent().layout().addWidget(group_other) splitter.parent().layout().removeWidget(splitter) # cleanup widgets del splitter del group del self def _paint_normals(self): glColor3f(1, 1, 1) def _draw(obj): md = obj.getMetaData() if alembic.AbcGeom.IPolyMesh.matches(md) or alembic.AbcGeom.ISubD.matches(md): meshObj = alembic.AbcGeom.IPolyMesh(obj.getParent(), obj.getName()) mesh = meshObj.getSchema() xf = get_final_matrix(meshObj) iss = alembic.Abc.ISampleSelector(0) facesProp = mesh.getFaceIndicesProperty() if not facesProp.valid(): return pointsProp = mesh.getPositionsProperty() if not pointsProp.valid(): return normalsProp = mesh.getNormalsParam().getValueProperty() if not normalsProp.valid(): return boundsProp = mesh.getSelfBoundsProperty() if not boundsProp.valid(): return faces = facesProp.getValue(iss) points = pointsProp.getValue(iss) normals = normalsProp.getValue(iss) bounds = boundsProp.getValue(iss) for i, fi in enumerate(faces): p = points[fi] * xf n = normals[i] v = p + n glBegin(GL_LINES) glColor3f(0, 1, 0) glVertex3f(p[0], p[1], p[2]) glVertex3f(v[0], v[1], v[2]) glEnd() for child in obj.children: try: _draw(child) except Exception, e: log.warn("unhandled exception: %s" % e) for scene in self.state.scenes: _draw(scene.top())
class GLWidget(QtOpenGL.QGLWidget): """ AbcView OpenGL Widget. Basic usage :: >>> viewer = GLWidget() >>> viewer.add_file("file.abc") """ signal_scene_opened = QtCore.pyqtSignal(GLScene) signal_scene_removed = QtCore.pyqtSignal(GLScene) signal_scene_error = QtCore.pyqtSignal(str) signal_scene_drawn = QtCore.pyqtSignal() signal_play_fwd = QtCore.pyqtSignal() signal_play_stop = QtCore.pyqtSignal() signal_current_time = QtCore.pyqtSignal(float) signal_current_frame = QtCore.pyqtSignal(int) signal_set_camera = QtCore.pyqtSignal(GLCamera) signal_new_camera = QtCore.pyqtSignal(GLCamera) signal_camera_updated = QtCore.pyqtSignal(GLCamera) def __init__(self, parent=None, fps=24, state=None): """ :param parent: parent Qt object :param fps: frames per second (default 24) :param state: GLState object (for shared states) """ self.camera = None format = QtOpenGL.QGLFormat() format.setDirectRendering(True) format.setSampleBuffers(True) self.state = state or GLState() self.state.signal_state_change.connect(self.handle_state_change) super(GLWidget, self).__init__(format, parent) self.setAutoBufferSwap(True) self.setMouseTracking(True) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setCursor(QtCore.Qt.OpenHandCursor) # save the parent object self._main = parent # frames per second value self.__time = 0 self.__frame = 0 self.__fps = fps self.__playing = False # various matrices and vectors self.__bounds_default = imath.Box3d((-5, -5, -5), (5, 5, 5)) self.__bounds = None self.__radius = 5.0 self.__last_pok = False self.__last_p2d = QtCore.QPoint() self.__last_p3d = [1.0, 0.0, 0.0] self.__rotating = False # for animated scenes self.timer = QtCore.QTimer(self) # default camera self.camera = GLCamera(self) self.state.add_camera(self.camera) self.frame() def clear(self): self.frame() self.updateGL() def add_file(self, filepath): self.add_scene(GLScene(filepath)) def add_scene(self, scene): """ Adds a scene to the viewer session. :param scene: GLScene object """ self.state.add_scene(scene) self.signal_scene_opened.emit(scene) self.updateGL() def remove_scene(self, scene): """ Removes a given GLScene object from the master scene. :param scene: GLScene to remove. """ self.state.remove_scene(scene) self.signal_scene_removed.emit(scene) self.updateGL() def add_camera(self, camera): """ :param camera: GLCamera object """ log.debug("GLWidget.add_camera: %s" % camera) self.state.add_camera(camera) self.signal_new_camera.emit(camera) def remove_camera(self, camera): """ :param camera: GLCamera object to remove """ self.state.remove_camera(camera) @update_camera def set_camera(self, camera="interactive"): """ Sets the scene camera from a given camera name string :param camera: Name of camera or GLCamera object """ if type(camera) in [str, unicode]: if "/" in camera: camera = os.path.split("/")[-1] if camera not in [cam.name for cam in self.state.cameras]: log.warn("camera not found: %s" % camera) return self.camera = self.state.get_camera_by_name(camera) else: self.camera = camera self.resizeGL(self.width(), self.height()) self.signal_set_camera.emit(self.camera) def _get_time(self): return self.__time def _set_time(self, new_time): self.__time = new_time self.__frame = new_time * self.fps for scene in self.state.scenes: if scene.visible: scene.set_time(new_time) if self.camera and self.camera.auto_frame: self.frame() self.signal_current_time.emit(new_time) self.signal_current_frame.emit(int(round(new_time * self.fps))) self.updateGL() current_time = property(_get_time, _set_time, doc="set/get current time") def _get_frame(self): return self.__frame def _set_frame(self, frame): if frame > self.frame_range()[1]: frame = self.frame_range()[0] elif frame < self.frame_range()[0]: frame = self.frame_range()[1] frame = frame / float(self.fps) self.current_time = frame current_frame = property(_get_frame, _set_frame, doc="set/get current frame") def is_playing(self): return self.__playing def play(self): """ plays loaded scenes by activating timer and setting callback """ self.timer.setInterval(1.0 / (float(self.fps))) self.connect(self.timer, QtCore.SIGNAL("timeout ()"), self._play_fwd_cb) self.timer.start() self.signal_play_fwd.emit() def _play_fwd_cb(self): """ play callback, sets current time for all scenes """ self.__playing = True min_time, max_time = self.time_range() self.current_time += 1.0 / float(self.fps) if self.current_time > max_time: self.current_time = min_time def stop(self): """ stops scene playback """ self.__playing = False self.disconnect(self.timer, QtCore.SIGNAL("timeout ()"), self._play_fwd_cb) self.connect(self.timer, QtCore.SIGNAL("timeout ()"), self._play_stop_cb) self.updateGL() def _play_stop_cb(self): self.signal_play_stop.emit() def _get_fps(self): return self.__fps def _set_fps(self, fps): self.__fps = fps fps = property(_get_fps, _set_fps, doc="frames per second value") def aspect_ratio(self): """ Returns current aspect ration of the viewer. """ return self.width() / float(self.height()) def time_range(self): """ Returns total time range in seconds. """ min = None max = None if self.state.scenes: for scene in self.state.scenes: if min is None or scene.min_time() < min: min = scene.min_time() if max is None or scene.max_time() > max: max = scene.max_time() else: min, max = 0, 0 return (min, max) def frame_range(self): """ Returns total frame range. """ (min, max) = self.time_range() return (min * self.fps, max * self.fps) def _get_bounds(self): #TODO: ugly code needs refactor if self.state.scenes: bounds = None for scene in self.state.scenes: if not scene.loaded: continue if bounds is None or scene.bounds().max() > bounds.max(): bounds = scene.bounds() min = bounds.min() max = bounds.max() if scene.properties.get("translate"): max = max * imath.V3d(*scene.translate) min = min * imath.V3d(*scene.translate) if scene.properties.get("scale"): max = max * imath.V3d(*scene.scale) min = min * imath.V3d(*scene.scale) bounds = imath.Box3d(min, max) if bounds is None: return self.__bounds_default self.__bounds = bounds return self.__bounds else: return self.__bounds_default def _set_bounds(self, bounds): self.__bounds = bounds bounds = property(_get_bounds, _set_bounds, doc="scene bounding box") @update_camera def frame(self, bounds=None): """ Frames the viewer's active camera on the bounds of the currently loaded and visible scenes. :param bounds: imath.Box3d bounds object. """ if bounds is None: bounds = self.bounds self.camera.frame(bounds) def split(self, orientation=QtCore.Qt.Vertical, wipe=False): """ Splist the viewer into two separate widgets according to the orientation param. """ if not self.parent(): return item = self.parent().layout().itemAt(0) splitter = GLSplitter(orientation, wipe) self.parent().layout().addWidget(splitter) group1 = QtGui.QGroupBox() group1.setLayout(QtGui.QVBoxLayout()) group1.layout().setSpacing(0) group1.layout().setMargin(0) group1.layout().addWidget(item.widget()) group2 = QtGui.QGroupBox() group2.setLayout(QtGui.QVBoxLayout()) group2.layout().setSpacing(0) group2.layout().setMargin(0) new_viewer = GLWidget(self._main, state=self.state) group2.layout().addWidget(new_viewer) splitter.addWidget(group1) splitter.addWidget(group2) def split_vert(self): """ Splits the viewer vertically. """ self.split(QtCore.Qt.Horizontal) def split_horz(self): """ Splits the viewer horizontally. """ self.split(QtCore.Qt.Vertical) #def wipe_horz(self): # self.split(QtCore.Qt.Horizontal, wipe=True) #TODO: support viewer pop-outs def unsplit(self): """ Unsplits and deletes current viewer """ if not self.parent(): return splitter = self.parent().parent() # should be exactly two groups per splitter index = splitter.indexOf(self.parent()) index_other = 1 * (1 - index) group = splitter.widget(index) group_other = splitter.widget(index_other) # disconnect signals #self.state.signal_state_change.disconnect() splitter.parent().layout().addWidget(group_other) splitter.parent().layout().removeWidget(splitter) # cleanup widgets del splitter del group del self def _paint_normals(self): glColor3f(1, 1, 1) def _draw(obj): md = obj.getMetaData() if alembic.AbcGeom.IPolyMesh.matches( md) or alembic.AbcGeom.ISubD.matches(md): meshObj = alembic.AbcGeom.IPolyMesh(obj.getParent(), obj.getName()) mesh = meshObj.getSchema() xf = get_final_matrix(meshObj) iss = alembic.Abc.ISampleSelector(0) facesProp = mesh.getFaceIndicesProperty() if not facesProp.valid(): return pointsProp = mesh.getPositionsProperty() if not pointsProp.valid(): return normalsProp = mesh.getNormalsParam().getValueProperty() if not normalsProp.valid(): return boundsProp = mesh.getSelfBoundsProperty() if not boundsProp.valid(): return faces = facesProp.getValue(iss) points = pointsProp.getValue(iss) normals = normalsProp.getValue(iss) bounds = boundsProp.getValue(iss) for i, fi in enumerate(faces): p = points[fi] * xf n = normals[i] v = p + n glBegin(GL_LINES) glColor3f(0, 1, 0) glVertex3f(p[0], p[1], p[2]) glVertex3f(v[0], v[1], v[2]) glEnd() for child in obj.children: try: _draw(child) except Exception, e: log.warn("unhandled exception: %s" % e) for scene in self.state.scenes: _draw(scene.top())