Example #1
0
    def __init__(self):
        #loadPrcFileData('startup', 'window-type none')
        self.currentFile = None
        self.fNeedToSave = False
        self.actionEvents = []
        #self.objectMgr = ObjectMgr(self)
        self.curveEditor = CurveEditor(self)
        self.fileMgr = FileMgr(self)
        self.actionMgr = ActionMgr()

        self.fMoveCamera = False

        self.NPParent = render

        # define your own config file in inherited class
        self.settingsFile = None

        # you can show/hide specific properties by using propertiesMask and this mode
        self.BASE_MODE = BitMask32.bit(0)
        self.CREATE_CURVE_MODE = BitMask32.bit(2)
        self.EDIT_CURVE_MODE = BitMask32.bit(3)
        self.ANIM_MODE = BitMask32.bit(4)
        self.GRAPH_EDITOR = False

        self.mode = self.BASE_MODE
        self.preMode = None
Example #2
0
    def __init__(self):
        #loadPrcFileData('startup', 'window-type none')
        self.currentFile = None
        
        self.fNeedToSave = False    #if there are unsaved changes
        self.actionEvents = []
        #self.objectMgr = ObjectMgr(self)
        self.fileMgr = FileMgr(self)
        self.actionMgr = ActionMgr()
        self.standaloneExporter = StandaloneExporter(self)
        self.saved = False  #if the project has been saved at all

        self.fMoveCamera = False

        self.NPParent = render

        # define your own config file in inherited class
        self.settingsFile = None

        # you can show/hide specific properties by using propertiesMask and this mode
        self.mode = BitMask32()
        
        self.tempDir = None
        
        self.manipMode = 'translate'
        
        groundRay = CollisionNode('groundRay')
        groundRay.addSolid(CollisionRay(Point3(0,0,0), Vec3(0,0,-1)))
        groundRay.setFromCollideMask(BitMask32.allOn())
        self.groundCollide = render.attachNewNode(groundRay)
        self.groundCollideHandler = CollisionHandlerQueue()
        self.groundCollideTraverser = CollisionTraverser()
        self.groundCollideTraverser.addCollider(self.groundCollide, self.groundCollideHandler)
    def __init__(self):
        #loadPrcFileData('startup', 'window-type none')
        self.currentFile = None
        
        self.fNeedToSave = False    #if there are unsaved changes
        self.actionEvents = []
        #self.objectMgr = ObjectMgr(self)
        self.fileMgr = FileMgr(self)
        self.actionMgr = ActionMgr()
        self.standaloneExporter = StandaloneExporter(self)
        self.saved = False  #if the project has been saved at all

        self.fMoveCamera = False

        self.NPParent = render

        # define your own config file in inherited class
        self.settingsFile = None

        # you can show/hide specific properties by using propertiesMask and this mode
        self.mode = BitMask32()
        
        self.tempDir = None
        
        self.manipMode = 'translate'
        
        groundRay = CollisionNode('groundRay')
        groundRay.addSolid(CollisionRay(Point3(0,0,0), Vec3(0,0,-1)))
        groundRay.setFromCollideMask(BitMask32.allOn())
        self.groundCollide = render.attachNewNode(groundRay)
        self.groundCollideHandler = CollisionHandlerQueue()
        self.groundCollideTraverser = CollisionTraverser()
        self.groundCollideTraverser.addCollider(self.groundCollide, self.groundCollideHandler)
Example #4
0
    def __init__(self, parent, editor, terrain):
        pre = wx.PreDialog()
        self.res = xrc.XmlResource(GUI_FILENAME)
        self.res.LoadOnDialog(pre, parent, 'dlgTerrainPaint')
        self.PostCreate(pre)
        self.Bind(wx.EVT_INIT_DIALOG, self.onCreate)

        self.parent = parent
        self.editor = editor
        self.terrain = terrain
        #self.oldCanvas = PNMImgae()
        #self.oldCanvas.copyFrom(terrain.heightField())
        self.brushRadius = 1
        self.viewport = None

        self.oldX = -1
        self.oldY = -1

        self.paintCursor = loader.loadModel(
            "models/terrain_cursor.egg")  #jack")
        self.paintRing = loader.loadModel("models/terrain_ring.egg")
        self.paintCursor.setScale(12)
        self.paintCursor.reparentTo(self.editor.NPParent)
        self.paintCursor.setPos(self.terrain.getNodePath().getPos())
        self.paintRing.reparentTo(self.editor.NPParent)
        self.paintRing.setPos(self.paintCursor.getPos())

        taskMgr.add(self.followMouseTask, "followMouseTask")
        self.customImage = PNMImage(32, 32)
        self.customImage.read("full_white_square_gradiant_alpha.tif")
        self.raiseImageWithCustomImage()

        #TO DO:if no light check for later
        light = PointLight('Terrain Light')
        light.setColor(Vec4(1, 1, 1, 1))
        self.light = self.editor.NPParent.attachNewNode(light)
        pos = self.terrain.getNodePath().getPos()
        self.light.setPos(Point3(0, 0, pos[2] + 240))
        self.terrain.getNodePath().setLight(
            self.light)  #self.editor.NPParent.setLight(self.light)
        #self.editor.NPParent.setPoint(Point3(0,0, pos[2]+400))

        self.actionMgr = ActionMgr()
 def __init__(self, parent, editor, terrain):
     pre = wx.PreDialog()
     self.res = xrc.XmlResource(GUI_FILENAME)
     self.res.LoadOnDialog(pre, parent, 'dlgTerrainPaint')
     self.PostCreate(pre)
     self.Bind(wx.EVT_INIT_DIALOG, self.onCreate)
     
     self.parent = parent
     self.editor = editor
     self.terrain = terrain
     #self.oldCanvas = PNMImgae()
     #self.oldCanvas.copyFrom(terrain.heightField())
     self.brushRadius = 1
     self.viewport = None
     
     self.oldX = -1
     self.oldY = -1
     
     self.paintCursor = loader.loadModel("models/terrain_cursor.egg")#jack")
     self.paintRing = loader.loadModel("models/terrain_ring.egg")
     self.paintCursor.setScale(12)
     self.paintCursor.reparentTo(self.editor.NPParent)
     self.paintCursor.setPos(self.terrain.getNodePath().getPos())
     self.paintRing.reparentTo(self.editor.NPParent)
     self.paintRing.setPos(self.paintCursor.getPos())
     
     taskMgr.add(self.followMouseTask, "followMouseTask")
     self.customImage = PNMImage(32,32)
     self.customImage.read("full_white_square_gradiant_alpha.tif")
     self.raiseImageWithCustomImage()
     
     #TO DO:if no light check for later
     light = PointLight('Terrain Light')
     light.setColor(Vec4(1,1,1,1))
     self.light = self.editor.NPParent.attachNewNode(light)
     pos = self.terrain.getNodePath().getPos()
     self.light.setPos(Point3(0,0,pos[2]+240))
     self.terrain.getNodePath().setLight(self.light)#self.editor.NPParent.setLight(self.light)
     #self.editor.NPParent.setPoint(Point3(0,0, pos[2]+400))
     
     self.actionMgr = ActionMgr()
Example #6
0
class LevelEditorBase(DirectObject):
    """ Base Class for Panda3D LevelEditor """
    def __init__(self):
        #loadPrcFileData('startup', 'window-type none')
        self.currentFile = None
        self.fNeedToSave = False
        self.actionEvents = []
        #self.objectMgr = ObjectMgr(self)
        self.curveEditor = CurveEditor(self)
        self.fileMgr = FileMgr(self)
        self.actionMgr = ActionMgr()

        self.fMoveCamera = False

        self.NPParent = render

        # define your own config file in inherited class
        self.settingsFile = None

        # you can show/hide specific properties by using propertiesMask and this mode
        self.BASE_MODE = BitMask32.bit(0)
        self.CREATE_CURVE_MODE = BitMask32.bit(2)
        self.EDIT_CURVE_MODE = BitMask32.bit(3)
        self.ANIM_MODE = BitMask32.bit(4)
        self.GRAPH_EDITOR = False

        self.mode = self.BASE_MODE
        self.preMode = None

    def initialize(self):
        """ You should call this in your __init__ method of inherited LevelEditor class """
        # specifiy what obj can be 'selected' as objects
        base.direct.selected.addTag('OBJRoot')

        self.actionEvents.extend([
            # Node path events
            ('DIRECT-select', self.select),
            ('DIRECT-delete', self.handleDelete),
            ('DIRECT-preDeselectAll', self.deselectAll),
            ('DIRECT_deselectAll', self.deselectAllCB),
            ('preRemoveNodePath', self.removeNodePathHook),
            ('DIRECT_deselectedNodePath', self.deselectAllCB),
            ('DIRECT_selectedNodePath_fMulti_fTag_fLEPane', self.selectedNodePathHook),
            ('DIRECT_deselectAll', self.deselectAll),
            ('LE-Undo', self.actionMgr.undo),
            ('LE-Redo', self.actionMgr.redo),
            ('LE-Duplicate', self.objectMgr.duplicateSelected),
            ('DIRECT_manipulateObjectCleanup', self.cleanUpManipulating),
            ('LE-MakeLive', self.objectMgr.makeSelectedLive),
            ('LE-NewScene', self.ui.onNew),
            ('LE-SaveScene', self.ui.onSave),
            ('LE-OpenScene', self.ui.onOpen),
            ('LE-Quit', self.ui.quit),
            ('DIRECT-mouse1', self.handleMouse1),
            ('DIRECT-mouse1Up', self.handleMouse1Up),
            ('DIRECT-mouse2', self.handleMouse2),
            ('DIRECT-mouse2Up', self.handleMouse2Up),
            ('DIRECT-mouse3', self.handleMouse3),
            ('DIRECT-mouse3Up', self.handleMouse3Up),
            ('DIRECT-toggleWidgetVis', self.toggleWidget),
            ])

        # Add all the action events
        for event in self.actionEvents:
            if len(event) == 3:
                self.accept(event[0], event[1], event[2])
            else:
                self.accept(event[0], event[1])

        # editor state text display such as edit mode
        self.statusReadout = OnscreenText(
            pos = (-1.2, 0.9), bg=Vec4(1,1,1,1),
            scale = 0.05, align = TextNode.ALeft,
            mayChange = 1, font = TextNode.getDefaultFont())
        self.statusReadout.setText("")
        # Make sure readout is never lit or drawn in wireframe
        useDirectRenderStyle(self.statusReadout)
        self.statusReadout.reparentTo(hidden)
        self.statusLines = []
        taskMgr.doMethodLater(5, self.updateStatusReadoutTimeouts, 'updateStatus')

        self.loadSettings()
        self.reset()

    def setTitleWithFilename(self, filename=""):
        title = self.ui.appname
        if filename != "":
           filenameshort = os.path.basename(filename)
           title = title + " (%s)"%filenameshort
        self.ui.SetLabel(title)

    def removeNodePathHook(self, nodePath):
        if nodePath is None:
            return
        base.direct.deselect(nodePath)
        self.objectMgr.removeObjectByNodePath(nodePath)

        if base.direct.selected.last is not None and nodePath == base.direct.selected.last:
            # if base.direct.selected.last is refering to this
            # removed obj, clear the reference
            if (hasattr(__builtins__,'last')):
                __builtins__.last = None
            else:
                __builtins__['last'] = None
            base.direct.selected.last = None

    def toggleWidget(self):
        if self.objectMgr.currNodePath:
            obj = self.objectMgr.findObjectByNodePath(self.objectMgr.currNodePath)
            if obj and not obj[OG.OBJ_DEF].movable:
                return
        base.direct.toggleWidgetVis()

    def handleMouse1(self, modifiers):
        if base.direct.fAlt or modifiers == 4:
            self.fMoveCamera = True
            return
        if self.mode == self.CREATE_CURVE_MODE :
            self.curveEditor.createCurve()


    def handleMouse1Up(self):
        self.fMoveCamera = False


    def handleMouse2(self, modifiers):
        if base.direct.fAlt or modifiers == 4:
            self.fMoveCamera = True
            return

    def handleMouse2Up(self):
        self.fMoveCamera = False

    def handleMouse3(self, modifiers):
        if base.direct.fAlt or modifiers == 4:
            self.fMoveCamera = True
            return

        self.ui.onRightDown()

    def handleMouse3Up(self):
        self.fMoveCamera = False

    def handleDelete(self):
        oldSelectedNPs = base.direct.selected.getSelectedAsList()
        oldUIDs = []
        for oldNP in oldSelectedNPs:
            obj = self.objectMgr.findObjectByNodePath(oldNP)
            if obj:
                oldUIDs.append(obj[OG.OBJ_UID])

        action = ActionDeleteObj(self)
        self.actionMgr.push(action)
        action()

        for uid in oldUIDs:
            self.ui.sceneGraphUI.delete(uid)

##         reply = wx.MessageBox("Do you want to delete selected?", "Delete?",
##                               wx.YES_NO | wx.ICON_QUESTION)
##         if reply == wx.YES:
##             base.direct.removeAllSelected()
##         else:
##             # need to reset COA
##             dnp = base.direct.selected.last
##             # Update camera controls coa to this point
##             # Coa2Camera = Coa2Dnp * Dnp2Camera
##             mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(base.direct.camera)
##             row = mCoa2Camera.getRow(3)
##             coa = Vec3(row[0], row[1], row[2])
##             base.direct.cameraControl.updateCoa(coa)

    def cleanUpManipulating(self, selectedNPs):
        for np in selectedNPs:
            obj = self.objectMgr.findObjectByNodePath(np)
            if obj:
                action = ActionTransformObj(self, obj[OG.OBJ_UID], Mat4(np.getMat()))
                self.actionMgr.push(action)
                action()

    def select(self, nodePath, fMultiSelect=0, fSelectTag=1, fResetAncestry=1, fLEPane=0, fUndo=1):
        if fUndo:
            # Select tagged object if present
            if fSelectTag:
                for tag in base.direct.selected.tagList:
                    if nodePath.hasNetTag(tag):
                        nodePath = nodePath.findNetTag(tag)
                        break
            action = ActionSelectObj(self, nodePath, fMultiSelect)
            self.actionMgr.push(action)
            action()
        else:
            base.direct.selectCB(nodePath, fMultiSelect, fSelectTag, fResetAncestry, fLEPane, fUndo)

    def selectedNodePathHook(self, nodePath, fMultiSelect = 0, fSelectTag = 1, fLEPane = 0):
        # handle unpickable nodepath
        if nodePath.getName() in base.direct.iRay.unpickable:
            base.direct.deselect(nodePath)
            return

        if fMultiSelect == 0 and fLEPane == 0:
           oldSelectedNPs = base.direct.selected.getSelectedAsList()
           for oldNP in oldSelectedNPs:
              obj = self.objectMgr.findObjectByNodePath(oldNP)
              if obj:
                 self.ui.sceneGraphUI.deSelect(obj[OG.OBJ_UID])
        self.objectMgr.selectObject(nodePath, fLEPane)
        self.ui.buildContextMenu(nodePath)

        if self.mode == self.EDIT_CURVE_MODE:
            taskMgr.add(self.curveEditor.editCurve, "modify")
            self.curveEditor.accept("DIRECT-enter", self.curveEditor.onBaseMode)

    def deselectAll(self, np=None):
        if len(base.direct.selected.getSelectedAsList()) ==0:
            return
        action = ActionDeselectAll(self)
        self.actionMgr.push(action)
        action()

    def deselectAllCB(self, dnp=None):
        self.objectMgr.deselectAll()

    def reset(self):
        if self.fNeedToSave:
            reply = wx.MessageBox("Do you want to save current scene?", "Save?",
                               wx.YES_NO | wx.ICON_QUESTION)
            if reply == wx.YES:
                result = self.ui.onSave()
                if result == False:
                    return

        base.direct.deselectAll()
        base.direct.selected.last = None
        self.ui.reset()
        self.objectMgr.reset()
        self.animMgr.reset()
        self.actionMgr.reset()
        self.ui.perspView.camera.setPos(-19, -19, 19)
        self.ui.perspView.camera.lookAt(Point3(0, 0, 0))
        self.ui.leftView.camera.setPos(600, 0, 0)
        self.ui.frontView.camera.setPos(0, -600, 0)
        self.ui.topView.camera.setPos(0, 0, 600)
        self.resetOrthoCam(self.ui.topView)
        self.resetOrthoCam(self.ui.frontView)
        self.resetOrthoCam(self.ui.leftView)
        self.fNeedToSave = False
        self.setTitleWithFilename()

    def resetOrthoCam(self, view):
        base.direct.drList[base.camList.index(NodePath(view.camNode))].orthoFactor = 0.1
        x = view.ClientSize.GetWidth() * 0.1
        y = view.ClientSize.GetHeight() * 0.1
        view.camLens.setFilmSize(x, y)

    def save(self):
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        if self.currentFile:
            self.fileMgr.saveToFile(self.currentFile)
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))

    def saveAs(self, fileName):
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        self.fileMgr.saveToFile(fileName)
        self.currentFile = fileName
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))

    def load(self, fileName):
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        self.reset()
        self.fileMgr.loadFromFile(fileName)
        self.currentFile = fileName
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))

    def saveSettings(self):
        if self.settingsFile is None:
            return

        try:
            f = open(self.settingsFile, 'w')
            f.write('gridSize\n%f\n'%self.ui.perspView.grid.gridSize)
            f.write('gridSpacing\n%f\n'%self.ui.perspView.grid.gridSpacing)
            f.write('hotKey\n%s\n'%base.direct.hotKeyMap)
            f.close()
        except:
            pass

    def loadSettings(self):
        if self.settingsFile is None:
            return

        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        try:
            f = open(self.settingsFile, 'r')
            configLines = f.readlines()
            f.close()

            gridSize = 100.0
            gridSpacing = 5.0
            for i in range(0, len(configLines)):
                line = configLines[i]
                i = i + 1
                if line.startswith('gridSize'):
                    gridSize = float(configLines[i])
                elif line.startswith('gridSpacing'):
                    gridSpacing = float(configLines[i])
                elif line.startswith('hotKey'):
                    customHotKeyMap = eval(configLines[i])
                    customHotKeyDict = {}
                    for hotKey in customHotKeyMap.keys():
                        desc = customHotKeyMap[hotKey]
                        customHotKeyDict[desc[1]] = hotKey

                    overriddenKeys = []
                    for key in base.direct.hotKeyMap.keys():
                        desc = base.direct.hotKeyMap[key]
                        if desc[1] in customHotKeyDict.keys():
                            overriddenKeys.append(key)

                    for key in overriddenKeys:
                        del base.direct.hotKeyMap[key]

                    base.direct.hotKeyMap.update(customHotKeyMap)

            self.ui.updateGrids(gridSize, gridSpacing)
            self.ui.updateMenu()
        except:
            pass
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))

    def convertMaya(self, modelname, callBack, obj=None, isAnim=False):
        if obj and isAnim:
            mayaConverter = MayaConverter(self.ui, self, modelname, callBack, obj, isAnim)
        else:
            reply = wx.MessageBox("Is it an animation file?", "Animation?",
                              wx.YES_NO | wx.ICON_QUESTION)
            if reply == wx.YES:
                mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, True)
            else:
                mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, False)
        mayaConverter.Show()

    def convertFromMaya(self, modelname, callBack):
        mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, False)
        mayaConverter.Show()

    def exportToMaya(self, mayaFileName):
        exportRootNP = render
        self.exportToMayaCB(mayaFileName, exportRootNP)

    def exportToMayaCB(self, mayaFileName, exportRootNP):
        bamFileName = mayaFileName + ".bam"

        if base.direct.selected.last:
            obj = self.objectMgr.findObjectByNodePath(base.direct.selected.last)
            if obj:
                exportRootNP = obj[OG.OBJ_NP]

        exportRootNP.writeBamFile(bamFileName)
        mayaConverter = MayaConverter(self.ui, self, mayaFileName, None, None, False, FROM_BAM_TO_MAYA)
        mayaConverter.Show()

    def updateStatusReadout(self, status, color=None):
        if status:
            # add new status line, first check to see if it already exists
            alreadyExists = False
            for currLine in self.statusLines:
                if (status == currLine[1]):
                    alreadyExists = True
                    break
            if (alreadyExists == False):
                time = globalClock.getRealTime() + 15
                self.statusLines.append([time,status,color])

        # update display of new status lines
        self.statusReadout.reparentTo(aspect2d)
        statusText = ""
        lastColor = None
        for currLine in self.statusLines:
            statusText += currLine[1] + '\n'
            lastColor = currLine[2]
        self.statusReadout.setText(statusText)
        if (lastColor):
            self.statusReadout.textNode.setCardColor(
                lastColor[0], lastColor[1], lastColor[2], lastColor[3])
            self.statusReadout.textNode.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
        else:
            self.statusReadout.textNode.setCardColor(1,1,1,1)
            self.statusReadout.textNode.setCardAsMargin(0.1, 0.1, 0.1, 0.1)

    def updateStatusReadoutTimeouts(self,task=None):
        removalList = []
        for currLine in self.statusLines:
            if (globalClock.getRealTime() >= currLine[0]):
                removalList.append(currLine)
        for currRemoval in removalList:
            self.statusLines.remove(currRemoval)
        self.updateStatusReadout(None)
        # perform doMethodLater again after delay
        # This crashes when CTRL-C'ing, so this is a cheap hack.
        #return 2
        from direct.task import Task
        return Task.again

    def propMeetsReq(self, typeName, parentNP):
        if self.ui.parentToSelectedMenuItem.IsChecked():
           if base.direct.selected.last:
              parent = base.le.objectMgr.findObjectByNodePath(base.direct.selected.last)
              if parent:
                 parentNP[0] = parent[OG.OBJ_NP]
        else:
           parentNP[0] = None
        return True
class LevelEditorBase(DirectObject):
    """ Base Class for Panda3D LevelEditor """ 
    def __init__(self):
        #loadPrcFileData('startup', 'window-type none')
        self.currentFile = None
        
        self.fNeedToSave = False    #if there are unsaved changes
        self.actionEvents = []
        #self.objectMgr = ObjectMgr(self)
        self.fileMgr = FileMgr(self)
        self.actionMgr = ActionMgr()
        self.standaloneExporter = StandaloneExporter(self)
        self.saved = False  #if the project has been saved at all

        self.fMoveCamera = False

        self.NPParent = render

        # define your own config file in inherited class
        self.settingsFile = None

        # you can show/hide specific properties by using propertiesMask and this mode
        self.mode = BitMask32()
        
        self.tempDir = None
        
        self.manipMode = 'translate'
        
        groundRay = CollisionNode('groundRay')
        groundRay.addSolid(CollisionRay(Point3(0,0,0), Vec3(0,0,-1)))
        groundRay.setFromCollideMask(BitMask32.allOn())
        self.groundCollide = render.attachNewNode(groundRay)
        self.groundCollideHandler = CollisionHandlerQueue()
        self.groundCollideTraverser = CollisionTraverser()
        self.groundCollideTraverser.addCollider(self.groundCollide, self.groundCollideHandler)
        
        
    
    def initialize(self):
        """ You should call this in your __init__ method of inherited LevelEditor class """
        # specifiy what obj can be 'selected' as objects
        base.direct.selected.addTag('OBJRoot')

        self.actionEvents.extend([
            # Node path events
            ('DIRECT-select', self.select),
            ('DIRECT-delete', self.handleDelete),
            ('DIRECT-preDeselectAll', self.deselectAll),
            ('DIRECT_deselectAll', self.deselectAllCB),
            ('preRemoveNodePath', self.removeNodePathHook),
            ('DIRECT_deselectedNodePath', self.deselectAllCB),
            ('DIRECT_selectedNodePath_fMulti_fTag_fLEPane', self.selectedNodePathHook),
            ('DIRECT_deselectAll', self.deselectAll),
            ('LE-Undo', self.actionMgr.undo),
            ('LE-Redo', self.actionMgr.redo),
            ('LE-Duplicate', self.ui.onDuplicate),
            ('DIRECT_manipulateObjectCleanup', self.cleanUpManipulating),
            #('LE-MakeLive', self.objectMgr.makeSelectedLive),
            ('LE-NewScene', self.ui.onNew),
            ('LE-SaveScene', self.ui.onSave),
            ('LE-OpenScene', self.ui.onOpen),
            ('LE-Import', self.ui.onImport),
            ('LE-Quit', self.ui.quit),
            ('DIRECT-mouse1', self.handleMouse1),
            ('DIRECT-mouse1Up', self.handleMouse1Up),
            ('DIRECT-mouse2', self.handleMouse2),
            ('DIRECT-mouse2Up', self.handleMouse2Up),
            ('DIRECT-mouse3', self.handleMouse3),
            ('DIRECT-mouse3Up', self.handleMouse3Up),
            ('LE-translateMode', self.translateMode),
            ('LE-rotateMode', self.rotateMode),
            ('LE-scaleMode', self.scaleMode),
            ('LE-localMode', self.localMode),
            ('LE-worldMode', self.worldMode),
            ('LE-DropToGround', self.onDropToGround),
            ('LE-lookAtSelected', self.lookAtSelected),
            ('LE-moveCameraToSelected', self.moveCameraToSelected),
            ('LE-moveAllCamerasToSelected', self.moveAllCamerasToSelected),
            ])

        # Add all the action events
        for event in self.actionEvents:
            if len(event) == 3:
                self.accept(event[0], event[1], event[2])
            else:
                self.accept(event[0], event[1])        

        # editor state text display such as edit mode
        self.statusReadout = OnscreenText(
            pos = (-1.2, 0.9), bg=Vec4(1,1,1,1),
            scale = 0.05, align = TextNode.ALeft,
            mayChange = 1, font = TextNode.getDefaultFont())
        self.statusReadout.setText("")
        # Make sure readout is never lit or drawn in wireframe
        useDirectRenderStyle(self.statusReadout)
        self.statusReadout.reparentTo(hidden)
        self.statusLines = []
        taskMgr.doMethodLater(5, self.updateStatusReadoutTimeouts, 'updateStatus')
        taskMgr.add(self.updateShaders, 'updateShaders')

        self.loadSettings()
        self.reset()
        self.newProj()
        
        self.resetWidgets()
        base.direct.manipulationControl.useSeparateScaleHandles = True
        base.direct.cameraControl.switchDirBelowZero = False
        
        #self.defaultColor = BGC_LIGHT_BLUE
        self.setBackgroundColor(BGC_LIGHT_BLUE)
        
        
    
    #opens a new project in the temp directory
    def newProj(self):
        if self.tempDir and os.path.exists(self.tempDir):
            shutil.rmtree(self.tempDir)
        self.tempDir = os.path.join(Util.getTempDir(), 'NewProj')
        if os.path.exists(self.tempDir):
            for root, dirs, files in os.walk(self.tempDir):
                for f in files:
                    file = os.path.join(root, f)
                    fileAtt = os.stat(file)[0]
                    if (not fileAtt & stat.S_IWRITE):
                        os.chmod(file, stat.S_IWRITE)
                    
            shutil.rmtree(self.tempDir)
        
        projFile = Filename.fromOsSpecific(self.tempDir) + '/New Project.proj'
        self.currentProj = Project(projFile, "New Project")
        #defaultSceneName = "default"
        #self.currentProj.addScene(defaultSceneName, 
        #                          Filename(defaultSceneName+'.scene'))#Filename(projFile.getBasenameWoExtension() + '.scene'))
        #current Scene that the objectMgr manages and saves to
        #self.currentScene = self.currentProj.sceneFilename
        self.currentSceneName = self.currentProj.sceneName
        self.ui.scenesUI.populateTreeFromScenes()#add(defaultSceneName)
        self.projDir = self.currentProj.dir
        self.lib = self.currentProj.lib
        self.saved = False
        self.ui.libraryUI.update()
        self.ui.storyObjUI.update()
        self.ui.soundUI.update()
    
    def setTitleWithFilename(self, filename=""):
        title = self.ui.appname
        if filename != "":
           filenameshort = os.path.basename(filename)
           title = title + " (%s)"%filenameshort
        self.ui.SetLabel(title)

    def removeNodePathHook(self, nodePath):
        if nodePath is None:
            return
        base.direct.deselect(nodePath)
        self.objectMgr.removeObjectByNodePath(nodePath)

        if (base.direct.selected.last != None and nodePath.compareTo(base.direct.selected.last)==0):
            # if base.direct.selected.last is refering to this
            # removed obj, clear the reference
            if (hasattr(__builtins__,'last')):
                __builtins__.last = None
            else:
                __builtins__['last'] = None
            base.direct.selected.last = None

    def handleMouse1(self, modifiers):
        if base.direct.fAlt or modifiers == 4:
            self.fMoveCamera = True
            return

    def handleMouse1Up(self):
        self.fMoveCamera = False
        
        base.direct.fAlt = wx.GetKeyState(wx.WXK_ALT)
        base.direct.fControl = wx.GetKeyState(wx.WXK_CONTROL)
        base.direct.fShift = wx.GetKeyState(wx.WXK_SHIFT)

    def handleMouse2(self, modifiers):
        if base.direct.fAlt or modifiers == 4:
            self.fMoveCamera = True
            return

    def handleMouse2Up(self):
        self.fMoveCamera = False
        
        base.direct.fAlt = wx.GetKeyState(wx.WXK_ALT)
        base.direct.fControl = wx.GetKeyState(wx.WXK_CONTROL)
        base.direct.fShift = wx.GetKeyState(wx.WXK_SHIFT)
        
    def handleMouse3(self, modifiers):
        if base.direct.fAlt or modifiers == 4:
            self.fMoveCamera = True
            return

        self.ui.onRightDown()

    def handleMouse3Up(self):
        self.fMoveCamera = False
        
        base.direct.fAlt = wx.GetKeyState(wx.WXK_ALT)
        base.direct.fControl = wx.GetKeyState(wx.WXK_CONTROL)
        base.direct.fShift = wx.GetKeyState(wx.WXK_SHIFT)

    def handleDelete(self):
        oldSelectedNPs = base.direct.selected.getSelectedAsList()
        oldUIDs = []
        for oldNP in oldSelectedNPs:
            obj = self.objectMgr.findObjectByNodePath(oldNP)
            if obj:
                oldUIDs.append(obj.getName())
        action = ActionDeleteObj(self)
        self.actionMgr.push(action)
        action()

##         reply = wx.MessageBox("Do you want to delete selected?", "Delete?",
##                               wx.YES_NO | wx.ICON_QUESTION)
##         if reply == wx.YES:
##             base.direct.removeAllSelected()
##         else:
##             # need to reset COA
##             dnp = base.direct.selected.last
##             # Update camera controls coa to this point
##             # Coa2Camera = Coa2Dnp * Dnp2Camera
##             mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(base.direct.camera)
##             row = mCoa2Camera.getRow(3)
##             coa = Vec3(row[0], row[1], row[2])
##             base.direct.cameraControl.updateCoa(coa)

    def translateMode(self, evt=None):
        self.manipMode = 'translate'
        self.resetWidgets()

        self.ui.translateMenuItem.Check()
        
    def rotateMode(self, evt=None):
        self.manipMode = 'rotate'
        self.resetWidgets()
        
        self.ui.rotateMenuItem.Check()
    
    def scaleMode(self, evt=None):
        self.manipMode = 'scale'
        self.resetWidgets()
        
        self.ui.scaleMenuItem.Check()
    
    def worldMode(self, evt=None):
        base.direct.manipulationControl.switchToWorldSpaceMode()
        self.ui.worldMenuItem.Check()
    
    def localMode(self, evt=None):
        base.direct.manipulationControl.switchToLocalSpaceMode()
        self.ui.localMenuItem.Check()
     
    def showWidget(self):
        for widget in base.direct.manipulationControl.widgetList:
            widget.activate()
    
    def hideWidget(self):
        for widget in base.direct.manipulationControl.widgetList:
            widget.deactivate()
     
    def resetWidgets(self):
        for widget in base.direct.manipulationControl.widgetList:
            widget.disableHandles('all')
            if self.manipMode == 'translate':
                widget.enableHandles('post')
            elif self.manipMode == 'rotate':
                widget.enableHandles('ring')
            elif self.manipMode == 'scale':
                widget.enableHandles('scale')

    #makes the camera look at the center of teh bounding box of whatever is selected
    def lookAtSelected(self):
        selected = base.direct.selected.getSelectedAsList()
        if selected:
            bounds = BoundingBox()
            for np in selected:
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)      
        else:
            bounds = BoundingBox()
            for obj in self.objectMgr.objects.values():
                np = obj.nodePath
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)
        if bounds.isEmpty() or bounds.isInfinite():
            center = Point3(0, 0, 0)
        else:
            center = Point3((bounds.getMax() + bounds.getMin()) / 2.0)
        
        np = NodePath('temp')
        np.setPos(self.ui.perspView.camera.getPos())
        np.lookAt(center)
        i = LerpHprInterval(self.ui.perspView.camera, 1.0, np.getHpr(), blendType='easeInOut')
        i.start()
        base.direct.cameraControl.coaMarkerPos.assign(center)
        np.removeNode()
    
    #moves the camera to the outside of the bounding box of whatever is selected and looks at it
    def moveCameraToSelected(self):
        selected = base.direct.selected.getSelectedAsList()
        if selected:
            bounds = BoundingBox()
            for np in selected:
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)      
        else:
            bounds = BoundingBox()
            for obj in self.objectMgr.objects.values():
                np = obj.nodePath
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)
        
        if bounds.isEmpty() or bounds.isInfinite():
            center = Point3(0, 0, 0)
            targetPos = Point3(-19, -19, 19)
        else:
            center = Point3((bounds.getMax() + bounds.getMin()) / 2.0)
            diff = self.ui.perspView.camera.getPos() - center
            diff.normalize()
            targetPos = center + diff * (bounds.getMax() - bounds.getMin()).length() * 1.8
        
        np = NodePath('temp')
        np.setPos(targetPos)
        np.lookAt(center)
        i = LerpPosHprInterval(self.ui.perspView.camera, 1, targetPos, np.getHpr(), blendType='easeInOut')
        i.start()
        base.direct.cameraControl.coaMarkerPos.assign(center)
        np.removeNode()
    
    #moves all cameras(perspective and the 3 ortho cameras) to focus on the selected object
    def moveAllCamerasToSelected(self):
        selected = base.direct.selected.getSelectedAsList()
        if selected:
            bounds = BoundingBox()
            for np in selected:
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)        
        else:
            bounds = BoundingBox()
            for obj in self.objectMgr.objects.values():
                np = obj.nodePath
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)
        
        #perspective
        if bounds.isEmpty() or bounds.isInfinite():
                center = Point3(0, 0, 0)
                targetPos = Point3(-19, -19, 19)
        else:
            center = Point3((bounds.getMax() + bounds.getMin()) / 2.0)
            diff = self.ui.perspView.camera.getPos() - center
            diff.normalize()
            targetPos = center + diff * (bounds.getMax() - bounds.getMin()).length() * 1.8
        
        np = NodePath('temp')
        np.setPos(targetPos)
        np.lookAt(center)
        i = LerpPosHprInterval(self.ui.perspView.camera, 1, targetPos, np.getHpr(), blendType='easeInOut')
        i.start()
        base.direct.cameraControl.coaMarkerPos.assign(center)
        np.removeNode()
        
        #top
        if bounds.isEmpty() or bounds.isInfinite():
            targetPos = Point3(0, 0, 600)
            base.direct.drList[base.camList.index(NodePath(self.ui.topView.camNode))].orthoFactor = 0.1
            
        else:
            targetPos = Point3((bounds.getMax().getX() + bounds.getMin().getX()) / 2.0, (bounds.getMax().getY() + bounds.getMin().getY()) / 2.0, bounds.getMax().getZ() + 600)
            size = max( (bounds.getMax().getX() - bounds.getMin().getX()), (bounds.getMax().getY() - bounds.getMin().getY()))
            base.direct.drList[base.camList.index(NodePath(self.ui.topView.camNode))].orthoFactor = size / min(self.ui.topView.ClientSize.GetWidth(), self.ui.topView.ClientSize.GetHeight() )
            
        x = self.ui.topView.ClientSize.GetWidth() * base.direct.drList[base.camList.index(NodePath(self.ui.topView.camNode))].orthoFactor
        y = self.ui.topView.ClientSize.GetHeight() * base.direct.drList[base.camList.index(NodePath(self.ui.topView.camNode))].orthoFactor
        i = LerpFunc(self.orthoPosFilmSizeInterval, extraArgs=[self.ui.topView.camera, self.ui.topView.camLens, self.ui.topView.camera.getPos(), targetPos,\
        self.ui.topView.camLens.getFilmSize().getX(), x, self.ui.topView.camLens.getFilmSize().getY(), y], blendType = 'noBlend', duration=1)
        i.start()
        
        #right
        if bounds.isEmpty() or bounds.isInfinite():
            targetPos = Point3(600, 0, 0)
            base.direct.drList[base.camList.index(NodePath(self.ui.leftView.camNode))].orthoFactor = 0.1
            
        else:
            targetPos = Point3(bounds.getMax().getX() + 600, (bounds.getMax().getY() + bounds.getMin().getY()) / 2.0, (bounds.getMax().getZ() + bounds.getMin().getZ()) / 2.0)
            size = max( (bounds.getMax().getY() - bounds.getMin().getY()), (bounds.getMax().getZ() - bounds.getMin().getZ()))
            base.direct.drList[base.camList.index(NodePath(self.ui.leftView.camNode))].orthoFactor = size / min(self.ui.leftView.ClientSize.GetWidth(), self.ui.leftView.ClientSize.GetHeight() )
            
        x = self.ui.leftView.ClientSize.GetWidth() * base.direct.drList[base.camList.index(NodePath(self.ui.leftView.camNode))].orthoFactor
        y = self.ui.leftView.ClientSize.GetHeight() * base.direct.drList[base.camList.index(NodePath(self.ui.leftView.camNode))].orthoFactor
        i = LerpFunc(self.orthoPosFilmSizeInterval, extraArgs=[self.ui.leftView.camera, self.ui.leftView.camLens, self.ui.leftView.camera.getPos(), targetPos,\
        self.ui.leftView.camLens.getFilmSize().getX(), x, self.ui.leftView.camLens.getFilmSize().getY(), y], blendType = 'noBlend', duration=1)
        i.start()
        
        #front
        if bounds.isEmpty() or bounds.isInfinite():
            targetPos = Point3(0, -600, 0)
            base.direct.drList[base.camList.index(NodePath(self.ui.frontView.camNode))].orthoFactor = 0.1
            
        else:
            targetPos = Point3((bounds.getMax().getX() + bounds.getMin().getX()) / 2.0, bounds.getMin().getY() - 600, (bounds.getMax().getZ() + bounds.getMin().getZ()) / 2.0)
            size = max( (bounds.getMax().getX() - bounds.getMin().getX()), (bounds.getMax().getZ() - bounds.getMin().getZ()))
            base.direct.drList[base.camList.index(NodePath(self.ui.frontView.camNode))].orthoFactor = size / min(self.ui.frontView.ClientSize.GetWidth(), self.ui.frontView.ClientSize.GetHeight() )
            
        x = self.ui.frontView.ClientSize.GetWidth() * base.direct.drList[base.camList.index(NodePath(self.ui.frontView.camNode))].orthoFactor
        y = self.ui.frontView.ClientSize.GetHeight() * base.direct.drList[base.camList.index(NodePath(self.ui.frontView.camNode))].orthoFactor
        i = LerpFunc(self.orthoPosFilmSizeInterval, extraArgs=[self.ui.frontView.camera, self.ui.frontView.camLens, self.ui.frontView.camera.getPos(), targetPos,\
        self.ui.frontView.camLens.getFilmSize().getX(), x, self.ui.frontView.camLens.getFilmSize().getY(), y], blendType = 'noBlend', duration=1)
        i.start()
        
            
    def orthoPosFilmSizeInterval(self, t, camera, camLens, beginPos, endPos, beginX, endX, beginY, endY):
        camera.setPos(beginPos * (1-t) + endPos * t)
        camLens.setFilmSize(beginX * (1-t) + endX * t, beginY * (1-t) + endY * t)
        
    def cleanUpManipulating(self, selectedNPs):
        for np in selectedNPs:
            obj = self.objectMgr.findObjectByNodePath(np)
            if obj and np.getMat() != self.objectMgr.objectsLastXform[obj.getName()]:
                action = ActionTransformObj(self, obj.getName(), Mat4(np.getMat()))
                self.actionMgr.push(action)
                action()

    def select(self, nodePath, fMultiSelect=0, fSelectTag=1, fResetAncestry=1, fLEPane=0, fUndo=1):
        base.direct.toggleWidgetVis()
        if fUndo:
            # Select tagged object if present
            if fSelectTag:
                for tag in base.direct.selected.tagList:
                    if nodePath.hasNetTag(tag):
                        nodePath = nodePath.findNetTag(tag)
                        break
            action = ActionSelectObj(self, nodePath, fMultiSelect=fMultiSelect, fSelectTag=fSelectTag, fResetAncestry=fResetAncestry,fLEPane=fLEPane)
            self.actionMgr.push(action)
            action()
        else:
            base.direct.selectCB(nodePath, fMultiSelect, fSelectTag, fResetAncestry, fLEPane, fUndo)
            
        if base.direct.selected.getSelectedAsList:
            self.showWidget()

    def selectedNodePathHook(self, nodePath, fMultiSelect = 0, fSelectTag = 1, fLEPane = 0):
        # handle unpickable nodepath
        if nodePath.getName() in base.direct.iRay.unpickable:
            base.direct.deselect(nodePath)
            return

        if fMultiSelect == 0 and fLEPane == 0:
           oldSelectedNPs = base.direct.selected.getSelectedAsList()
           for oldNP in oldSelectedNPs:
              obj = self.objectMgr.findObjectByNodePath(oldNP)
              if obj:
                 self.ui.sceneGraphUI.deSelect(obj.getName())
        self.objectMgr.selectObject(nodePath, fLEPane, fMultiSelect)
        self.ui.buildContextMenu(nodePath)
        
        
    def deselectAll(self, np=None):
        self.hideWidget()
        self.objectMgr.deselectAll()
        if len(base.direct.selected.getSelectedAsList()) ==0:
            return
        action = ActionDeselectAll(self)
        self.actionMgr.push(action)
        action()

    def deselectAllCB(self, dnp=None):
        if not dnp:
            self.objectMgr.deselectAll()
            self.editor.ui.sceneGraphUI.tree.UnselectAll()
        else:
            obj = self.objectMgr.findObjectByNodePath(dnp)
            if obj:
                self.ui.sceneGraphUI.deSelect(obj.name)
        
    def reset(self, resetViews=True):
        if self.fNeedToSave:
            reply = wx.MessageBox("Do you want to save the current project?", "Save?",
                               wx.YES_NO | wx.ICON_QUESTION)
            if reply == wx.YES:
                result = self.ui.onSave()
                if result == False:
                    return

        base.direct.deselectAll()
        self.ui.reset()
        self.objectMgr.reset()
        self.actionMgr.reset()
        self.soundMgr.reset()
        self.journalMgr.reset()
        self.inventoryMgr.reset()
        if resetViews:
            self.ui.perspView.camera.setPos(-19, -19, 19)
            self.ui.perspView.camera.lookAt(Point3(0, 0, 0))
            self.ui.leftView.camera.setPos(600, 0, 0)
            self.ui.frontView.camera.setPos(0, -600, 0)
            self.ui.topView.camera.setPos(0, 0, 600)
            self.resetOrthoCam(self.ui.topView)
            self.resetOrthoCam(self.ui.frontView)
            self.resetOrthoCam(self.ui.leftView)
        self.fNeedToSave = False
        self.setTitleWithFilename()
    
    def resetScene(self):
        if self.fNeedToSave:
            reply = wx.MessageBox("With Switching Scenes you will lose the previous Scene.\n Do you want to save the current project?", "Save?",
                               wx.YES_NO | wx.ICON_QUESTION)
            if reply == wx.YES:
                result = self.ui.onSave()
                if result == False:
                    return
        base.direct.deselectAll()
        self.objectMgr.reset()
        self.actionMgr.reset()
        self.soundMgr.reset()# May not reset this
        self.fNeedToSave = False
        self.setTitleWithFilename()
        
        
        
    def resetOrthoCam(self, view):
        base.direct.drList[base.camList.index(NodePath(view.camNode))].orthoFactor = 0.1
        x = view.ClientSize.GetWidth() * 0.1
        y = view.ClientSize.GetHeight() * 0.1
        view.camLens.setFilmSize(x, y)
        
    def save(self):
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        #check to make sure everything is writable
        try:
            f = open(self.currentProj.filename.toOsSpecific(), 'a')
            f.close()
        except IOError as e:
            dlg = wx.MessageDialog(self.ui, "The project file " +\
            " could not be written.  Make sure it is not marked read-only and try again",\
            caption = "Save Error", style=wx.ICON_ERROR|wx.OK)
            dlg.ShowModal()
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            return
            
        try:
            f = open((self.projDir + '/' + self.currentProj.getScene(self.currentSceneName).getFullpath()).toOsSpecific(), 'a')
            f.close()
        except IOError as e:
            dlg = wx.MessageDialog(self.ui, "The scene file "  +\
            " could not be written.  Make sure it is not marked read-only and try again",\
            caption = "Save Error", style=wx.ICON_ERROR|wx.OK)
            dlg.ShowModal()
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            return
            
        try:
            f = open((self.projDir + '/' + 'lib.index').toOsSpecific(), 'a')
            f.close()
        except IOError as e:
            dlg = wx.MessageDialog(self.ui, "The library index file " +\
            " could not be written.  Make sure it is not marked read-only and try again",\
            caption = "Save Error", style=wx.ICON_ERROR|wx.OK)
            dlg.ShowModal()
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            return
        
        try:
            f = open((self.projDir + '/' +  self.currentProj.journalFilename.getFullpath()).toOsSpecific(), 'a')
            f.close()
        except IOError as e:
            dlg = wx.MessageDialog(self.ui, "The journal file " +\
            " could not be written.  Make sure it is not marked read-only and try again",\
            caption = "Save Error", style=wx.ICON_ERROR|wx.OK)
            dlg.ShowModal()
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            return
        
        self.currentProj.saveToFile()
        self.fileMgr.saveToFile(self.projDir + '/' + self.currentProj.getScene(self.currentSceneName).getFullpath())
        self.fileMgr.saveJournalToFile(self.projDir+'/'+self.currentProj.journalFilename.getFullpath())
        self.fileMgr.saveInventoryMapToFile(self.projDir+'/'+self.currentProj.inventoryMapFilename.getFullpath())
        self.lib.saveToFile()
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))

    def saveAs(self, fileName, projName):
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        self.currentProj.saveAs(fileName, projName, self.saved)
        self.tempDir = None
        self.projDir = self.currentProj.dir
        self.fileMgr.saveToFile(self.projDir + '/' + self.currentProj.getScene(self.currentSceneName).getFullpath())
        self.fileMgr.saveJournalToFile(self.projDir+'/'+self.currentProj.journalFilename.getFullpath())
        self.fileMgr.saveInventoryMapToFile(self.projDir+'/'+self.currentProj.inventoryMapFilename.getFullpath())
        self.saved = True
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
        
#    def createSceneFile(self,sceneFile):
#        try:
#            f = open((self.projDir + '/' + sceneFile.getFullpath()).toOsSpecific(), 'a')
#            f.close()
#        except IOError as e:
#            dlg = wx.MessageDialog(self.ui, "The scene file "  +\
#            " could not be written.  Make sure it is not marked read-only and try again",\
#            caption = "Save Error", style=wx.ICON_ERROR|wx.OK)
#            dlg.ShowModal()
#            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
#            return

    def load(self, fileName, resetViews=True, setSaved=True):
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        self.reset(resetViews=resetViews)
        self.currentProj = Project(fileName)
        self.projDir = self.currentProj.dir
        self.lib = self.currentProj.lib
        
        #make sure we get updated versions of assets
        ModelPool.releaseAllModels()
        TexturePool.releaseAllTextures()
        ShaderPool.releaseAllShaders()
        
        self.currentSceneName = self.currentProj.sceneName
        self.fileMgr.loadFromFile(self.projDir + '/' +self.currentProj.getScene(self.currentSceneName).getFullpath())
        self.fileMgr.loadJournalFromFile(self.projDir+'/'+self.currentProj.journalFilename.getFullpath())
        self.fileMgr.loadInventoryMapFromFile(self.projDir+'/'+self.currentProj.inventoryMapFilename.getFullpath())
        if setSaved:
            self.saved = True
        
        #self.currenScene = self.currentProj.sceneFilename
        self.ui.scenesUI.populateTreeFromScenes()
        
        self.objectMgr.updateMainCharWidget() #[antonjs 4/14/11]
        
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))

    #Cosider to change merging projects: Maybe just merging scenes?
    def mergeProject(self, fileName, prefix='', newNodeName= ''):
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        otherProj = Project(fileName)
        if not prefix:
            prefix = otherProj.name
        try:
            self.lib.checkLibrary(otherProj.lib, prefix)
        except Exception as e:
            print 'ERROR:Could not merge libraries'
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            raise e
            return
            
        self.lib.mergeWith(otherProj.lib, prefix, saveAfter=True)
        try:
            self.fileMgr.loadFromFile(otherProj.dir + '/' + otherProj.scenes[otherProj.sceneName].getFullpath(), merge=True, lib=otherProj.lib, otherName=prefix, newNodeName= newNodeName)
        except Util.SceneMergeError as e:
            print 'ERROR:could not merge scenes'
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            traceback.print_exc(file=sys.stdout)
            return
        
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
        self.ui.libraryUI.update()
        self.ui.storyObjUI.update()
        self.ui.soundUI.update()
        self.objectMgr.updateMainCharWidget() #[antonjs 4/14/11]
        
        self.fNeedToSave = True
        
    def saveSettings(self):
        if self.settingsFile is None:
            return
        
        try:
            f = open(self.settingsFile, 'w')
            f.write('gridSize\n%f\n'%self.ui.perspView.grid.gridSize)
            f.write('gridSpacing\n%f\n'%self.ui.perspView.grid.gridSpacing)
            f.write('hotKey\n%s\n'%base.direct.hotKeyMap)
            f.close()
        except:
            pass        

    def loadSettings(self):
        base.direct.hotKeyMap = {   
            'control-y': ('Redo', 'LE-Redo'),
            'shift-v': ('Toggle Marker', 'DIRECT-toggleMarkerVis'),
            'control-n': ('New Scene', 'LE-NewScene'),
            'control-s': ('Save Scene', 'LE-SaveScene'),
            'escape': ('Deselect All', 'deselectAll'),
            'control-z': ('Undo', 'LE-Undo'),
            ',': ('Scale Down Widget', 'DIRECT-widgetScaleDown'),
            '.': ('Scale Up Widget', 'DIRECT-widgetScaleUp'),
            'control-o': ('Open Scene', 'LE-OpenScene'),
            'control-q': ('Quit', 'LE-Quit'),
            'control-i': ('Import', 'LE-Import'),
            # 'b': ('Toggle Backface', 'DIRECT-toggleBackface'),
            #'f': ('Fit on Widget', 'DIRECT-fitOnWidget'),
            # 't': ('Toggle Textures', 'DIRECT-toggleTexture'),
            't': ('Toggle Wireframe', 'DIRECT-toggleWireframe'),
            'f' : ('Look at Selected', 'LE-lookAtSelected'),
            'c' : ('Move Camera to Selected', 'LE-moveCameraToSelected'),
            'shift-c' : ('Move All Cameras to Selected', 'LE-moveAllCamerasToSelected'),
            'w': ('Enter Translate Mode', 'LE-translateMode'),
            'e': ('Enter Rotate Mode', 'LE-rotateMode'),
            'r': ('Enter Scale Mode', 'LE-scaleMode'),
            'delete': ('Delete', 'DIRECT-delete'),
            'control-g': ('Drop Selected to Ground', 'LE-DropToGround'),
            'control-d': ('Duplicate', 'LE-Duplicate')}
        
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        try:
            f = open(self.settingsFile, 'r')
            configLines = f.readlines()
            f.close()

            gridSize = 100.0
            gridSpacing = 5.0
            for i in range(0, len(configLines)):
                line = configLines[i]
                i = i + 1
                if line.startswith('gridSize'):
                    gridSize = float(configLines[i])
                elif line.startswith('gridSpacing'):
                    gridSpacing = float(configLines[i])
                elif line.startswith('hotKey'):
                    customHotKeyMap = eval(configLines[i])
                    customHotKeyDict = {}
                    for hotKey in customHotKeyMap.keys():
                        desc = customHotKeyMap[hotKey]
                        customHotKeyDict[desc[1]] = hotKey

                    overriddenKeys = []
                    for key in base.direct.hotKeyMap.keys():
                        desc = base.direct.hotKeyMap[key]
                        if desc[1] in customHotKeyDict.keys():
                            overriddenKeys.append(key)

                    for key in overriddenKeys:
                        del base.direct.hotKeyMap[key]
                            
                    base.direct.hotKeyMap.update(customHotKeyMap)

            self.ui.updateGrids(gridSize, gridSpacing)
            self.ui.updateMenu()
        except:
            base.direct.hotKeyMap = {   
            'control-y': ('Redo', 'LE-Redo'),
            'shift-v': ('Toggle Marker', 'DIRECT-toggleMarkerVis'),
            'control-n': ('New Scene', 'LE-NewScene'),
            'control-s': ('Save Scene', 'LE-SaveScene'),
            'escape': ('Deselect All', 'deselectAll'),
            'control-z': ('Undo', 'LE-Undo'),
            ',': ('Scale Down Widget', 'DIRECT-widgetScaleDown'),
            '.': ('Scale Up Widget', 'DIRECT-widgetScaleUp'),
            'control-o': ('Open Scene', 'LE-OpenScene'),
            'control-q': ('Quit', 'LE-Quit'),
            'control-i': ('Import', 'LE-Import'),
            # 'b': ('Toggle Backface', 'DIRECT-toggleBackface'),
            #'f': ('Fit on Widget', 'DIRECT-fitOnWidget'),
            # 't': ('Toggle Textures', 'DIRECT-toggleTexture'),
            't': ('Toggle Wireframe', 'DIRECT-toggleWireframe'),
            'f' : ('Look at Selected', 'LE-lookAtSelected'),
            'c' : ('Move Camera to Selected', 'LE-moveCameraToSelected'),
            'shift-c' : ('Move All Cameras to Selected', 'LE-moveAllCamerasToSelected'),
            'w': ('Enter Translate Mode', 'LE-translateMode'),
            'e': ('Enter Rotate Mode', 'LE-rotateMode'),
            'r': ('Enter Scale Mode', 'LE-scaleMode'),
            'g': ('Switch to World Space Manipulation', 'LE-worldMode'),
            'l': ('Switch to Local Space Manipulation', 'LE-localMode'),
            'delete': ('Delete', 'DIRECT-delete'),
            'control-g': ('Drop Selected to Ground', 'LE-DropToGround'),
            'control-d': ('Duplicate', 'LE-Duplicate')}
            self.ui.updateMenu()
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))

    def convertMaya(self, modelname, callBack, obj=None, isAnim=False):
        if obj and isAnim:
            mayaConverter = MayaConverter(self.ui, self, modelname, callBack, obj, isAnim)
        else:
            reply = wx.MessageBox("Is it an animation file?", "Animation?",
                              wx.YES_NO | wx.ICON_QUESTION)
            if reply == wx.YES:
                mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, True)
            else:        
                mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, False)
        mayaConverter.Show()

    def convertFromMaya(self, modelname, callBack):
        mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, False)
        mayaConverter.Show()

    def updateStatusReadout(self, status, color=None):
        if status:
            # add new status line, first check to see if it already exists
            alreadyExists = False
            for currLine in self.statusLines:
                if (status == currLine[1]):
                    alreadyExists = True
                    break
            if (alreadyExists == False):
                time = globalClock.getRealTime() + 15
                self.statusLines.append([time,status,color])

        # update display of new status lines
        self.statusReadout.reparentTo(aspect2d)
        statusText = ""
        lastColor = None
        for currLine in self.statusLines:
            statusText += currLine[1] + '\n'
            lastColor = currLine[2]
        self.statusReadout.setText(statusText)
        if (lastColor):
            self.statusReadout.textNode.setCardColor(
                lastColor[0], lastColor[1], lastColor[2], lastColor[3])
            self.statusReadout.textNode.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
        else:
            self.statusReadout.textNode.setCardColor(1,1,1,1)
            self.statusReadout.textNode.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
            
    def updateStatusReadoutTimeouts(self,task=None):
        removalList = []
        for currLine in self.statusLines:
            if (globalClock.getRealTime() >= currLine[0]):
                removalList.append(currLine)
        for currRemoval in removalList:
            self.statusLines.remove(currRemoval)
        self.updateStatusReadout(None)
        # perform doMethodLater again after delay
        # This crashes when CTRL-C'ing, so this is a cheap hack.
        #return 2
        from direct.task import Task
        return Task.again

    def updateShaders(self, task):
        for obj in self.objectMgr.objects.values():
            if obj.shader and obj.shaderActive:
                obj.shader.update()
        return task.cont
        
    def propMeetsReq(self, typeName, parentNP):
        parentNP[0] = None
        return True
    
    def onDropToGround(self, evt=None):
        action = ActionDropSelectedToGround(self)
        self.actionMgr.push(action)
        action()
    
    def dropSelectedToGround(self):
        selected = base.direct.selected.getSelectedAsList()
        toDrop = set(selected)
        
        origParents = {}
        
        for np in toDrop:
            for otherNP in toDrop:
                if np != otherNP and otherNP.isAncestorOf(np):
                    origParents[np] = np.getParent()
                    np.wrtReparentTo(render)
                    break

        for np in toDrop:
            self.dropToGround(np)
                    
        for np, parent in origParents.iteritems():
            np.wrtReparentTo(parent)
            
    def dropToGround(self, np):
        self.groundCollide.setPos(np.getPos(render))
        
        self.groundCollideTraverser.traverse(render)
        
        if self.groundCollideHandler.getNumEntries() > 0:
            self.groundCollideHandler.sortEntries()
            for e in self.groundCollideHandler.getEntries():
                hitNP = e.getIntoNodePath()
                if hitNP.hasNetTag('OBJRoot'):
                    hitObj = hitNP.findNetTag('OBJRoot')
                    if hitObj.hasTag('LE-ground'):
                        np.setZ(render, e.getSurfacePoint(render).getZ())
                        return
    
        
                    
    def openScene(self, sceneName):
        self.ui.sceneGraphUI.reset()
        self.ui.soundUI.reset()
        sceneFile = self.currentProj.getScene(sceneName)
        #self.currentScene = sceneFile
        
        if(sceneName.strip().startswith("interior_")):
            self.setBackgroundColor(BGC_DARK_GREY)
        else:
            self.setBackgroundColor(BGC_LIGHT_BLUE)
        
        self.currentSceneName = sceneName
        f = Filename(sceneFile)
        f.setDirname(self.currentProj.dir.getFullpath())

        if os.path.exists(f.toOsSpecific()):
            self.fileMgr.loadFromFile(self.projDir + '/' +self.currentProj.getScene(self.currentSceneName).getFullpath())
        
        self.objectMgr.updateMainCharWidget() #[antonjs 4/14/11]
    
    def addScene(self):
        name, scenefile = self.currentProj.addScene()
        #create an empty sceneFile
        #cr
        doc = xml.dom.minidom.Document()
        root = doc.createElement("scene")
        doc.appendChild(root)
        root.appendChild(doc.createElement("objects"))
        root.appendChild(doc.createElement("layers"))
        root.appendChild(doc.createElement("sounds"))
        
        try:
            filename = self.projDir + '/' + scenefile.getFullpath()
            f = open(filename.toOsSpecific(), 'w')
            f.write(doc.toprettyxml())
            f.close()
        except IOError:
            raise SceneSaveError(filename.toOsSpecific())
        return name
        
    
    def removeScene(self, sceneName, delFile = False):
        toDelSceneFile = self.currentProj.getScene(sceneName)
        self.currentProj.removeScene(sceneName, delFile)
        #if the scene to remove the current Scene get the 
        if(self.currentSceneName == sceneName):
            self.openScene(self.currentProj.sceneName)
        #self.ui.onSave()
        #self.currentScene = self.currentProj.getOpeningScene()
        
        if(self.saved):
            self.save()
            
    def renameScene(self, name, newName):
        self.currentProj.renameScene(name,newName)
        if(self.currentSceneName == name):
            self.currentSceneName = newName
            if(newName.strip().startswith("interior_")):
                self.setBackgroundColor(BGC_DARK_GREY)
            else:
                self.setBackgroundColor(BGC_LIGHT_BLUE)
            
    def addEmptyTerrain(self):
        no = 0
        name =  self.currentSceneName+'_terrain'+str(no)
        tempFilePath = base.le.lib.projDir.toOsSpecific() + '/' + name+ '.png'
        assetFilename = Filename(tempFilePath)
        
        targetFilename = Filename(assetFilename)
        targetFilename.setDirname(self.currentProj.dir.getFullpath()+'/Textures')
        
        while os.path.exists(targetFilename.toOsSpecific()):
            no += 1
            tempFilePath = base.le.lib.projDir.toOsSpecific() + '/' + name+str(no)+ '.png'
            assetFilename = Filename(tempFilePath)
            targetFilename = Filename(assetFilename)
            targetFilename.setDirname(self.currentProj.dir.getFullpath()+'/Textures')
            
        
        tempImage = PNMImage(513,513)
        tempImage.fill(.5,.5,.5)
        tempImage.write(assetFilename)  
        
        no = 0
        #add the new terrain to the library
        asset = Terrain(name, assetFilename)
        while(1):
            try:
                base.le.lib.addTerrain(asset, True)
                break
            except:
                pass
                no += 1
                name =  self.currentSceneName+'_terrain'+str(no)
                #tempFilePath = base.le.lib.projDir.toOsSpecific() + '/' + name+ '.png'
                #assetFilename = Filename(tempFilePath)
                asset = Terrain(name, assetFilename)
            else:
                break
                        
        base.le.ui.libraryUI.update()
            
        #== Remove the temporary source file
        tempFilename = Filename(tempFilePath)
        #print 'temporary file path to now delete: ' + tempFilename.toOsSpecific()
        os.remove(tempFilename.toOsSpecific())
        
        pos = Vec3(512*(-.5), 512*(-.5), -128)            
        action = ActionAddNewObj(self, "Terrains", name = "terrain_"+name + ':1', asset=asset, anims={}, parent=None, pos=pos)
        self.actionMgr.push(action)
        newobj = action()
        newobj.getNodePath().setScale(1.,1.,255)
    
    #Color should a Vec4
    def setBackgroundColor(self, color):
        for i in range(4):
            base.winList[i].setClearColor(color)
class TerrainPaintUI(wx.Dialog):
    def __init__(self, parent, editor, terrain):
        pre = wx.PreDialog()
        self.res = xrc.XmlResource(GUI_FILENAME)
        self.res.LoadOnDialog(pre, parent, 'dlgTerrainPaint')
        self.PostCreate(pre)
        self.Bind(wx.EVT_INIT_DIALOG, self.onCreate)
        
        self.parent = parent
        self.editor = editor
        self.terrain = terrain
        #self.oldCanvas = PNMImgae()
        #self.oldCanvas.copyFrom(terrain.heightField())
        self.brushRadius = 1
        self.viewport = None
        
        self.oldX = -1
        self.oldY = -1
        
        self.paintCursor = loader.loadModel("models/terrain_cursor.egg")#jack")
        self.paintRing = loader.loadModel("models/terrain_ring.egg")
        self.paintCursor.setScale(12)
        self.paintCursor.reparentTo(self.editor.NPParent)
        self.paintCursor.setPos(self.terrain.getNodePath().getPos())
        self.paintRing.reparentTo(self.editor.NPParent)
        self.paintRing.setPos(self.paintCursor.getPos())
        
        taskMgr.add(self.followMouseTask, "followMouseTask")
        self.customImage = PNMImage(32,32)
        self.customImage.read("full_white_square_gradiant_alpha.tif")
        self.raiseImageWithCustomImage()
        
        #TO DO:if no light check for later
        light = PointLight('Terrain Light')
        light.setColor(Vec4(1,1,1,1))
        self.light = self.editor.NPParent.attachNewNode(light)
        pos = self.terrain.getNodePath().getPos()
        self.light.setPos(Point3(0,0,pos[2]+240))
        self.terrain.getNodePath().setLight(self.light)#self.editor.NPParent.setLight(self.light)
        #self.editor.NPParent.setPoint(Point3(0,0, pos[2]+400))
        
        self.actionMgr = ActionMgr()
    
    def onCreate(self, evt):
        self.Unbind(wx.EVT_INIT_DIALOG)
        base.le.ui.bindKeyEvents(False)
        
        self.Show()
        self.Bind(wx.EVT_CLOSE, self.Close)
        
        #init all the panels from XRC for parenting later on
        self.notebook = xrc.XRCCTRL(self, "notebook_1")
        self.canvasPanel = xrc.XRCCTRL(self, "canvasPanel")
        self.texturePanel = xrc.XRCCTRL(self,"texturePanel")
        #self.setupWxPaint()
        
        #self.canvasPanel.Bind(wx.EVT_PAINT, self.onPaint)
        #self.canvasPanel.Bind(wx.EVT_LEFT_DOWN, self.onClick)
        
        
        #edit Panel
        self.btnUpdateTerrain =  xrc.XRCCTRL(self,"btnUpdateTerrain")
        self.sliderBrushSize = xrc.XRCCTRL(self, "sliderBrushSize")
        self.textCtrlBrushSize = xrc.XRCCTRL(self, "textCtrlBrushSize")
        self.sliderGrayScale = xrc.XRCCTRL(self, "sliderGrayScale")
        self.textCtrlGrayScale = xrc.XRCCTRL(self, "textCtrlGrayScale")
        self.paintModeRadioBox = xrc.XRCCTRL(self, 'paintModeRadioBox')
        self.paintModeRadioBox.Hide()
        
        self.Bind(wx.EVT_BUTTON, self.saveTerrain, self.btnUpdateTerrain)
        self.sliderGrayScale.Bind(wx.EVT_SCROLL_ENDSCROLL, self.onSliderEnd)
        self.sliderBrushSize.Bind(wx.EVT_SCROLL_ENDSCROLL, self.onSliderEnd)
        #self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.onPageChange)
        
        
        self.setupViewport(self.canvasPanel)
        #self.setupTextureViewport()
        self.setupCanvas()
        #self.canvasPanel.CaptureMouse()

    #TODEL
    def onPageChange(self, evt):
        #0 is heightmap
        #1 is texture
        selected = self.notebook.GetSelection()
        if(self.viewport):
            self.viewport.Close()
        if(selected == 0):
            self.setupViewport(self.canvasPanel)
        else:
            self.setupViewport(self.texturePanel)
            
    
    def followMouseTask(self, task):
        panel_pos = self.canvasPanel.ScreenToClient(wx.GetMousePosition())
        if(self.isInBound(panel_pos.x,panel_pos.y)==False):
            return task.cont
        
        z = self.canvas.getBlueVal(panel_pos.x,panel_pos.y)
        #print "Blue: ", z
        
        z2 = self.canvas.getGrayVal(panel_pos.x,panel_pos.y)
        #print "Gray: ", z2
        
        if z < 128:
            z = 128
        #print "Mouse pos: ", Point3(panel_pos.x, math.fabs(panel_pos.y-512), z)
        mousePos = self.terrain.getNodePath().getPos() + Point3(panel_pos.x, math.fabs(panel_pos.y-512), z+1)
        self.paintCursor.setPos(mousePos)
        self.paintRing.setPos(mousePos)
        self.paintRing.setZ(30)
        return task.cont
        
        
        
        
        
    def setupWxPaint(self):
        self.bitmap = wx.Bitmap("bitmap")
        #self.canvasPanel.AddChild(self.bitmap)
        Debug.debug(__name__,str( self.terrain.asset.getFullFilename().getExtension()))
        self.bitmap.LoadFile(self.terrain.asset.getFullFilename().toOsSpecific(),wx.BITMAP_TYPE_ANY)
        #self.static = wx.StaticBitmap(self.canvasPanel,size = wx.Size(513,513), style = wx.EXPAND )
        #self.static.SetBitmap(self.bitmap)
        #dc =wx.ClientDC(self)
        #dc.DrawBitmap(self.bitmap, 0, 0)
    
    def onClick(self,evt):
        self.canvasPanel.Bind(wx.EVT_PAINT, self.onPaint)
        panel_pos = self.canvasPanel.ScreenToClient(wx.GetMousePosition())
        # draw a blue line (thickness = 4)
        self.dc.DrawCircle(panel_pos.x, panel_pos.y,10)
        
        
        
    def onPaint(self, evt):
        self.dc =wx.PaintDC(self.canvasPanel)
        self.dc.DrawBitmap(self.bitmap, 0, 0)
        self.dc.SetPen(wx.Pen('blue', 4))
        self.dc.SetBrush(wx.Brush('blue',wx.SOLID))

        #dc.DrawLine(50, 20, 300, 20)
        #dc.SetPen(wx.Pen('red', 1))
        # draw a red rounded-rectangle
        #rect = wx.Rect(50, 50, 100, 100) 
        #dc.DrawRoundedRectangleRect(rect, 8)
        # draw a red circle with yellow fill
        #dc.SetBrush(wx.Brush('yellow'))
        #x = 250
        #y = 100
        #r = 50
        #dc.DrawCircle(x, y, r)
          
        pass
          
        
    def setupViewport(self, panel):
        self.terrainScene = NodePath(PandaNode("TerrainPaintScene"))      
        self.terrain2d = NodePath(PandaNode("TerrainPaint2d"))
        self.terrain2dScaled =self.terrain2d.attachNewNode(PandaNode("terrain2dScaled"))
        
        base.direct.manipulationControl.disableManipulation()

           
        self.viewport = TerrainView('persp', panel)
        self.viewport.SetClientSize((513,513))
        self.viewport.Update()
        base.le.ui.wxStep()
        self.viewport.initialize()

        #apply a mask to make sure GUI stuff from the main window doesn't show up here
        self.viewport.cam2d.node().setCameraMask(LE_IMPORT_MASK)    
        self.viewport.camera.reparentTo(self.terrainScene)
        self.viewport.camera.setPos(0,-20,0)
        self.viewport.camera.lookAt(0,0,0)
        self.viewport.cam2d.reparentTo(self.terrain2d)
        
        
        
        self.viewport.accept("mouse1", self.startPaint)
        self.viewport.accept("mouse1-up", self.stopPaint)
        self.viewport.accept('z',self.actionMgr.undo)
        self.viewport.accept('y', self.actionMgr.redo)
        
        
    def setupCanvas(self):
        self.temp = loader.loadModel("jack")
        #self.temp.reparentTo(self.terrain2d)
        #self.viewport.camera.lookAt(self.temp)
        self.canvas = PNMImage(513,513)
                
#        if(self.terrain.terrain.hasColorMap()==False):
#            self.canvas.fill(1,1,1)
#            self.canvas.makeRgb()
#            print self.canvas.getNumChannels()
#            self.terrain.terrain.setColorMap(self.canvas)
#        else:
        self.canvas = self.terrain.terrain.heightfield()#self.canvas.read(Filename(self.terrain.asset.getFullFilename()))
        if(self.canvas.hasAlpha()):
            Debug.debug(__name__,"In canvas there is alpha")
        self.canvas.addAlpha()
        for i in range(0,self.canvas.getReadXSize()):
            for j in range(0, self.canvas.getReadYSize()):
                self.canvas.setAlpha(i,j,.5)
        sizeX =  self.canvas.getReadXSize()
        sizeY =  self.canvas.getReadYSize()
        #self.canvas.makeGrayscale()
        Debug.debug(__name__, str(sizeX)+" "+str(sizeY))
        self.tex = Texture()
        self.tex.load(self.canvas)
        #self.tex.reparentTo(self.terrain2d)
        CM=CardMaker('') 
        CM.setFrameFullscreenQuad()
        self.card=self.terrain2d.attachNewNode(CM.generate()) 
        self.card.setTexture(self.tex) 
        
        self.viewport.SetClientSize((sizeX, sizeY))
        self.canvasPanel.SetSize(wx.Size(sizeX, sizeY))
        self.viewport.Update()
        base.le.ui.wxStep()
        
        self.painter = PNMPainter(self.canvas)
        brush = PNMBrush.makeSpot((1,1,1,1),5.0,True )
        self.painter.setPen(brush)
        #print terrain2d
        #self.canvas.reparentTo(self.terrain2d)
        
        #panel_pos = self.canvasPanel.ScreenToClient(wx.GetMousePosition())
        #print self.viewport.bt.getParent().getMouseX() 
    
    def onSliderEnd(self,evt):
        size = self.sliderBrushSize.GetValue()
        self.brushRadius = size
        grayScale = self.sliderGrayScale.GetValue()
        self.setBrush(size,grayScale)
    
    
    def setBrush(self, size, grayScale):             
        scale = grayScale/255.0
        brush = PNMBrush.makeSpot((scale,scale,scale,1.0),size,True, effect=(PNMBrush.BEBlend)  )
        self.paintRing.setScale(size)
        #brush = PNMBrush.makeImage("75%.tif",16,16)
        self.painter.setPen(brush)
        self.painter.setFill(brush)
        
        pass
    # x and y position of the draw point
    def paintSpot(self,x,y,radius,higher = True, step = 1):
        topX = x-radius
        topY = y - radius
        bottomX = x+radius
        bottomY = y+radius
        if(self.isInBound(x,y)==False):
           return
        baseVal = self.canvas.getGrayVal(x,y)
        #print "baseVal ",baseVal
        baseRGB = self.canvas.getXel(x,y)
        #print "baseRGB ",baseRGB
        for i in range(topX,bottomX):
            for j in range(topY,bottomY):
                if(self.isInBound(i,j)==False):
                    continue
                #print "=========="
                #print i, " ", j
                sum = math.fabs(i-x)+math.fabs(j-y)
                strength = radius-sum
                if(sum<=radius):
                    val = self.canvas.getGrayVal(i, j)#get the current Color
                    #raise it or lower it.
                    if(higher):
                        newVal = self.roundGrayScale(val+strength)
                    else:
                        newVal = self.roundGrayScale(val-stength)
                    
                    #newVal = Vec3(newVal,newVal,newVal)
                    newVal /= 255.0
                    self.canvas.setXel(i,j, newVal, newVal,newVal)
                    
                   
        
        
    def roundGrayScale(self, val, min=0, max=255):
        if val < 0 :    return 0
        elif val > 255: return 255
        else:             return val 
    def isInBound(self, x,y):
        a = x
        b = y
        xMax = self.canvas.getReadXSize()-1
        yMax = self.canvas.getReadYSize()-1
        if(a<0):
            return False
        elif(a>xMax):
            return False
        if(b<0):
            return False
        elif(b>yMax):
            return False
        
        return True
            
        
        
    def roundCoord(self, x, y):
        a = x
        b = y
        xMax = self.canvas.getReadXSize()
        yMax = self.canvas.getReadYSize()
        if(a<0):
            a = 0
        elif(a>xMax):
            a = xMax
        if(b<0):
            b = 0
        elif(b>yMax):
            b = yMax
            
        return (a,b)
            
    
    def updateImage(self):
        #sizeX =  self.canvas.getReadXSize()
        #sizeY =  self.canvas.getReadYSize()
        #self.tex = Texture()
        self.tex.load(self.canvas)
        self.card.clearTexture()
        self.card.setTexture(self.tex)
        #self.canvas.alphaFill(0)
        
    def resetTerrain(self, event = None):
        print "Terrain is Saved"
        file = Filename("temp.jpeg")
        file.setDirname(self.editor.currentProj.dir.getFullpath()+'/Textures')
        status = self.canvas.write(file)
        #print "Status: ",status
                 
        #self.canvas.fill(.5,.5,.5)
        #self.updateTerrain()
        #self.updateImage()
    def saveTerrain(self, event = None):
        #print type(self.terrain.asset)
        #print self.terrain.asset.getFullFilename().toOsSpecific()
        file = self.terrain.asset.getFullFilename().toOsSpecific()
        status = self.canvas.write(file)
        
        
        thumbnailFile = self.terrain.asset.getThumbnail()#.getFullpath()
        #thumbnailPath = Filename('Thumbnails/' + texture.filename.getBasename())
#        print thumbnailFile
        cwd = os.getcwd()
        os.chdir((self.editor.projDir + '/Textures/').toOsSpecific())
        #os.remove(thumbnailFile.toOsSpecific())
        subprocess.call(["image-resize","-x 60", "-y 60", "-g 1", "-o" +thumbnailFile.toOsSpecific(),self.terrain.asset.filename.getBasename()])
        #self.terrain.asset.thumbnail = thumbnailFile
        
        os.chdir(cwd)
        print "Terrain is Saved"
        
        self.editor.ui.libraryUI.update()
        
    
    def updateTerrain(self, event=None):
        #self.terrain.terrain.setHeightfield(self.canvas)
        #self.paintCursor.detachNode()#reparentTo(self.terrain.getNodePath())
        #self.terrain.terrain.setTexture(self.canvas)
        self.terrain.update()
        self.terrain.generate()
        x = self.terrain.getScale()[0]
        y = self.terrain.getScale()[1]
        z = 255.0
        self.terrain.setScale(Vec3(x, y, z))
    
    def mouse(self, event=None):
        pos = event.GetPosition()
        #print pos
        #print "HEREREREREER"
    
    def startPaint(self):
        panel_pos = self.canvasPanel.ScreenToClient(wx.GetMousePosition())
        #print panel_pos.x, " ", panel_pos.y
        x = self.canvas.getReadXSize
        y = self.canvas.getReadYSize
        if(panel_pos.x > x or panel_pos.x < 0):
            return
        if(panel_pos.y > y or panel_pos.y < 0):
            return
        
        self.drawAction = ActionDraw(self.editor, self)
        taskMgr.add(self.OnMove, "paintTask")
    
    def stopPaint(self):
        if(taskMgr.hasTaskNamed("paintTask") == False):
            return
        taskMgr.remove("paintTask")
        self.actionMgr.push(self.drawAction)
        self.drawAction()
        self.updateTerrain()

    
    
    def paintTask(self, task):
        pass
        
        
    def OnMove(self, task=None):
        curchoice = self.paintModeRadioBox.GetSelection()
        panel_pos = self.canvasPanel.ScreenToClient(wx.GetMousePosition())
        #if(self.oldX == panel_pos.x and self.oldY == panel_pos.y):
        #    return
        if(curchoice == 0):
            self.painter.drawPoint(panel_pos.x,panel_pos.y)
        #self.canvas.renderSpot(VBase4D(.5,.5,.5,1),VBase4D(.5,.5,.5,1),.00001,.00003)
        #self.oldX = panel_pos.x
        #self.oldY = panel_pos.y
        #OR
            #self.paintSpot(panel_pos.x,panel_pos.y,self.brushRadius)
        #OR
        elif(curchoice == 1):
            subImage = PNMImage(32,32)
            subImage = PNMImage("full_white_square_gradiant_alpha.tif")
            #subImage.gaussianFilter(32)
            if(subImage.hasAlpha()):
                pass# print "Sub Image has alpha"
                #subImage.addAlpha()
            self.canvas.blendSubImage(subImage,panel_pos.x,panel_pos.y,0,0,-1,-1,.1)
        elif(curchoice == 2):
            subImage = PNMImage(32,32)
            subImage = PNMImage("brush_512_75%gray.tif")
            #subImage.gaussianFilter(32)
            if(subImage.hasAlpha()):
                pass#print "Sub Image gray has alpha"
            self.canvas.blendSubImage(subImage,panel_pos.x,panel_pos.y,0,0,-1,-1,.1)
        #print panel_pos
        self.updateImage()
        #print "HEREREREREER"
        
        if(task != None):
            return task.cont
        else:
            return task.done
   
    def Close(self, evt=None):
        self.saveTerrain()
        if(self.viewport):
            self.viewport.Close()
        #base.direct.manipulationControl.widgetList.remove(self.handles)
        base.direct.drList.removeDisplayRegionContext(self.viewport.cam)
        base.direct.manipulationControl.enableManipulation()
        base.le.ui.bindKeyEvents(True)
        self.viewport.ignore("mouse1")
        self.viewport.ignore("mouse1-up")
        self.viewport.ignore("z")
        self.viewport.ignore("y")
        self.paintCursor.detachNode()
        self.paintRing.detachNode()
        taskMgr.remove("followMouseTask")
        #self.editor.NPParent.clearLight(self.light)
        self.terrain.getNodePath().clearLight(self.light)
        self.light.detachNode()

        #self.ReleaseMouse()
        
        self.Destroy()
        
    def raiseImageWithCustomImage(self):
        for i in range(0,self.customImage.getReadXSize()):
            line = []
            for j in range(0, self.customImage.getReadYSize()):
                line.append("["+str(self.customImage.getXelA(i,j))+"]")
Example #9
0
class TerrainPaintUI(wx.Dialog):
    def __init__(self, parent, editor, terrain):
        pre = wx.PreDialog()
        self.res = xrc.XmlResource(GUI_FILENAME)
        self.res.LoadOnDialog(pre, parent, 'dlgTerrainPaint')
        self.PostCreate(pre)
        self.Bind(wx.EVT_INIT_DIALOG, self.onCreate)

        self.parent = parent
        self.editor = editor
        self.terrain = terrain
        #self.oldCanvas = PNMImgae()
        #self.oldCanvas.copyFrom(terrain.heightField())
        self.brushRadius = 1
        self.viewport = None

        self.oldX = -1
        self.oldY = -1

        self.paintCursor = loader.loadModel(
            "models/terrain_cursor.egg")  #jack")
        self.paintRing = loader.loadModel("models/terrain_ring.egg")
        self.paintCursor.setScale(12)
        self.paintCursor.reparentTo(self.editor.NPParent)
        self.paintCursor.setPos(self.terrain.getNodePath().getPos())
        self.paintRing.reparentTo(self.editor.NPParent)
        self.paintRing.setPos(self.paintCursor.getPos())

        taskMgr.add(self.followMouseTask, "followMouseTask")
        self.customImage = PNMImage(32, 32)
        self.customImage.read("full_white_square_gradiant_alpha.tif")
        self.raiseImageWithCustomImage()

        #TO DO:if no light check for later
        light = PointLight('Terrain Light')
        light.setColor(Vec4(1, 1, 1, 1))
        self.light = self.editor.NPParent.attachNewNode(light)
        pos = self.terrain.getNodePath().getPos()
        self.light.setPos(Point3(0, 0, pos[2] + 240))
        self.terrain.getNodePath().setLight(
            self.light)  #self.editor.NPParent.setLight(self.light)
        #self.editor.NPParent.setPoint(Point3(0,0, pos[2]+400))

        self.actionMgr = ActionMgr()

    def onCreate(self, evt):
        self.Unbind(wx.EVT_INIT_DIALOG)
        base.le.ui.bindKeyEvents(False)

        self.Show()
        self.Bind(wx.EVT_CLOSE, self.Close)

        #init all the panels from XRC for parenting later on
        self.notebook = xrc.XRCCTRL(self, "notebook_1")
        self.canvasPanel = xrc.XRCCTRL(self, "canvasPanel")
        self.texturePanel = xrc.XRCCTRL(self, "texturePanel")
        #self.setupWxPaint()

        #self.canvasPanel.Bind(wx.EVT_PAINT, self.onPaint)
        #self.canvasPanel.Bind(wx.EVT_LEFT_DOWN, self.onClick)

        #edit Panel
        self.btnUpdateTerrain = xrc.XRCCTRL(self, "btnUpdateTerrain")
        self.sliderBrushSize = xrc.XRCCTRL(self, "sliderBrushSize")
        self.textCtrlBrushSize = xrc.XRCCTRL(self, "textCtrlBrushSize")
        self.sliderGrayScale = xrc.XRCCTRL(self, "sliderGrayScale")
        self.textCtrlGrayScale = xrc.XRCCTRL(self, "textCtrlGrayScale")
        self.paintModeRadioBox = xrc.XRCCTRL(self, 'paintModeRadioBox')
        self.paintModeRadioBox.Hide()

        self.Bind(wx.EVT_BUTTON, self.saveTerrain, self.btnUpdateTerrain)
        self.sliderGrayScale.Bind(wx.EVT_SCROLL_ENDSCROLL, self.onSliderEnd)
        self.sliderBrushSize.Bind(wx.EVT_SCROLL_ENDSCROLL, self.onSliderEnd)
        #self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.onPageChange)

        self.setupViewport(self.canvasPanel)
        #self.setupTextureViewport()
        self.setupCanvas()
        #self.canvasPanel.CaptureMouse()

    #TODEL
    def onPageChange(self, evt):
        #0 is heightmap
        #1 is texture
        selected = self.notebook.GetSelection()
        if (self.viewport):
            self.viewport.Close()
        if (selected == 0):
            self.setupViewport(self.canvasPanel)
        else:
            self.setupViewport(self.texturePanel)

    def followMouseTask(self, task):
        panel_pos = self.canvasPanel.ScreenToClient(wx.GetMousePosition())
        if (self.isInBound(panel_pos.x, panel_pos.y) == False):
            return task.cont

        z = self.canvas.getBlueVal(panel_pos.x, panel_pos.y)
        #print "Blue: ", z

        z2 = self.canvas.getGrayVal(panel_pos.x, panel_pos.y)
        #print "Gray: ", z2

        if z < 128:
            z = 128
        #print "Mouse pos: ", Point3(panel_pos.x, math.fabs(panel_pos.y-512), z)
        mousePos = self.terrain.getNodePath().getPos() + Point3(
            panel_pos.x, math.fabs(panel_pos.y - 512), z + 1)
        self.paintCursor.setPos(mousePos)
        self.paintRing.setPos(mousePos)
        self.paintRing.setZ(30)
        return task.cont

    def setupWxPaint(self):
        self.bitmap = wx.Bitmap("bitmap")
        #self.canvasPanel.AddChild(self.bitmap)
        Debug.debug(__name__,
                    str(self.terrain.asset.getFullFilename().getExtension()))
        self.bitmap.LoadFile(
            self.terrain.asset.getFullFilename().toOsSpecific(),
            wx.BITMAP_TYPE_ANY)
        #self.static = wx.StaticBitmap(self.canvasPanel,size = wx.Size(513,513), style = wx.EXPAND )
        #self.static.SetBitmap(self.bitmap)
        #dc =wx.ClientDC(self)
        #dc.DrawBitmap(self.bitmap, 0, 0)

    def onClick(self, evt):
        self.canvasPanel.Bind(wx.EVT_PAINT, self.onPaint)
        panel_pos = self.canvasPanel.ScreenToClient(wx.GetMousePosition())
        # draw a blue line (thickness = 4)
        self.dc.DrawCircle(panel_pos.x, panel_pos.y, 10)

    def onPaint(self, evt):
        self.dc = wx.PaintDC(self.canvasPanel)
        self.dc.DrawBitmap(self.bitmap, 0, 0)
        self.dc.SetPen(wx.Pen('blue', 4))
        self.dc.SetBrush(wx.Brush('blue', wx.SOLID))

        #dc.DrawLine(50, 20, 300, 20)
        #dc.SetPen(wx.Pen('red', 1))
        # draw a red rounded-rectangle
        #rect = wx.Rect(50, 50, 100, 100)
        #dc.DrawRoundedRectangleRect(rect, 8)
        # draw a red circle with yellow fill
        #dc.SetBrush(wx.Brush('yellow'))
        #x = 250
        #y = 100
        #r = 50
        #dc.DrawCircle(x, y, r)

        pass

    def setupViewport(self, panel):
        self.terrainScene = NodePath(PandaNode("TerrainPaintScene"))
        self.terrain2d = NodePath(PandaNode("TerrainPaint2d"))
        self.terrain2dScaled = self.terrain2d.attachNewNode(
            PandaNode("terrain2dScaled"))

        base.direct.manipulationControl.disableManipulation()

        self.viewport = TerrainView('persp', panel)
        self.viewport.SetClientSize((513, 513))
        self.viewport.Update()
        base.le.ui.wxStep()
        self.viewport.initialize()

        #apply a mask to make sure GUI stuff from the main window doesn't show up here
        self.viewport.cam2d.node().setCameraMask(LE_IMPORT_MASK)
        self.viewport.camera.reparentTo(self.terrainScene)
        self.viewport.camera.setPos(0, -20, 0)
        self.viewport.camera.lookAt(0, 0, 0)
        self.viewport.cam2d.reparentTo(self.terrain2d)

        self.viewport.accept("mouse1", self.startPaint)
        self.viewport.accept("mouse1-up", self.stopPaint)
        self.viewport.accept('z', self.actionMgr.undo)
        self.viewport.accept('y', self.actionMgr.redo)

    def setupCanvas(self):
        self.temp = loader.loadModel("jack")
        #self.temp.reparentTo(self.terrain2d)
        #self.viewport.camera.lookAt(self.temp)
        self.canvas = PNMImage(513, 513)

        #        if(self.terrain.terrain.hasColorMap()==False):
        #            self.canvas.fill(1,1,1)
        #            self.canvas.makeRgb()
        #            print self.canvas.getNumChannels()
        #            self.terrain.terrain.setColorMap(self.canvas)
        #        else:
        self.canvas = self.terrain.terrain.heightfield(
        )  #self.canvas.read(Filename(self.terrain.asset.getFullFilename()))
        if (self.canvas.hasAlpha()):
            Debug.debug(__name__, "In canvas there is alpha")
        self.canvas.addAlpha()
        for i in range(0, self.canvas.getReadXSize()):
            for j in range(0, self.canvas.getReadYSize()):
                self.canvas.setAlpha(i, j, .5)
        sizeX = self.canvas.getReadXSize()
        sizeY = self.canvas.getReadYSize()
        #self.canvas.makeGrayscale()
        Debug.debug(__name__, str(sizeX) + " " + str(sizeY))
        self.tex = Texture()
        self.tex.load(self.canvas)
        #self.tex.reparentTo(self.terrain2d)
        CM = CardMaker('')
        CM.setFrameFullscreenQuad()
        self.card = self.terrain2d.attachNewNode(CM.generate())
        self.card.setTexture(self.tex)

        self.viewport.SetClientSize((sizeX, sizeY))
        self.canvasPanel.SetSize(wx.Size(sizeX, sizeY))
        self.viewport.Update()
        base.le.ui.wxStep()

        self.painter = PNMPainter(self.canvas)
        brush = PNMBrush.makeSpot((1, 1, 1, 1), 5.0, True)
        self.painter.setPen(brush)
        #print terrain2d
        #self.canvas.reparentTo(self.terrain2d)

        #panel_pos = self.canvasPanel.ScreenToClient(wx.GetMousePosition())
        #print self.viewport.bt.getParent().getMouseX()

    def onSliderEnd(self, evt):
        size = self.sliderBrushSize.GetValue()
        self.brushRadius = size
        grayScale = self.sliderGrayScale.GetValue()
        self.setBrush(size, grayScale)

    def setBrush(self, size, grayScale):
        scale = grayScale / 255.0
        brush = PNMBrush.makeSpot((scale, scale, scale, 1.0),
                                  size,
                                  True,
                                  effect=(PNMBrush.BEBlend))
        self.paintRing.setScale(size)
        #brush = PNMBrush.makeImage("75%.tif",16,16)
        self.painter.setPen(brush)
        self.painter.setFill(brush)

        pass

    # x and y position of the draw point
    def paintSpot(self, x, y, radius, higher=True, step=1):
        topX = x - radius
        topY = y - radius
        bottomX = x + radius
        bottomY = y + radius
        if (self.isInBound(x, y) == False):
            return
        baseVal = self.canvas.getGrayVal(x, y)
        #print "baseVal ",baseVal
        baseRGB = self.canvas.getXel(x, y)
        #print "baseRGB ",baseRGB
        for i in range(topX, bottomX):
            for j in range(topY, bottomY):
                if (self.isInBound(i, j) == False):
                    continue
                #print "=========="
                #print i, " ", j
                sum = math.fabs(i - x) + math.fabs(j - y)
                strength = radius - sum
                if (sum <= radius):
                    val = self.canvas.getGrayVal(i, j)  #get the current Color
                    #raise it or lower it.
                    if (higher):
                        newVal = self.roundGrayScale(val + strength)
                    else:
                        newVal = self.roundGrayScale(val - stength)

                    #newVal = Vec3(newVal,newVal,newVal)
                    newVal /= 255.0
                    self.canvas.setXel(i, j, newVal, newVal, newVal)

    def roundGrayScale(self, val, min=0, max=255):
        if val < 0: return 0
        elif val > 255: return 255
        else: return val

    def isInBound(self, x, y):
        a = x
        b = y
        xMax = self.canvas.getReadXSize() - 1
        yMax = self.canvas.getReadYSize() - 1
        if (a < 0):
            return False
        elif (a > xMax):
            return False
        if (b < 0):
            return False
        elif (b > yMax):
            return False

        return True

    def roundCoord(self, x, y):
        a = x
        b = y
        xMax = self.canvas.getReadXSize()
        yMax = self.canvas.getReadYSize()
        if (a < 0):
            a = 0
        elif (a > xMax):
            a = xMax
        if (b < 0):
            b = 0
        elif (b > yMax):
            b = yMax

        return (a, b)

    def updateImage(self):
        #sizeX =  self.canvas.getReadXSize()
        #sizeY =  self.canvas.getReadYSize()
        #self.tex = Texture()
        self.tex.load(self.canvas)
        self.card.clearTexture()
        self.card.setTexture(self.tex)
        #self.canvas.alphaFill(0)

    def resetTerrain(self, event=None):
        print "Terrain is Saved"
        file = Filename("temp.jpeg")
        file.setDirname(self.editor.currentProj.dir.getFullpath() +
                        '/Textures')
        status = self.canvas.write(file)
        #print "Status: ",status

        #self.canvas.fill(.5,.5,.5)
        #self.updateTerrain()
        #self.updateImage()
    def saveTerrain(self, event=None):
        #print type(self.terrain.asset)
        #print self.terrain.asset.getFullFilename().toOsSpecific()
        file = self.terrain.asset.getFullFilename().toOsSpecific()
        status = self.canvas.write(file)

        thumbnailFile = self.terrain.asset.getThumbnail()  #.getFullpath()
        #thumbnailPath = Filename('Thumbnails/' + texture.filename.getBasename())
        #        print thumbnailFile
        cwd = os.getcwd()
        os.chdir((self.editor.projDir + '/Textures/').toOsSpecific())
        #os.remove(thumbnailFile.toOsSpecific())
        subprocess.call([
            "image-resize", "-x 60", "-y 60", "-g 1",
            "-o" + thumbnailFile.toOsSpecific(),
            self.terrain.asset.filename.getBasename()
        ])
        #self.terrain.asset.thumbnail = thumbnailFile

        os.chdir(cwd)
        print "Terrain is Saved"

        self.editor.ui.libraryUI.update()

    def updateTerrain(self, event=None):
        #self.terrain.terrain.setHeightfield(self.canvas)
        #self.paintCursor.detachNode()#reparentTo(self.terrain.getNodePath())
        #self.terrain.terrain.setTexture(self.canvas)
        self.terrain.update()
        self.terrain.generate()
        x = self.terrain.getScale()[0]
        y = self.terrain.getScale()[1]
        z = 255.0
        self.terrain.setScale(Vec3(x, y, z))

    def mouse(self, event=None):
        pos = event.GetPosition()
        #print pos
        #print "HEREREREREER"

    def startPaint(self):
        panel_pos = self.canvasPanel.ScreenToClient(wx.GetMousePosition())
        #print panel_pos.x, " ", panel_pos.y
        x = self.canvas.getReadXSize
        y = self.canvas.getReadYSize
        if (panel_pos.x > x or panel_pos.x < 0):
            return
        if (panel_pos.y > y or panel_pos.y < 0):
            return

        self.drawAction = ActionDraw(self.editor, self)
        taskMgr.add(self.OnMove, "paintTask")

    def stopPaint(self):
        if (taskMgr.hasTaskNamed("paintTask") == False):
            return
        taskMgr.remove("paintTask")
        self.actionMgr.push(self.drawAction)
        self.drawAction()
        self.updateTerrain()

    def paintTask(self, task):
        pass

    def OnMove(self, task=None):
        curchoice = self.paintModeRadioBox.GetSelection()
        panel_pos = self.canvasPanel.ScreenToClient(wx.GetMousePosition())
        #if(self.oldX == panel_pos.x and self.oldY == panel_pos.y):
        #    return
        if (curchoice == 0):
            self.painter.drawPoint(panel_pos.x, panel_pos.y)
        #self.canvas.renderSpot(VBase4D(.5,.5,.5,1),VBase4D(.5,.5,.5,1),.00001,.00003)
        #self.oldX = panel_pos.x
        #self.oldY = panel_pos.y
        #OR
        #self.paintSpot(panel_pos.x,panel_pos.y,self.brushRadius)
        #OR
        elif (curchoice == 1):
            subImage = PNMImage(32, 32)
            subImage = PNMImage("full_white_square_gradiant_alpha.tif")
            #subImage.gaussianFilter(32)
            if (subImage.hasAlpha()):
                pass  # print "Sub Image has alpha"
                #subImage.addAlpha()
            self.canvas.blendSubImage(subImage, panel_pos.x, panel_pos.y, 0, 0,
                                      -1, -1, .1)
        elif (curchoice == 2):
            subImage = PNMImage(32, 32)
            subImage = PNMImage("brush_512_75%gray.tif")
            #subImage.gaussianFilter(32)
            if (subImage.hasAlpha()):
                pass  #print "Sub Image gray has alpha"
            self.canvas.blendSubImage(subImage, panel_pos.x, panel_pos.y, 0, 0,
                                      -1, -1, .1)
        #print panel_pos
        self.updateImage()
        #print "HEREREREREER"

        if (task != None):
            return task.cont
        else:
            return task.done

    def Close(self, evt=None):
        self.saveTerrain()
        if (self.viewport):
            self.viewport.Close()
        #base.direct.manipulationControl.widgetList.remove(self.handles)
        base.direct.drList.removeDisplayRegionContext(self.viewport.cam)
        base.direct.manipulationControl.enableManipulation()
        base.le.ui.bindKeyEvents(True)
        self.viewport.ignore("mouse1")
        self.viewport.ignore("mouse1-up")
        self.viewport.ignore("z")
        self.viewport.ignore("y")
        self.paintCursor.detachNode()
        self.paintRing.detachNode()
        taskMgr.remove("followMouseTask")
        #self.editor.NPParent.clearLight(self.light)
        self.terrain.getNodePath().clearLight(self.light)
        self.light.detachNode()

        #self.ReleaseMouse()

        self.Destroy()

    def raiseImageWithCustomImage(self):
        for i in range(0, self.customImage.getReadXSize()):
            line = []
            for j in range(0, self.customImage.getReadYSize()):
                line.append("[" + str(self.customImage.getXelA(i, j)) + "]")
Example #10
0
class LevelEditorBase(DirectObject):
    """ Base Class for Panda3D LevelEditor """ 
    def __init__(self):
        #loadPrcFileData('startup', 'window-type none')
        self.currentFile = None
        
        self.fNeedToSave = False    #if there are unsaved changes
        self.actionEvents = []
        #self.objectMgr = ObjectMgr(self)
        self.fileMgr = FileMgr(self)
        self.actionMgr = ActionMgr()
        self.standaloneExporter = StandaloneExporter(self)
        self.saved = False  #if the project has been saved at all

        self.fMoveCamera = False

        self.NPParent = render

        # define your own config file in inherited class
        self.settingsFile = None

        # you can show/hide specific properties by using propertiesMask and this mode
        self.mode = BitMask32()
        
        self.tempDir = None
        
        self.manipMode = 'translate'
        
        groundRay = CollisionNode('groundRay')
        groundRay.addSolid(CollisionRay(Point3(0,0,0), Vec3(0,0,-1)))
        groundRay.setFromCollideMask(BitMask32.allOn())
        self.groundCollide = render.attachNewNode(groundRay)
        self.groundCollideHandler = CollisionHandlerQueue()
        self.groundCollideTraverser = CollisionTraverser()
        self.groundCollideTraverser.addCollider(self.groundCollide, self.groundCollideHandler)
        
        
    
    def initialize(self):
        """ You should call this in your __init__ method of inherited LevelEditor class """
        # specifiy what obj can be 'selected' as objects
        base.direct.selected.addTag('OBJRoot')

        self.actionEvents.extend([
            # Node path events
            ('DIRECT-select', self.select),
            ('DIRECT-delete', self.handleDelete),
            ('DIRECT-preDeselectAll', self.deselectAll),
            ('DIRECT_deselectAll', self.deselectAllCB),
            ('preRemoveNodePath', self.removeNodePathHook),
            ('DIRECT_deselectedNodePath', self.deselectAllCB),
            ('DIRECT_selectedNodePath_fMulti_fTag_fLEPane', self.selectedNodePathHook),
            ('DIRECT_deselectAll', self.deselectAll),
            ('LE-Undo', self.actionMgr.undo),
            ('LE-Redo', self.actionMgr.redo),
            ('LE-Duplicate', self.ui.onDuplicate),
            ('DIRECT_manipulateObjectCleanup', self.cleanUpManipulating),
            #('LE-MakeLive', self.objectMgr.makeSelectedLive),
            ('LE-NewScene', self.ui.onNew),
            ('LE-SaveScene', self.ui.onSave),
            ('LE-OpenScene', self.ui.onOpen),
            ('LE-Import', self.ui.onImport),
            ('LE-Quit', self.ui.quit),
            ('DIRECT-mouse1', self.handleMouse1),
            ('DIRECT-mouse1Up', self.handleMouse1Up),
            ('DIRECT-mouse2', self.handleMouse2),
            ('DIRECT-mouse2Up', self.handleMouse2Up),
            ('DIRECT-mouse3', self.handleMouse3),
            ('DIRECT-mouse3Up', self.handleMouse3Up),
            ('LE-translateMode', self.translateMode),
            ('LE-rotateMode', self.rotateMode),
            ('LE-scaleMode', self.scaleMode),
            ('LE-localMode', self.localMode),
            ('LE-worldMode', self.worldMode),
            ('LE-DropToGround', self.onDropToGround),
            ('LE-lookAtSelected', self.lookAtSelected),
            ('LE-moveCameraToSelected', self.moveCameraToSelected),
            ('LE-moveAllCamerasToSelected', self.moveAllCamerasToSelected),
            ])

        # Add all the action events
        for event in self.actionEvents:
            if len(event) == 3:
                self.accept(event[0], event[1], event[2])
            else:
                self.accept(event[0], event[1])        

        # editor state text display such as edit mode
        self.statusReadout = OnscreenText(
            pos = (-1.2, 0.9), bg=Vec4(1,1,1,1),
            scale = 0.05, align = TextNode.ALeft,
            mayChange = 1, font = TextNode.getDefaultFont())
        self.statusReadout.setText("")
        # Make sure readout is never lit or drawn in wireframe
        useDirectRenderStyle(self.statusReadout)
        self.statusReadout.reparentTo(hidden)
        self.statusLines = []
        taskMgr.doMethodLater(5, self.updateStatusReadoutTimeouts, 'updateStatus')
        taskMgr.add(self.updateShaders, 'updateShaders')

        self.loadSettings()
        self.reset()
        self.newProj()
        
        self.resetWidgets()
        base.direct.manipulationControl.useSeparateScaleHandles = True
        base.direct.cameraControl.switchDirBelowZero = False
        
        #self.defaultColor = BGC_LIGHT_BLUE
        self.setBackgroundColor(BGC_LIGHT_BLUE)
        
        
    
    #opens a new project in the temp directory
    def newProj(self):
        if self.tempDir and os.path.exists(self.tempDir):
            shutil.rmtree(self.tempDir)
        self.tempDir = os.path.join(Util.getTempDir(), 'NewProj')
        if os.path.exists(self.tempDir):
            for root, dirs, files in os.walk(self.tempDir):
                for f in files:
                    file = os.path.join(root, f)
                    fileAtt = os.stat(file)[0]
                    if (not fileAtt & stat.S_IWRITE):
                        os.chmod(file, stat.S_IWRITE)
                    
            shutil.rmtree(self.tempDir)
        
        projFile = Filename.fromOsSpecific(self.tempDir) + '/New Project.proj'
        self.currentProj = Project(projFile, "New Project")
        #defaultSceneName = "default"
        #self.currentProj.addScene(defaultSceneName, 
        #                          Filename(defaultSceneName+'.scene'))#Filename(projFile.getBasenameWoExtension() + '.scene'))
        #current Scene that the objectMgr manages and saves to
        #self.currentScene = self.currentProj.sceneFilename
        self.currentSceneName = self.currentProj.sceneName
        self.ui.scenesUI.populateTreeFromScenes()#add(defaultSceneName)
        self.projDir = self.currentProj.dir
        self.lib = self.currentProj.lib
        self.saved = False
        self.ui.libraryUI.update()
        self.ui.storyObjUI.update()
        self.ui.soundUI.update()
    
    def setTitleWithFilename(self, filename=""):
        title = self.ui.appname
        if filename != "":
           filenameshort = os.path.basename(filename)
           title = title + " (%s)"%filenameshort
        self.ui.SetLabel(title)

    def removeNodePathHook(self, nodePath):
        if nodePath is None:
            return
        base.direct.deselect(nodePath)
        self.objectMgr.removeObjectByNodePath(nodePath)

        if (base.direct.selected.last != None and nodePath.compareTo(base.direct.selected.last)==0):
            # if base.direct.selected.last is refering to this
            # removed obj, clear the reference
            if (hasattr(__builtins__,'last')):
                __builtins__.last = None
            else:
                __builtins__['last'] = None
            base.direct.selected.last = None

    def handleMouse1(self, modifiers):
        if base.direct.fAlt or modifiers == 4:
            self.fMoveCamera = True
            return

    def handleMouse1Up(self):
        self.fMoveCamera = False
        
        base.direct.fAlt = wx.GetKeyState(wx.WXK_ALT)
        base.direct.fControl = wx.GetKeyState(wx.WXK_CONTROL)
        base.direct.fShift = wx.GetKeyState(wx.WXK_SHIFT)

    def handleMouse2(self, modifiers):
        if base.direct.fAlt or modifiers == 4:
            self.fMoveCamera = True
            return

    def handleMouse2Up(self):
        self.fMoveCamera = False
        
        base.direct.fAlt = wx.GetKeyState(wx.WXK_ALT)
        base.direct.fControl = wx.GetKeyState(wx.WXK_CONTROL)
        base.direct.fShift = wx.GetKeyState(wx.WXK_SHIFT)
        
    def handleMouse3(self, modifiers):
        if base.direct.fAlt or modifiers == 4:
            self.fMoveCamera = True
            return

        self.ui.onRightDown()

    def handleMouse3Up(self):
        self.fMoveCamera = False
        
        base.direct.fAlt = wx.GetKeyState(wx.WXK_ALT)
        base.direct.fControl = wx.GetKeyState(wx.WXK_CONTROL)
        base.direct.fShift = wx.GetKeyState(wx.WXK_SHIFT)

    def handleDelete(self):
        oldSelectedNPs = base.direct.selected.getSelectedAsList()
        oldUIDs = []
        for oldNP in oldSelectedNPs:
            obj = self.objectMgr.findObjectByNodePath(oldNP)
            if obj:
                oldUIDs.append(obj.getName())
        action = ActionDeleteObj(self)
        self.actionMgr.push(action)
        action()

##         reply = wx.MessageBox("Do you want to delete selected?", "Delete?",
##                               wx.YES_NO | wx.ICON_QUESTION)
##         if reply == wx.YES:
##             base.direct.removeAllSelected()
##         else:
##             # need to reset COA
##             dnp = base.direct.selected.last
##             # Update camera controls coa to this point
##             # Coa2Camera = Coa2Dnp * Dnp2Camera
##             mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(base.direct.camera)
##             row = mCoa2Camera.getRow(3)
##             coa = Vec3(row[0], row[1], row[2])
##             base.direct.cameraControl.updateCoa(coa)

    def translateMode(self, evt=None):
        self.manipMode = 'translate'
        self.resetWidgets()

        self.ui.translateMenuItem.Check()
        
    def rotateMode(self, evt=None):
        self.manipMode = 'rotate'
        self.resetWidgets()
        
        self.ui.rotateMenuItem.Check()
    
    def scaleMode(self, evt=None):
        self.manipMode = 'scale'
        self.resetWidgets()
        
        self.ui.scaleMenuItem.Check()
    
    def worldMode(self, evt=None):
        base.direct.manipulationControl.switchToWorldSpaceMode()
        self.ui.worldMenuItem.Check()
    
    def localMode(self, evt=None):
        base.direct.manipulationControl.switchToLocalSpaceMode()
        self.ui.localMenuItem.Check()
     
    def showWidget(self):
        for widget in base.direct.manipulationControl.widgetList:
            widget.activate()
    
    def hideWidget(self):
        for widget in base.direct.manipulationControl.widgetList:
            widget.deactivate()
     
    def resetWidgets(self):
        for widget in base.direct.manipulationControl.widgetList:
            widget.disableHandles('all')
            if self.manipMode == 'translate':
                widget.enableHandles('post')
            elif self.manipMode == 'rotate':
                widget.enableHandles('ring')
            elif self.manipMode == 'scale':
                widget.enableHandles('scale')

    #makes the camera look at the center of teh bounding box of whatever is selected
    def lookAtSelected(self):
        selected = base.direct.selected.getSelectedAsList()
        if selected:
            bounds = BoundingBox()
            for np in selected:
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)      
        else:
            bounds = BoundingBox()
            for obj in self.objectMgr.objects.values():
                np = obj.nodePath
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)
        if bounds.isEmpty() or bounds.isInfinite():
            center = Point3(0, 0, 0)
        else:
            center = Point3((bounds.getMax() + bounds.getMin()) / 2.0)
        
        np = NodePath('temp')
        np.setPos(self.ui.perspView.camera.getPos())
        np.lookAt(center)
        i = LerpHprInterval(self.ui.perspView.camera, 1.0, np.getHpr(), blendType='easeInOut')
        i.start()
        base.direct.cameraControl.coaMarkerPos.assign(center)
        np.removeNode()
    
    #moves the camera to the outside of the bounding box of whatever is selected and looks at it
    def moveCameraToSelected(self):
        selected = base.direct.selected.getSelectedAsList()
        if selected:
            bounds = BoundingBox()
            for np in selected:
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)      
        else:
            bounds = BoundingBox()
            for obj in self.objectMgr.objects.values():
                np = obj.nodePath
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)
        
        if bounds.isEmpty() or bounds.isInfinite():
            center = Point3(0, 0, 0)
            targetPos = Point3(-19, -19, 19)
        else:
            center = Point3((bounds.getMax() + bounds.getMin()) / 2.0)
            diff = self.ui.perspView.camera.getPos() - center
            diff.normalize()
            targetPos = center + diff * (bounds.getMax() - bounds.getMin()).length() * 1.8
        
        np = NodePath('temp')
        np.setPos(targetPos)
        np.lookAt(center)
        i = LerpPosHprInterval(self.ui.perspView.camera, 1, targetPos, np.getHpr(), blendType='easeInOut')
        i.start()
        base.direct.cameraControl.coaMarkerPos.assign(center)
        np.removeNode()
    
    #moves all cameras(perspective and the 3 ortho cameras) to focus on the selected object
    def moveAllCamerasToSelected(self):
        selected = base.direct.selected.getSelectedAsList()
        if selected:
            bounds = BoundingBox()
            for np in selected:
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)        
        else:
            bounds = BoundingBox()
            for obj in self.objectMgr.objects.values():
                np = obj.nodePath
                b = np.getBounds()
                b.xform(np.getParent().getMat(render))
                bounds.extendBy(b)
        
        #perspective
        if bounds.isEmpty() or bounds.isInfinite():
                center = Point3(0, 0, 0)
                targetPos = Point3(-19, -19, 19)
        else:
            center = Point3((bounds.getMax() + bounds.getMin()) / 2.0)
            diff = self.ui.perspView.camera.getPos() - center
            diff.normalize()
            targetPos = center + diff * (bounds.getMax() - bounds.getMin()).length() * 1.8
        
        np = NodePath('temp')
        np.setPos(targetPos)
        np.lookAt(center)
        i = LerpPosHprInterval(self.ui.perspView.camera, 1, targetPos, np.getHpr(), blendType='easeInOut')
        i.start()
        base.direct.cameraControl.coaMarkerPos.assign(center)
        np.removeNode()
        
        #top
        if bounds.isEmpty() or bounds.isInfinite():
            targetPos = Point3(0, 0, 600)
            base.direct.drList[base.camList.index(NodePath(self.ui.topView.camNode))].orthoFactor = 0.1
            
        else:
            targetPos = Point3((bounds.getMax().getX() + bounds.getMin().getX()) / 2.0, (bounds.getMax().getY() + bounds.getMin().getY()) / 2.0, bounds.getMax().getZ() + 600)
            size = max( (bounds.getMax().getX() - bounds.getMin().getX()), (bounds.getMax().getY() - bounds.getMin().getY()))
            base.direct.drList[base.camList.index(NodePath(self.ui.topView.camNode))].orthoFactor = size / min(self.ui.topView.ClientSize.GetWidth(), self.ui.topView.ClientSize.GetHeight() )
            
        x = self.ui.topView.ClientSize.GetWidth() * base.direct.drList[base.camList.index(NodePath(self.ui.topView.camNode))].orthoFactor
        y = self.ui.topView.ClientSize.GetHeight() * base.direct.drList[base.camList.index(NodePath(self.ui.topView.camNode))].orthoFactor
        i = LerpFunc(self.orthoPosFilmSizeInterval, extraArgs=[self.ui.topView.camera, self.ui.topView.camLens, self.ui.topView.camera.getPos(), targetPos,\
        self.ui.topView.camLens.getFilmSize().getX(), x, self.ui.topView.camLens.getFilmSize().getY(), y], blendType = 'noBlend', duration=1)
        i.start()
        
        #right
        if bounds.isEmpty() or bounds.isInfinite():
            targetPos = Point3(600, 0, 0)
            base.direct.drList[base.camList.index(NodePath(self.ui.leftView.camNode))].orthoFactor = 0.1
            
        else:
            targetPos = Point3(bounds.getMax().getX() + 600, (bounds.getMax().getY() + bounds.getMin().getY()) / 2.0, (bounds.getMax().getZ() + bounds.getMin().getZ()) / 2.0)
            size = max( (bounds.getMax().getY() - bounds.getMin().getY()), (bounds.getMax().getZ() - bounds.getMin().getZ()))
            base.direct.drList[base.camList.index(NodePath(self.ui.leftView.camNode))].orthoFactor = size / min(self.ui.leftView.ClientSize.GetWidth(), self.ui.leftView.ClientSize.GetHeight() )
            
        x = self.ui.leftView.ClientSize.GetWidth() * base.direct.drList[base.camList.index(NodePath(self.ui.leftView.camNode))].orthoFactor
        y = self.ui.leftView.ClientSize.GetHeight() * base.direct.drList[base.camList.index(NodePath(self.ui.leftView.camNode))].orthoFactor
        i = LerpFunc(self.orthoPosFilmSizeInterval, extraArgs=[self.ui.leftView.camera, self.ui.leftView.camLens, self.ui.leftView.camera.getPos(), targetPos,\
        self.ui.leftView.camLens.getFilmSize().getX(), x, self.ui.leftView.camLens.getFilmSize().getY(), y], blendType = 'noBlend', duration=1)
        i.start()
        
        #front
        if bounds.isEmpty() or bounds.isInfinite():
            targetPos = Point3(0, -600, 0)
            base.direct.drList[base.camList.index(NodePath(self.ui.frontView.camNode))].orthoFactor = 0.1
            
        else:
            targetPos = Point3((bounds.getMax().getX() + bounds.getMin().getX()) / 2.0, bounds.getMin().getY() - 600, (bounds.getMax().getZ() + bounds.getMin().getZ()) / 2.0)
            size = max( (bounds.getMax().getX() - bounds.getMin().getX()), (bounds.getMax().getZ() - bounds.getMin().getZ()))
            base.direct.drList[base.camList.index(NodePath(self.ui.frontView.camNode))].orthoFactor = size / min(self.ui.frontView.ClientSize.GetWidth(), self.ui.frontView.ClientSize.GetHeight() )
            
        x = self.ui.frontView.ClientSize.GetWidth() * base.direct.drList[base.camList.index(NodePath(self.ui.frontView.camNode))].orthoFactor
        y = self.ui.frontView.ClientSize.GetHeight() * base.direct.drList[base.camList.index(NodePath(self.ui.frontView.camNode))].orthoFactor
        i = LerpFunc(self.orthoPosFilmSizeInterval, extraArgs=[self.ui.frontView.camera, self.ui.frontView.camLens, self.ui.frontView.camera.getPos(), targetPos,\
        self.ui.frontView.camLens.getFilmSize().getX(), x, self.ui.frontView.camLens.getFilmSize().getY(), y], blendType = 'noBlend', duration=1)
        i.start()
        
            
    def orthoPosFilmSizeInterval(self, t, camera, camLens, beginPos, endPos, beginX, endX, beginY, endY):
        camera.setPos(beginPos * (1-t) + endPos * t)
        camLens.setFilmSize(beginX * (1-t) + endX * t, beginY * (1-t) + endY * t)
        
    def cleanUpManipulating(self, selectedNPs):
        for np in selectedNPs:
            obj = self.objectMgr.findObjectByNodePath(np)
            if obj and np.getMat() != self.objectMgr.objectsLastXform[obj.getName()]:
                action = ActionTransformObj(self, obj.getName(), Mat4(np.getMat()))
                self.actionMgr.push(action)
                action()

    def select(self, nodePath, fMultiSelect=0, fSelectTag=1, fResetAncestry=1, fLEPane=0, fUndo=1):
        base.direct.toggleWidgetVis()
        if fUndo:
            # Select tagged object if present
            if fSelectTag:
                for tag in base.direct.selected.tagList:
                    if nodePath.hasNetTag(tag):
                        nodePath = nodePath.findNetTag(tag)
                        break
            action = ActionSelectObj(self, nodePath, fMultiSelect=fMultiSelect, fSelectTag=fSelectTag, fResetAncestry=fResetAncestry,fLEPane=fLEPane)
            self.actionMgr.push(action)
            action()
        else:
            base.direct.selectCB(nodePath, fMultiSelect, fSelectTag, fResetAncestry, fLEPane, fUndo)
            
        if base.direct.selected.getSelectedAsList:
            self.showWidget()

    def selectedNodePathHook(self, nodePath, fMultiSelect = 0, fSelectTag = 1, fLEPane = 0):
        # handle unpickable nodepath
        if nodePath.getName() in base.direct.iRay.unpickable:
            base.direct.deselect(nodePath)
            return

        if fMultiSelect == 0 and fLEPane == 0:
           oldSelectedNPs = base.direct.selected.getSelectedAsList()
           for oldNP in oldSelectedNPs:
              obj = self.objectMgr.findObjectByNodePath(oldNP)
              if obj:
                 self.ui.sceneGraphUI.deSelect(obj.getName())
        self.objectMgr.selectObject(nodePath, fLEPane, fMultiSelect)
        self.ui.buildContextMenu(nodePath)
        
        
    def deselectAll(self, np=None):
        self.hideWidget()
        self.objectMgr.deselectAll()
        if len(base.direct.selected.getSelectedAsList()) ==0:
            return
        action = ActionDeselectAll(self)
        self.actionMgr.push(action)
        action()

    def deselectAllCB(self, dnp=None):
        if not dnp:
            self.objectMgr.deselectAll()
            self.editor.ui.sceneGraphUI.tree.UnselectAll()
        else:
            obj = self.objectMgr.findObjectByNodePath(dnp)
            if obj:
                self.ui.sceneGraphUI.deSelect(obj.name)
        
    def reset(self, resetViews=True):
        if self.fNeedToSave:
            reply = wx.MessageBox("Do you want to save the current project?", "Save?",
                               wx.YES_NO | wx.ICON_QUESTION)
            if reply == wx.YES:
                result = self.ui.onSave()
                if result == False:
                    return

        base.direct.deselectAll()
        self.ui.reset()
        self.objectMgr.reset()
        self.actionMgr.reset()
        self.soundMgr.reset()
        self.journalMgr.reset()
        self.inventoryMgr.reset()
        if resetViews:
            self.ui.perspView.camera.setPos(-19, -19, 19)
            self.ui.perspView.camera.lookAt(Point3(0, 0, 0))
            self.ui.leftView.camera.setPos(600, 0, 0)
            self.ui.frontView.camera.setPos(0, -600, 0)
            self.ui.topView.camera.setPos(0, 0, 600)
            self.resetOrthoCam(self.ui.topView)
            self.resetOrthoCam(self.ui.frontView)
            self.resetOrthoCam(self.ui.leftView)
        self.fNeedToSave = False
        self.setTitleWithFilename()
    
    def resetScene(self):
        if self.fNeedToSave:
            reply = wx.MessageBox("With Switching Scenes you will lose the previous Scene.\n Do you want to save the current project?", "Save?",
                               wx.YES_NO | wx.ICON_QUESTION)
            if reply == wx.YES:
                result = self.ui.onSave()
                if result == False:
                    return
        base.direct.deselectAll()
        self.objectMgr.reset()
        self.actionMgr.reset()
        self.soundMgr.reset()# May not reset this
        self.fNeedToSave = False
        self.setTitleWithFilename()
        
        
        
    def resetOrthoCam(self, view):
        base.direct.drList[base.camList.index(NodePath(view.camNode))].orthoFactor = 0.1
        x = view.ClientSize.GetWidth() * 0.1
        y = view.ClientSize.GetHeight() * 0.1
        view.camLens.setFilmSize(x, y)
        
    def save(self):
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        #check to make sure everything is writable
        try:
            f = open(self.currentProj.filename.toOsSpecific(), 'a')
            f.close()
        except IOError as e:
            dlg = wx.MessageDialog(self.ui, "The project file " +\
            " could not be written.  Make sure it is not marked read-only and try again",\
            caption = "Save Error", style=wx.ICON_ERROR|wx.OK)
            dlg.ShowModal()
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            return
            
        try:
            f = open((self.projDir + '/' + self.currentProj.getScene(self.currentSceneName).getFullpath()).toOsSpecific(), 'a')
            f.close()
        except IOError as e:
            dlg = wx.MessageDialog(self.ui, "The scene file "  +\
            " could not be written.  Make sure it is not marked read-only and try again",\
            caption = "Save Error", style=wx.ICON_ERROR|wx.OK)
            dlg.ShowModal()
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            return
            
        try:
            f = open((self.projDir + '/' + 'lib.index').toOsSpecific(), 'a')
            f.close()
        except IOError as e:
            dlg = wx.MessageDialog(self.ui, "The library index file " +\
            " could not be written.  Make sure it is not marked read-only and try again",\
            caption = "Save Error", style=wx.ICON_ERROR|wx.OK)
            dlg.ShowModal()
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            return
        
        try:
            f = open((self.projDir + '/' +  self.currentProj.journalFilename.getFullpath()).toOsSpecific(), 'a')
            f.close()
        except IOError as e:
            dlg = wx.MessageDialog(self.ui, "The journal file " +\
            " could not be written.  Make sure it is not marked read-only and try again",\
            caption = "Save Error", style=wx.ICON_ERROR|wx.OK)
            dlg.ShowModal()
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            return
        
        self.currentProj.saveToFile()
        self.fileMgr.saveToFile(self.projDir + '/' + self.currentProj.getScene(self.currentSceneName).getFullpath())
        self.fileMgr.saveJournalToFile(self.projDir+'/'+self.currentProj.journalFilename.getFullpath())
        self.fileMgr.saveInventoryMapToFile(self.projDir+'/'+self.currentProj.inventoryMapFilename.getFullpath())
        self.lib.saveToFile()
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))

    def saveAs(self, fileName, projName):
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        self.currentProj.saveAs(fileName, projName, self.saved)
        self.tempDir = None
        self.projDir = self.currentProj.dir
        self.fileMgr.saveToFile(self.projDir + '/' + self.currentProj.getScene(self.currentSceneName).getFullpath())
        self.fileMgr.saveJournalToFile(self.projDir+'/'+self.currentProj.journalFilename.getFullpath())
        self.fileMgr.saveInventoryMapToFile(self.projDir+'/'+self.currentProj.inventoryMapFilename.getFullpath())
        self.saved = True
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
        
#    def createSceneFile(self,sceneFile):
#        try:
#            f = open((self.projDir + '/' + sceneFile.getFullpath()).toOsSpecific(), 'a')
#            f.close()
#        except IOError as e:
#            dlg = wx.MessageDialog(self.ui, "The scene file "  +\
#            " could not be written.  Make sure it is not marked read-only and try again",\
#            caption = "Save Error", style=wx.ICON_ERROR|wx.OK)
#            dlg.ShowModal()
#            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
#            return

    def load(self, fileName, resetViews=True, setSaved=True):
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        self.reset(resetViews=resetViews)
        self.currentProj = Project(fileName)
        self.projDir = self.currentProj.dir
        self.lib = self.currentProj.lib
        
        #make sure we get updated versions of assets
        ModelPool.releaseAllModels()
        TexturePool.releaseAllTextures()
        ShaderPool.releaseAllShaders()
        
        self.currentSceneName = self.currentProj.sceneName
        self.fileMgr.loadFromFile(self.projDir + '/' +self.currentProj.getScene(self.currentSceneName).getFullpath())
        self.fileMgr.loadJournalFromFile(self.projDir+'/'+self.currentProj.journalFilename.getFullpath())
        self.fileMgr.loadInventoryMapFromFile(self.projDir+'/'+self.currentProj.inventoryMapFilename.getFullpath())
        if setSaved:
            self.saved = True
        
        #self.currenScene = self.currentProj.sceneFilename
        self.ui.scenesUI.populateTreeFromScenes()
        
        self.objectMgr.updateMainCharWidget() #[antonjs 4/14/11]
        
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))

    #Cosider to change merging projects: Maybe just merging scenes?
    def mergeProject(self, fileName, prefix='', newNodeName= ''):
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        otherProj = Project(fileName)
        if not prefix:
            prefix = otherProj.name
        try:
            self.lib.checkLibrary(otherProj.lib, prefix)
        except Exception as e:
            print 'ERROR:Could not merge libraries'
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            raise e
            return
            
        self.lib.mergeWith(otherProj.lib, prefix, saveAfter=True)
        try:
            self.fileMgr.loadFromFile(otherProj.dir + '/' + otherProj.scenes[otherProj.sceneName].getFullpath(), merge=True, lib=otherProj.lib, otherName=prefix, newNodeName= newNodeName)
        except Util.SceneMergeError as e:
            print 'ERROR:could not merge scenes'
            self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            traceback.print_exc(file=sys.stdout)
            return
        
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
        self.ui.libraryUI.update()
        self.ui.storyObjUI.update()
        self.ui.soundUI.update()
        self.objectMgr.updateMainCharWidget() #[antonjs 4/14/11]
        
        self.fNeedToSave = True
        
    def saveSettings(self):
        if self.settingsFile is None:
            return
        
        try:
            f = open(self.settingsFile, 'w')
            f.write('gridSize\n%f\n'%self.ui.perspView.grid.gridSize)
            f.write('gridSpacing\n%f\n'%self.ui.perspView.grid.gridSpacing)
            f.write('hotKey\n%s\n'%base.direct.hotKeyMap)
            f.close()
        except:
            pass        

    def loadSettings(self):
        base.direct.hotKeyMap = {   
            'control-y': ('Redo', 'LE-Redo'),
            'shift-v': ('Toggle Marker', 'DIRECT-toggleMarkerVis'),
            'control-n': ('New Scene', 'LE-NewScene'),
            'control-s': ('Save Scene', 'LE-SaveScene'),
            'escape': ('Deselect All', 'deselectAll'),
            'control-z': ('Undo', 'LE-Undo'),
            ',': ('Scale Down Widget', 'DIRECT-widgetScaleDown'),
            '.': ('Scale Up Widget', 'DIRECT-widgetScaleUp'),
            'control-o': ('Open Scene', 'LE-OpenScene'),
            'control-q': ('Quit', 'LE-Quit'),
            'control-i': ('Import', 'LE-Import'),
            # 'b': ('Toggle Backface', 'DIRECT-toggleBackface'),
            #'f': ('Fit on Widget', 'DIRECT-fitOnWidget'),
            # 't': ('Toggle Textures', 'DIRECT-toggleTexture'),
            't': ('Toggle Wireframe', 'DIRECT-toggleWireframe'),
            'f' : ('Look at Selected', 'LE-lookAtSelected'),
            'c' : ('Move Camera to Selected', 'LE-moveCameraToSelected'),
            'shift-c' : ('Move All Cameras to Selected', 'LE-moveAllCamerasToSelected'),
            'w': ('Enter Translate Mode', 'LE-translateMode'),
            'e': ('Enter Rotate Mode', 'LE-rotateMode'),
            'r': ('Enter Scale Mode', 'LE-scaleMode'),
            'delete': ('Delete', 'DIRECT-delete'),
            'control-g': ('Drop Selected to Ground', 'LE-DropToGround'),
            'control-d': ('Duplicate', 'LE-Duplicate')}
        
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
        try:
            f = open(self.settingsFile, 'r')
            configLines = f.readlines()
            f.close()

            gridSize = 100.0
            gridSpacing = 5.0
            for i in range(0, len(configLines)):
                line = configLines[i]
                i = i + 1
                if line.startswith('gridSize'):
                    gridSize = float(configLines[i])
                elif line.startswith('gridSpacing'):
                    gridSpacing = float(configLines[i])
                elif line.startswith('hotKey'):
                    customHotKeyMap = eval(configLines[i])
                    customHotKeyDict = {}
                    for hotKey in customHotKeyMap.keys():
                        desc = customHotKeyMap[hotKey]
                        customHotKeyDict[desc[1]] = hotKey

                    overriddenKeys = []
                    for key in base.direct.hotKeyMap.keys():
                        desc = base.direct.hotKeyMap[key]
                        if desc[1] in customHotKeyDict.keys():
                            overriddenKeys.append(key)

                    for key in overriddenKeys:
                        del base.direct.hotKeyMap[key]
                            
                    base.direct.hotKeyMap.update(customHotKeyMap)

            self.ui.updateGrids(gridSize, gridSpacing)
            self.ui.updateMenu()
        except:
            base.direct.hotKeyMap = {   
            'control-y': ('Redo', 'LE-Redo'),
            'shift-v': ('Toggle Marker', 'DIRECT-toggleMarkerVis'),
            'control-n': ('New Scene', 'LE-NewScene'),
            'control-s': ('Save Scene', 'LE-SaveScene'),
            'escape': ('Deselect All', 'deselectAll'),
            'control-z': ('Undo', 'LE-Undo'),
            ',': ('Scale Down Widget', 'DIRECT-widgetScaleDown'),
            '.': ('Scale Up Widget', 'DIRECT-widgetScaleUp'),
            'control-o': ('Open Scene', 'LE-OpenScene'),
            'control-q': ('Quit', 'LE-Quit'),
            'control-i': ('Import', 'LE-Import'),
            # 'b': ('Toggle Backface', 'DIRECT-toggleBackface'),
            #'f': ('Fit on Widget', 'DIRECT-fitOnWidget'),
            # 't': ('Toggle Textures', 'DIRECT-toggleTexture'),
            't': ('Toggle Wireframe', 'DIRECT-toggleWireframe'),
            'f' : ('Look at Selected', 'LE-lookAtSelected'),
            'c' : ('Move Camera to Selected', 'LE-moveCameraToSelected'),
            'shift-c' : ('Move All Cameras to Selected', 'LE-moveAllCamerasToSelected'),
            'w': ('Enter Translate Mode', 'LE-translateMode'),
            'e': ('Enter Rotate Mode', 'LE-rotateMode'),
            'r': ('Enter Scale Mode', 'LE-scaleMode'),
            'g': ('Switch to World Space Manipulation', 'LE-worldMode'),
            'l': ('Switch to Local Space Manipulation', 'LE-localMode'),
            'delete': ('Delete', 'DIRECT-delete'),
            'control-g': ('Drop Selected to Ground', 'LE-DropToGround'),
            'control-d': ('Duplicate', 'LE-Duplicate')}
            self.ui.updateMenu()
        self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))

    def convertMaya(self, modelname, callBack, obj=None, isAnim=False):
        if obj and isAnim:
            mayaConverter = MayaConverter(self.ui, self, modelname, callBack, obj, isAnim)
        else:
            reply = wx.MessageBox("Is it an animation file?", "Animation?",
                              wx.YES_NO | wx.ICON_QUESTION)
            if reply == wx.YES:
                mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, True)
            else:        
                mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, False)
        mayaConverter.Show()

    def convertFromMaya(self, modelname, callBack):
        mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, False)
        mayaConverter.Show()

    def updateStatusReadout(self, status, color=None):
        if status:
            # add new status line, first check to see if it already exists
            alreadyExists = False
            for currLine in self.statusLines:
                if (status == currLine[1]):
                    alreadyExists = True
                    break
            if (alreadyExists == False):
                time = globalClock.getRealTime() + 15
                self.statusLines.append([time,status,color])

        # update display of new status lines
        self.statusReadout.reparentTo(aspect2d)
        statusText = ""
        lastColor = None
        for currLine in self.statusLines:
            statusText += currLine[1] + '\n'
            lastColor = currLine[2]
        self.statusReadout.setText(statusText)
        if (lastColor):
            self.statusReadout.textNode.setCardColor(
                lastColor[0], lastColor[1], lastColor[2], lastColor[3])
            self.statusReadout.textNode.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
        else:
            self.statusReadout.textNode.setCardColor(1,1,1,1)
            self.statusReadout.textNode.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
            
    def updateStatusReadoutTimeouts(self,task=None):
        removalList = []
        for currLine in self.statusLines:
            if (globalClock.getRealTime() >= currLine[0]):
                removalList.append(currLine)
        for currRemoval in removalList:
            self.statusLines.remove(currRemoval)
        self.updateStatusReadout(None)
        # perform doMethodLater again after delay
        # This crashes when CTRL-C'ing, so this is a cheap hack.
        #return 2
        from direct.task import Task
        return Task.again

    def updateShaders(self, task):
        for obj in self.objectMgr.objects.values():
            if obj.shader and obj.shaderActive:
                obj.shader.update()
        return task.cont
        
    def propMeetsReq(self, typeName, parentNP):
        parentNP[0] = None
        return True
    
    def onDropToGround(self, evt=None):
        action = ActionDropSelectedToGround(self)
        self.actionMgr.push(action)
        action()
    
    def dropSelectedToGround(self):
        selected = base.direct.selected.getSelectedAsList()
        toDrop = set(selected)
        
        origParents = {}
        
        for np in toDrop:
            for otherNP in toDrop:
                if np != otherNP and otherNP.isAncestorOf(np):
                    origParents[np] = np.getParent()
                    np.wrtReparentTo(render)
                    break

        for np in toDrop:
            self.dropToGround(np)
                    
        for np, parent in origParents.iteritems():
            np.wrtReparentTo(parent)
            
    def dropToGround(self, np):
        self.groundCollide.setPos(np.getPos(render))
        
        self.groundCollideTraverser.traverse(render)
        
        if self.groundCollideHandler.getNumEntries() > 0:
            self.groundCollideHandler.sortEntries()
            for e in self.groundCollideHandler.getEntries():
                hitNP = e.getIntoNodePath()
                if hitNP.hasNetTag('OBJRoot'):
                    hitObj = hitNP.findNetTag('OBJRoot')
                    if hitObj.hasTag('LE-ground'):
                        np.setZ(render, e.getSurfacePoint(render).getZ())
                        return
    
        
                    
    def openScene(self, sceneName):
        self.ui.sceneGraphUI.reset()
        self.ui.soundUI.reset()
        sceneFile = self.currentProj.getScene(sceneName)
        #self.currentScene = sceneFile
        
        if(sceneName.strip().startswith("interior_")):
            self.setBackgroundColor(BGC_DARK_GREY)
        else:
            self.setBackgroundColor(BGC_LIGHT_BLUE)
        
        self.currentSceneName = sceneName
        f = Filename(sceneFile)
        f.setDirname(self.currentProj.dir.getFullpath())

        if os.path.exists(f.toOsSpecific()):
            self.fileMgr.loadFromFile(self.projDir + '/' +self.currentProj.getScene(self.currentSceneName).getFullpath())
        
        self.objectMgr.updateMainCharWidget() #[antonjs 4/14/11]
    
    def addScene(self):
        name, scenefile = self.currentProj.addScene()
        #create an empty sceneFile
        #cr
        doc = xml.dom.minidom.Document()
        root = doc.createElement("scene")
        doc.appendChild(root)
        root.appendChild(doc.createElement("objects"))
        root.appendChild(doc.createElement("layers"))
        root.appendChild(doc.createElement("sounds"))
        
        try:
            filename = self.projDir + '/' + scenefile.getFullpath()
            f = open(filename.toOsSpecific(), 'w')
            f.write(doc.toprettyxml())
            f.close()
        except IOError:
            raise SceneSaveError(filename.toOsSpecific())
        return name
        
    
    def removeScene(self, sceneName, delFile = False):
        toDelSceneFile = self.currentProj.getScene(sceneName)
        self.currentProj.removeScene(sceneName, delFile)
        #if the scene to remove the current Scene get the 
        if(self.currentSceneName == sceneName):
            self.openScene(self.currentProj.sceneName)
        #self.ui.onSave()
        #self.currentScene = self.currentProj.getOpeningScene()
        
        if(self.saved):
            self.save()
            
    def renameScene(self, name, newName):
        self.currentProj.renameScene(name,newName)
        if(self.currentSceneName == name):
            self.currentSceneName = newName
            if(newName.strip().startswith("interior_")):
                self.setBackgroundColor(BGC_DARK_GREY)
            else:
                self.setBackgroundColor(BGC_LIGHT_BLUE)
            
    def addEmptyTerrain(self):
        no = 0
        name =  self.currentSceneName+'_terrain'+str(no)
        tempFilePath = base.le.lib.projDir.toOsSpecific() + '/' + name+ '.png'
        assetFilename = Filename(tempFilePath)
        
        targetFilename = Filename(assetFilename)
        targetFilename.setDirname(self.currentProj.dir.getFullpath()+'/Textures')
        
        while os.path.exists(targetFilename.toOsSpecific()):
            no += 1
            tempFilePath = base.le.lib.projDir.toOsSpecific() + '/' + name+str(no)+ '.png'
            assetFilename = Filename(tempFilePath)
            targetFilename = Filename(assetFilename)
            targetFilename.setDirname(self.currentProj.dir.getFullpath()+'/Textures')
            
        
        tempImage = PNMImage(513,513)
        tempImage.fill(.5,.5,.5)
        tempImage.write(assetFilename)  
        
        no = 0
        #add the new terrain to the library
        asset = Terrain(name, assetFilename)
        while(1):
            try:
                base.le.lib.addTerrain(asset, True)
                break
            except:
                pass
                no += 1
                name =  self.currentSceneName+'_terrain'+str(no)
                #tempFilePath = base.le.lib.projDir.toOsSpecific() + '/' + name+ '.png'
                #assetFilename = Filename(tempFilePath)
                asset = Terrain(name, assetFilename)
            else:
                break
                        
        base.le.ui.libraryUI.update()
            
        #== Remove the temporary source file
        tempFilename = Filename(tempFilePath)
        #print 'temporary file path to now delete: ' + tempFilename.toOsSpecific()
        os.remove(tempFilename.toOsSpecific())
        
        pos = Vec3(512*(-.5), 512*(-.5), -128)            
        action = ActionAddNewObj(self, "Terrains", name = "terrain_"+name + ':1', asset=asset, anims={}, parent=None, pos=pos)
        self.actionMgr.push(action)
        newobj = action()
        newobj.getNodePath().setScale(1.,1.,255)
    
    #Color should a Vec4
    def setBackgroundColor(self, color):
        for i in range(4):
            base.winList[i].setClearColor(color)