class Application(BasicApplication): # modes SELECT_MODE = 0 MOVE_MODE = 1 MOVE_X_MODE = 2 MOVE_Y_MODE = 3 MOVE_Z_MODE = 4 ROTATE_X_MODE = 6 ROTATE_Y_MODE = 7 ROTATE_Z_MODE = 8 SCALE_MODE = 9 SCALE_X_MODE = 10 SCALE_Y_MODE = 11 SCALE_Z_MODE = 12 SCALE_RADIAL_X_MODE = 13 SCALE_RADIAL_Y_MODE = 14 SCALE_RADIAL_Z_MODE = 15 def __init__(self): BasicApplication.__init__(self) # initialize timer self.timer = Timer(self.OnTimer) # initialize state self.scene = Scene() self.scene.modified = False self.camera = ZoomCamera() self.selected = [] self.mode = self.SELECT_MODE # initialize window self.window = Window(self) self.window.canvas.OnRender = self.OnRender def Update(self, deltaTime): if self.window.active: # update camera position translation = Vector3f() if wx.GetKeyState(ord('A')): translation.x -= 1 if wx.GetKeyState(ord('D')): translation.x += 1 if wx.GetKeyState(ord('Q')): translation.y -= 1 if wx.GetKeyState(ord('E')): translation.y += 1 if wx.GetKeyState(ord('W')): translation.z -= 1 if wx.GetKeyState(ord('S')): translation.z += 1 if any(translation): if wx.GetKeyState(wx.WXK_CONTROL): translation *= .25 if wx.GetKeyState(wx.WXK_SHIFT): translation *= 4 translation.x, translation.z = ( Euler(self.camera.orientation.yaw, 0, 0) * Vector3f(translation.x, 0, translation.z)).Swizzle(0, 2) self.camera.position += (translation * prefs['camera.translation.speed'] * deltaTime) self.window.canvas.Refresh() def AskSave(self): if self.scene.modified: result = ShowSaveChangesDialog(self.window) if result: self.SaveScene() elif result is None: return False return True def Exit(self): if not self.Destroy(): return self.window.Close() def Destroy(self, ask = True): if ask and not self.AskSave(): return False self.timer.Stop() return True # rendering def Render(self): SetCameraMatrix(self.camera) DrawScene(self.scene, self.selected, (1., .5, .5) if self.mode == self.SELECT_MODE else (1., .75, .5)) # draw wireframe if prefs['render.wireframe']: glPushAttrib(GL_DEPTH_BUFFER_BIT) glDepthMask(False) DrawSceneWireframe(self.scene) glPopAttrib() # draw world axes if prefs['render.axes']: self.DrawAxes() def DrawAxes(self): glTranslate(*self.camera.position) glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT) glDepthMask(False) glDepthFunc(GL_GEQUAL) glBegin(GL_LINES) axes = ( Vector3f(1, 0, 0), Vector3f(0, 1, 0), Vector3f(0, 0, 1)) for axis in axes: glColor((axis * 0.5).tolist()) glVertex(0, 0, 0) glVertex((axis * 0.5).tolist()) glEnd() glDepthMask(True) glDepthFunc(GL_LESS) glBegin(GL_LINES) for axis in axes: glColor(axis.tolist()) glVertex(0, 0, 0) glVertex((axis * 0.5).tolist()) glEnd() glPopAttrib() # selection def RenderSelect(self, cursorPosition): SetCameraMatrixForSelect(self.camera, cursorPosition) # initialize selection mode glSelectBuffer(256) glRenderMode(GL_SELECT) glInitNames() # draw scene DrawSceneForSelect(self.scene) glFlush() return glRenderMode(GL_RENDER) def Select(self, cursorPosition): nameStack = self.RenderSelect(cursorPosition) if nameStack: nearest = (None, 1.) for near, far, names in nameStack: if near < nearest[1]: nearest = (names, near) if nearest[0]: names = nearest[0] return self.scene.forms[names[0]] return None def UpdateSelection(self, cursorPosition, shiftDown, ctrlDown): selection = self.Select(cursorPosition) if selection: if shiftDown: if ctrlDown: if selection in self.selected: self.selected.remove(selection) self.window.canvas.Refresh() elif selection not in self.selected: self.selected.append(selection) self.window.canvas.Refresh() elif [selection] != self.selected: self.selected = [selection] self.window.canvas.Refresh() elif not shiftDown and self.selected: self.selected = [] self.window.canvas.Refresh() # mode functions def SetMode(self, mode): self.mode = mode self.window.canvas.Refresh() def BakeMode(self): if self.mode != self.SELECT_MODE: for sel in self.selected: sel.BakeTransformation() self.SetMode(self.SELECT_MODE) self.scene.modified = True def ResetMode(self): if self.mode != self.SELECT_MODE: for sel in self.selected: sel.ResetTransformation() self.SetMode(self.SELECT_MODE) def ModeOnCursorMotion(self, motion): if self.mode == self.MOVE_MODE: translation = ( Euler(self.camera.orientation.yaw, 0, 0) * Vector3f(motion.x, 0, motion.y) * prefs['tool.translation.speed']) for sel in self.selected: sel.translation += translation else: translation = motion.x * prefs['tool.translation.speed'] rotation = motion.x * prefs['tool.rotation.speed'] scale = motion.x * prefs['tool.scale.speed'] if self.mode == self.MOVE_X_MODE: for sel in self.selected: sel.translation.x += translation elif self.mode == self.MOVE_Y_MODE: for sel in self.selected: sel.translation.y += translation elif self.mode == self.MOVE_Z_MODE: for sel in self.selected: sel.translation.z += translation elif self.mode == self.ROTATE_X_MODE: for sel in self.selected: sel.rotation.pitch += rotation elif self.mode == self.ROTATE_Y_MODE: for sel in self.selected: sel.rotation.yaw += rotation elif self.mode == self.ROTATE_Z_MODE: for sel in self.selected: sel.rotation.roll += rotation elif self.mode == self.SCALE_MODE: for sel in self.selected: sel.rescale += scale elif self.mode == self.SCALE_X_MODE: for sel in self.selected: sel.rescale.x += scale elif self.mode == self.SCALE_Y_MODE: for sel in self.selected: sel.rescale.y += scale elif self.mode == self.SCALE_Z_MODE: for sel in self.selected: sel.rescale.z += scale elif self.mode == self.SCALE_RADIAL_X_MODE: for sel in self.selected: sel.rescale.y += scale sel.rescale.z += scale elif self.mode == self.SCALE_RADIAL_Y_MODE: for sel in self.selected: sel.rescale.x += scale sel.rescale.z += scale elif self.mode == self.SCALE_RADIAL_Z_MODE: for sel in self.selected: sel.rescale.x += scale sel.rescale.y += scale self.window.canvas.Refresh() # camera modifiers def RotateCamera(self, cursorTranslation): cursorTranslation *= prefs['camera.rotation.speed'] rotation = Euler([RevToRad(c) for c in -cursorTranslation]) self.camera.orientation *= rotation self.window.canvas.Refresh() def GotoSelection(self): if self.selected: self.camera.position = \ sum([sel.position for sel in self.selected]) / len(self.selected) self.window.canvas.Refresh() # scene modifiers def NewForm(self): path = ShowOpenModelDialog(self.window, os.path.dirname(prefs['file.model.last']) + os.path.sep) if path: model = Model().FromFile(path) name = os.path.splitext(os.path.basename(path))[0] form = self.scene.Form(name, model) form.position = self.camera.position form.orientation.yaw = self.camera.orientation.yaw self.scene.forms.append(form) self.scene.modified = True self.window.canvas.Refresh() prefs['file.model.last'] = path # absolute positioning def PutOnTrack(self): # FIXME: implement self.window.canvas.Refresh() def PutOnGround(self): print 'working...' for sel in self.selected: if sel.name: print ' %s...' % sel.name nearest = (NegInf, None) for form in self.scene.forms: if form.model and form not in self.selected: for part in form.model.parts: vertices = [form.matrix * vertex.co for vertex in part.mesh.vertices] for face in part.mesh.faces: if IsPointInTriangle( sel.position.Swizzle(0, 2), vertices[face.indices[0]].Swizzle(0, 2), vertices[face.indices[1]].Swizzle(0, 2), vertices[face.indices[2]].Swizzle(0, 2)): mu = Barycentric( sel.position.Swizzle(0, 2), vertices[face.indices[0]].Swizzle(0, 2), vertices[face.indices[1]].Swizzle(0, 2), vertices[face.indices[2]].Swizzle(0, 2)) height = Bilerp( vertices[face.indices[0]].y, vertices[face.indices[1]].y, vertices[face.indices[2]].y, *mu) if (height <= sel.position.y + .001 and height > nearest[0]): normal = Bilerp( Orientation.GetMatrix(form) * part.mesh.vertices[face.indices[0]].no, Orientation.GetMatrix(form) * part.mesh.vertices[face.indices[1]].no, Orientation.GetMatrix(form) * part.mesh.vertices[face.indices[2]].no, *mu).Norm() nearest = (height, normal) if nearest[1]: sel.position.y = nearest[0] # FIXME: this implementation doesn't work # sel.orientation = EulerBetween(Vector3f(0, 1, 0), normal) self.window.canvas.Refresh() print 'done' # selection modifiers def DeleteSelection(self): if self.selected: for sel in self.selected: self.scene.forms.remove(sel) self.selected = [] self.window.canvas.Refresh() def ToggleSelection(self): for form in self.scene.forms: if form in self.selected: self.selected = [] break else: self.selected = self.scene.forms self.window.canvas.Refresh() # file menu functions def NewScene(self): if not self.AskSave(): return self.scene.__init__() self.scene.modified = False self.selected = [] self.window.canvas.Refresh() def OpenScene(self): if not self.AskSave(): return path = ShowOpenSceneDialog(self.window, os.path.dirname(prefs['file.scene.last']) + os.path.sep) if path: self.scene.FromFile(path) self.scene.modified = False self.selected = [] self.window.canvas.Refresh() prefs['file.scene.last'] = path print 'scene loaded from %s' % self.scene.path def SaveScene(self): if self.scene.modified: if self.scene.absPath: self.scene.ToFile() self.scene.modified = False print 'scene saved as %s' % self.scene.path else: self.SaveSceneAs() def SaveSceneAs(self): scenePath = ShowSaveSceneDialog(self.window, self.scene.absPath) if scenePath: self.scene.ToFile(scenePath) self.scene.modified = False print 'scene saved as %s' % self.scene.path def RevertScene(self): if self.scene.absPath: self.scene.FromFile() self.scene.modified = False self.selected = [] self.window.canvas.Refresh() print 'scene reverted from %s' % self.scene.path def ChangeRootDir(self): # FIXME: this should be a standard dialog # FIXME: we will have to reload all resources if root is changed pass ''' dlg = wx.DirDialog(self, 'Choose a root directory for loading resources', prefs['res.root'], wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST) if dlg.ShowModal() == wx.ID_OK: prefs['res.root'] = dlg.GetPath() ''' def ShowPreferences(self): pass # FIXME: show preference dialog # event handlers def OnRender(self): self.timer.Update() def OnTimer(self): self.Update(self.timer.delta)
class Application(BasicApplication): # selection constraints selectFaceConstraint = 1 deselectFaceConstraint = 2 selectCameraConstraint = 3 deselectCameraConstraint = 4 def __init__(self): BasicApplication.__init__(self) # initialize timer self.timer = Timer(self.OnTimer) # initialize state self.scene = Scene() self.scene.modified = False self.camera = Camera(Vector3f(4), Euler(DegToRad(45), DegToRad(-45))) self.selectedCamera = None # initialize window self.window = Window(self) self.window.canvas.OnRender = self.OnRender def Update(self, deltaTime): if self.window.active: # update camera position translation = Vector3f() if wx.GetKeyState(ord('A')): translation.x -= 1 if wx.GetKeyState(ord('D')): translation.x += 1 if wx.GetKeyState(ord('Q')): translation.y -= 1 if wx.GetKeyState(ord('E')): translation.y += 1 if wx.GetKeyState(ord('W')): translation.z -= 1 if wx.GetKeyState(ord('S')): translation.z += 1 if any(translation): if wx.GetKeyState(wx.WXK_CONTROL): translation *= .25; if wx.GetKeyState(wx.WXK_SHIFT): translation *= 4; self.camera.position += ( self.camera.orientation * translation * prefs['camera.translation.speed'] * deltaTime) self.window.canvas.Refresh() def AskSave(self): if (self.scene.modified or self.scene.cameraSet and self.scene.cameraSet.modified): result = ShowSaveChangesDialog(self.window) if result: self.Save() elif result is None: return False return True def Exit(self): if not self.Destroy(): return self.window.Close() def Destroy(self, ask = True): if ask and not self.AskSave(): return False self.timer.Stop() return True # rendering def RenderEdit(self): glPushAttrib(GL_VIEWPORT) viewport = glGetIntegerv(GL_VIEWPORT) glViewport( viewport[0], viewport[1], viewport[2] / 2, viewport[3]) SetCameraMatrix(self.camera) # draw track if self.scene.track: DrawTrack(self.scene.track, ( [face for i, face in enumerate(self.scene.track.faces) if self.selectedCamera in self.scene.cameraSet.trackFaces[i].cameras] if self.scene.cameraSet else ())) # draw cameras if self.scene.cameraSet: DrawCameras(self.scene.cameraSet.cameras, (self.selectedCamera,)) glPopAttrib() def RenderView(self): glPushAttrib(GL_VIEWPORT) viewport = glGetIntegerv(GL_VIEWPORT) glViewport( viewport[0] + viewport[2] / 2, viewport[1], viewport[2] - viewport[2] / 2, viewport[3]) SetCameraMatrix(self.selectedCamera or self.camera) # draw scene DrawScene(self.scene) # draw track if self.scene.track: DrawTrack(self.scene.track, ( [face for i, face in enumerate(self.scene.track.faces) if self.selectedCamera in self.scene.cameraSet.trackFaces[i].cameras] if self.scene.cameraSet else ())) glPopAttrib() # selection def RenderSelect(self, cursorPosition): glPushAttrib(GL_VIEWPORT) viewport = glGetIntegerv(GL_VIEWPORT) glViewport( viewport[0], viewport[1], viewport[2] / 2, viewport[3]) SetCameraMatrixForSelect(self.camera, cursorPosition) # initialize selection mode glSelectBuffer(256) glRenderMode(GL_SELECT) glInitNames() # draw track if self.scene.track: glPushName(0) DrawTrackForSelect(self.scene.track) glPopName() # draw cameras if self.scene.cameraSet: glPushName(1) DrawCamerasForSelect(self.scene.cameraSet.cameras) glPopName() glPopAttrib() glFlush() return glRenderMode(GL_RENDER) def Select(self, cursorPosition): nameStack = self.RenderSelect(cursorPosition) if nameStack: nearest = (None, 1.) for near, far, names in nameStack: if near < nearest[1]: nearest = (names, near) if nearest[0]: names = nearest[0] if names[0] == 0: return self.scene.track.faces[names[1]] if names[0] == 1: return self.scene.cameraSet.cameras[names[1]] assert not 'invalid name in stack' return None def UpdateSelection(self, cursorPosition, reset = False): if reset: self.__selectConstraint = None cursorPosition = Vector2i(cursorPosition) if cursorPosition.x < self.window.canvas.Size[0] / 2: selection = self.Select(cursorPosition) if isinstance(selection, Track.Face): if self.selectedCamera: i = self.scene.track.faces.index(selection) cameras = self.scene.cameraSet.trackFaces[i].cameras if self.selectedCamera not in cameras: if (not self.__selectConstraint or self.__selectConstraint is self.selectFaceConstraint): self.__selectConstraint = self.selectFaceConstraint cameras.append(self.selectedCamera) self.scene.cameraSet.modified = True self.window.canvas.Refresh() else: if (not self.__selectConstraint or self.__selectConstraint is self.deselectFaceConstraint): self.__selectConstraint = self.deselectFaceConstraint cameras.remove(self.selectedCamera) self.scene.cameraSet.modified = True self.window.canvas.Refresh() elif isinstance(selection, CameraSet.Camera): if (not self.__selectConstraint or self.__selectConstraint is self.selectCameraConstraint): self.__selectConstraint = self.selectCameraConstraint if selection is not self.selectedCamera: self.selectedCamera = selection self.window.canvas.Refresh() elif selection is None: if (not self.__selectConstraint or self.__selectConstraint is self.deselectCameraConstraint): self.__selectConstraint = self.deselectCameraConstraint if self.selectedCamera: self.selectedCamera = None self.window.canvas.Refresh() # camera modifiers def RotateCamera(self, cursorTranslation): cursorTranslation *= prefs['camera.rotation.speed'] * .001 rotation = Euler([RevToRad(c) for c in -cursorTranslation]) self.camera.orientation *= rotation self.window.canvas.Refresh() # camera set modifiers def NewCamera(self): if not self.scene.cameraSet: MakeCameraSet(self.scene) camera = CameraSet.Camera() camera.position = self.camera.position camera.orientation = Quaternion(self.camera.orientation) camera.fov = self.camera.fov self.scene.cameraSet.cameras.append(camera) self.selectedCamera = camera self.scene.cameraSet.modified = True self.window.canvas.Refresh() def DeleteSelectedCamera(self): assert self.selectedCamera self.ClearFaceSelection() self.scene.cameraSet.cameras.remove(self.selectedCamera) self.scene.cameraSet.modified = True self.selectedCamera = None self.window.canvas.Refresh() def RepositionSelectedCamera(self): assert self.selectedCamera self.selectedCamera.position = self.camera.position self.selectedCamera.orientation = Quaternion(self.camera.orientation) self.scene.cameraSet.modified = True self.window.canvas.Refresh() def ShowSelectedCameraProperties(self): if CameraPropertiesDialog(self.window.canvas, self.selectedCamera).ShowModal(): self.scene.cameraSet.modified = True self.window.canvas.Refresh() # track face selection modifiers def ClearFaceSelection(self): assert self.selectedCamera for face in self.scene.cameraSet.trackFaces: if self.selectedCamera in face.cameras: face.cameras.remove(self.selectedCamera) self.scene.cameraSet.modified = True self.window.canvas.Refresh() def ToggleFaceSelection(self): assert self.selectedCamera for face in self.scene.cameraSet.trackFaces: if self.selectedCamera in face.cameras: self.ClearFaceSelection() return for face in self.scene.cameraSet.trackFaces: face.cameras.append(self.selectedCamera) self.scene.cameraSet.modified = True self.window.canvas.Refresh() # file menu functions def NewScene(self): if not self.AskSave(): return self.scene.__init__() self.scene.modified = False self.selectedCamera = None self.window.canvas.Refresh() def OpenScene(self): if not self.AskSave(): return path = ShowOpenSceneDialog(self.window, os.path.dirname(prefs['file.scene.last']) + os.path.sep) if path: self.scene.FromFile(path) self.scene.modified = False if self.scene.cameraSet: self.scene.cameraSet.modified = False if self.scene.track: BindCameraSet(self.scene.cameraSet, self.scene.track) self.selectedCamera = None self.window.canvas.Refresh() prefs['file.scene.last'] = path print 'scene loaded from %s' % self.scene.path def Save(self): # request scene path if self.scene.modified and not self.scene.absPath: scenePath = ShowSaveSceneDialog(self.window) if not scenePath: return # request camera set path if self.scene.cameraSet and self.scene.cameraSet.modified and not self.scene.cameraSet.absPath: cameraSetPath = ShowSaveCameraSetDialog(self.window, (self.scene.absPath or scenePath).replace('.scene', '.cam')) if not cameraSetPath: return # NOTE: must set path here so that scene will know about it self.scene.cameraSet.SetPath(cameraSetPath) # save scene if self.scene.modified: self.scene.ToFile(self.scene.absPath or scenePath) self.scene.modified = False print 'scene saved as %s' % self.scene.path # save camera set if self.scene.cameraSet and self.scene.cameraSet.modified: self.scene.cameraSet.ToFile() self.scene.cameraSet.modified = False print 'camera set saved as %s' % self.scene.cameraSet.path def SaveAs(self): # request scene path scenePath = ShowSaveSceneDialog(self.window, self.scene.absPath) # request camera set path if self.scene.cameraSet: cameraSetPath = ShowSaveCameraSetDialog(self.window, self.cameraSet.absPath) if cameraSetPath: # NOTE: must set path here so that scene will know about it self.scene.cameraSet.SetPath(cameraSetPath) # save scene if scenePath: self.scene.ToFile(scenePath) self.scene.modified = False print 'scene saved as %s' % self.scene.path # save camera set if self.scene.cameraSet and cameraSetPath: self.scene.cameraSet.ToFile() self.scene.cameraSet.modified = False print 'camera set saved as %s' % self.scene.cameraSet.path def Revert(self): if self.scene.absPath: self.scene.FromFile() self.scene.modified = False if self.scene.cameraSet: self.scene.cameraSet.modified = False self.selectedCamera = None self.window.canvas.Refresh() print 'scene reverted from %s' % self.scene.path # event handlers def OnRender(self): self.timer.Update() def OnTimer(self): self.Update(self.timer.delta)