示例#1
0
 def ProcessImportsAndCreateScenes(self):
     from trinity.sceneRenderJobSpace import CreateSceneRenderJobSpace
     from trinity.eveSceneRenderJobInterior import CreateEveSceneRenderJobInterior
     from trinity.sceneRenderJobCharacters import CreateSceneRenderJobCharacters
     self.fisRenderJob = CreateSceneRenderJobSpace('SpaceScenePrimary')
     self.incarnaRenderJob = CreateEveSceneRenderJobInterior()
     self.characterRenderJob = CreateSceneRenderJobCharacters()
     self._CreateJobInterior()
     self._CreateJobCharCreation()
     self._CreateJobFiS()
示例#2
0
 def SetSecondaryScene(self, scene, sceneKey, sceneType):
     if sceneType == SCENE_TYPE_SPACE:
         newJob = self.secondaryJob is None
         if newJob:
             from trinity.sceneRenderJobSpace import CreateSceneRenderJobSpace
             self.secondaryJob = SceneContext(scene=scene,
                                              sceneKey=sceneKey,
                                              sceneType=sceneType)
             self.secondaryJob.renderJob = CreateSceneRenderJobSpace(
                 'SpaceSceneSecondary')
             self._CreateJobFiS(self.secondaryJob.renderJob)
         else:
             self.secondaryJob.scene = scene
             self.secondaryJob.sceneKey = sceneKey
         self.secondaryJob.renderJob.SetActiveScene(scene, sceneKey)
         self.secondaryJob.renderJob.UseFXAA(
             self.primaryJob.sceneType != SCENE_TYPE_SPACE)
         if newJob:
             self.secondaryJob.renderJob.Enable()
示例#3
0
class SceneManager(service.Service):
    __guid__ = 'svc.sceneManager'
    __exportedcalls__ = {
        'LoadScene': [],
        'GetScene': [],
        'GetIncarnaRenderJob': [],
        'EnableIncarnaRendering': []
    }
    __startupdependencies__ = ['settings', 'device']
    __notifyevents__ = ['OnGraphicSettingsChanged', 'OnSessionChanged']

    def Run(self, ms):
        service.Service.Run(self, ms)
        self.registeredScenes = {}
        self.registeredCameras = {}
        self.sceneLoadedEvents = {}
        self.registeredJobs = []
        self.cameraOffsetOverride = None
        self.uiBackdropScene = None
        self.ProcessImportsAndCreateScenes()
        self.primaryJob = SceneContext()
        self.secondaryJob = None
        self.loadingClearJob = trinity.CreateRenderJob()
        self.loadingClearJob.name = 'loadingClear'
        self.loadingClearJob.Clear((0, 0, 0, 1))
        self.loadingClearJob.enabled = False
        self.overlaySceneKeys = ['starmap', 'systemmap', 'planet', 'shipTree']
        self._sharedResources = {}
        self.routeVisualizer = None
        self.podDeathScene = None
        self.particlePoolManager = trinity.Tr2GPUParticlePoolManager()
        if '/skiprun' not in blue.pyos.GetArg():
            self._EnableLoadingClear()
        limit = gfxsettings.Get(gfxsettings.GFX_LOD_QUALITY) * 30
        self.explosionManager = util.ExplosionManager(limit)

    def ProcessImportsAndCreateScenes(self):
        from trinity.sceneRenderJobSpace import CreateSceneRenderJobSpace
        from trinity.eveSceneRenderJobInterior import CreateEveSceneRenderJobInterior
        from trinity.sceneRenderJobCharacters import CreateSceneRenderJobCharacters
        self.fisRenderJob = CreateSceneRenderJobSpace('SpaceScenePrimary')
        self.incarnaRenderJob = CreateEveSceneRenderJobInterior()
        self.characterRenderJob = CreateSceneRenderJobCharacters()
        self._CreateJobInterior()
        self._CreateJobCharCreation()
        self._CreateJobFiS()

    def _EnableLoadingClear(self):
        if not self.loadingClearJob.enabled:
            self.loadingClearJob.enabled = True
            trinity.renderJobs.recurring.insert(0, self.loadingClearJob)

    def _DisableLoadingClear(self):
        if self.loadingClearJob.enabled:
            self.loadingClearJob.enabled = False
            trinity.renderJobs.recurring.remove(self.loadingClearJob)

    def EnableIncarnaRendering(self):
        self._DisableLoadingClear()
        if self.secondaryJob is None:
            self.incarnaRenderJob.Enable()

    def RefreshJob(self, camera):
        """
            This function only really applies to Incarna where we need to seamlessly transition between multiple cameras.
            Instead of creating a new render job we replace the current render job's active camera with a new one.
        """
        sceneType = self.primaryJob.sceneType
        if sceneType == SCENE_TYPE_INTERIOR or sceneType == SCENE_TYPE_CHARACTER_CREATION:
            self.primaryJob.renderJob.SetActiveCamera(camera)
            uicore.uilib.SetSceneView(camera.viewMatrix,
                                      camera.projectionMatrix)

    def _CreateJobInterior(self):
        rj = self.incarnaRenderJob
        rj.CreateBasicRenderSteps()
        rj.EnableSceneUpdate(True)
        rj.EnableVisibilityQuery(True)

    def _CreateJobCharCreation(self):
        self.characterRenderJob.CreateBasicRenderSteps()
        self.characterRenderJob.EnableShadows(True)
        self.characterRenderJob.EnableScatter(True)
        self.characterRenderJob.EnableSculpting(True)
        self.characterRenderJob.Set2DBackdropScene(self.uiBackdropScene)

    def _CreateJobFiS(self, rj=None):
        if rj is None:
            rj = self.fisRenderJob
        rj.CreateBasicRenderSteps()
        rj.EnablePostProcessing(True)

    def GetFiSPostProcessingJob(self):
        return self.fisRenderJob.postProcessingJob

    def ApplyClothSimulationSettings(self):
        if 'character' not in sm.services:
            return
        if self.primaryJob.sceneType == SCENE_TYPE_INTERIOR:
            clothSimulation = sm.GetService('device').GetAppFeatureState(
                'Interior.clothSimulation', False)
            sm.GetService('character').EnableClothSimulation(clothSimulation)
        elif self.primaryJob.sceneType == SCENE_TYPE_CHARACTER_CREATION:
            clothSimulation = sm.GetService('device').GetAppFeatureState(
                'CharacterCreation.clothSimulation', True)
            sm.GetService('character').EnableClothSimulation(clothSimulation)

    def OnGraphicSettingsChanged(self, changes):
        self.incarnaRenderJob.SetSettingsBasedOnPerformancePreferences()
        self.fisRenderJob.SetSettingsBasedOnPerformancePreferences()
        self.characterRenderJob.SetSettingsBasedOnPerformancePreferences()
        if self.secondaryJob is not None:
            self.secondaryJob.renderJob.SetSettingsBasedOnPerformancePreferences(
            )
        for each in self.registeredJobs:
            each.object.SetSettingsBasedOnPerformancePreferences()

        if gfxsettings.GFX_INTERIOR_GRAPHICS_QUALITY in changes or gfxsettings.GFX_CHAR_CLOTH_SIMULATION in changes:
            self.ApplyClothSimulationSettings()
        if gfxsettings.GFX_LOD_QUALITY in changes:
            limit = gfxsettings.Get(gfxsettings.GFX_LOD_QUALITY) * 30
            self.explosionManager.SetLimit(limit)
        if gfxsettings.UI_CAMERA_OFFSET in changes:
            self.CheckCameraOffsets()
        if gfxsettings.UI_INCARNA_CAMERA_OFFSET in changes:
            sm.GetService('cameraClient').CheckCameraOffsets()
        if gfxsettings.UI_INCARNA_CAMERA_MOUSE_LOOK_SPEED in changes:
            sm.GetService('cameraClient').CheckMouseLookSpeed()
        if gfxsettings.MISC_LOAD_STATION_ENV in changes:
            val = gfxsettings.Get(gfxsettings.MISC_LOAD_STATION_ENV)
            if sm.GetService('viewState').IsViewActive('hangar') and not val:
                sm.GetService('station').ReloadLobby()
        if session.userid is not None:
            effectsEnabled = gfxsettings.Get(gfxsettings.UI_EFFECTS_ENABLED)
            if gfxsettings.UI_TRAILS_ENABLED in changes or gfxsettings.UI_EFFECTS_ENABLED in changes:
                trailsEnabled = effectsEnabled and gfxsettings.Get(
                    gfxsettings.UI_TRAILS_ENABLED)
                trinity.settings.SetValue('eveSpaceObjectTrailsEnabled',
                                          trailsEnabled)
            if gfxsettings.UI_GPU_PARTICLES_ENABLED in changes or gfxsettings.UI_EFFECTS_ENABLED in changes:
                gpuParticlesEnabled = effectsEnabled and gfxsettings.Get(
                    gfxsettings.UI_GPU_PARTICLES_ENABLED)
                trinity.settings.SetValue('gpuParticlesEnabled',
                                          gpuParticlesEnabled)
            if gfxsettings.UI_GODRAYS in changes:
                scene = self.GetRegisteredScene('default')
                if scene is not None and scene.sunBall is not None:
                    scene.sunBall.HandleGodraySetting()

    def GetIncarnaRenderJob(self):
        return self.incarnaRenderJob

    def GetIncarnaRenderJobVisualizationsMenu(self):
        """
        Visualisations are defined in the render job itself so pass them back out so that
        they can be presented in the menu.
        """
        return self.incarnaRenderJob.GetInsiderVisualizationMenu()

    def SetupIncarnaBackground(self, scene, sceneTranslation, sceneRotation):
        if scene is not None:
            self.incarnaRenderJob.SetBackgroundScene(scene)
            self.backgroundView = trinity.TriView()
            self.backgroundProjection = trinity.TriProjection()
            backGroundCameraUpdateFunction = self.incarnaRenderJob.GetBackgroundCameraUpdateFunction(
                self.backgroundView, self.backgroundProjection, 10.0, 40000.0,
                sceneTranslation, sceneRotation)
            self.incarnaRenderJob.SetBackgroundCameraViewAndProjection(
                self.backgroundView, self.backgroundProjection,
                backGroundCameraUpdateFunction)

    @telemetry.ZONE_METHOD
    def OnSessionChanged(self, isremote, session, change):
        """
        This will catch cases of someone transferring to another context without updating the scene type
        """
        if 'locationid' in change:
            newLocationID = change['locationid'][1]
            if util.IsSolarSystem(
                    newLocationID
            ) and self.primaryJob.sceneType != SCENE_TYPE_SPACE:
                log.LogWarn(
                    'SceneManager: I detected a session change into space but no one has bothered to update my scene type!'
                )
                self.SetSceneType(SCENE_TYPE_SPACE)

    @telemetry.ZONE_METHOD
    def SetSceneType(self, sceneType):
        if self.primaryJob.sceneType == sceneType:
            if sceneType == SCENE_TYPE_INTERIOR:
                self._EnableLoadingClear()
            return
        self.primaryJob = SceneContext(sceneType=sceneType)
        if sceneType == SCENE_TYPE_INTERIOR:
            log.LogInfo('Setting up WiS interior scene rendering')
            self.primaryJob.renderJob = self.incarnaRenderJob
            self.characterRenderJob.Disable()
            self.fisRenderJob.SetActiveScene(None)
            self.fisRenderJob.Disable()
            for each in self.registeredJobs:
                each.object.UseFXAA(True)

            self.ApplyClothSimulationSettings()
            if getattr(self.secondaryJob, 'sceneType',
                       None) == SCENE_TYPE_SPACE:
                self.secondaryJob.renderJob.UseFXAA(True)
            else:
                self._EnableLoadingClear()
        elif sceneType == SCENE_TYPE_CHARACTER_CREATION:
            log.LogInfo('Setting up character creation scene rendering')
            self.primaryJob.renderJob = self.characterRenderJob
            self.incarnaRenderJob.SetScene(None)
            self.incarnaRenderJob.SetBackgroundScene(None)
            self.incarnaRenderJob.Disable()
            self.fisRenderJob.SetActiveScene(None)
            self.fisRenderJob.Disable()
            self.ApplyClothSimulationSettings()
            self._DisableLoadingClear()
            self.characterRenderJob.Enable()
        elif sceneType == SCENE_TYPE_SPACE:
            log.LogInfo('Setting up space scene rendering')
            self.primaryJob.renderJob = self.fisRenderJob
            self.incarnaRenderJob.SetScene(None)
            self.incarnaRenderJob.SetBackgroundScene(None)
            self.incarnaRenderJob.Disable()
            self.characterRenderJob.SetScene(None)
            self.characterRenderJob.Disable()
            self.fisRenderJob.UseFXAA(False)
            for each in self.registeredJobs:
                each.object.UseFXAA(False)

            self._DisableLoadingClear()
            if getattr(self.secondaryJob, 'sceneType',
                       None) == SCENE_TYPE_SPACE:
                self.secondaryJob.renderJob.UseFXAA(False)
            if self.secondaryJob is None:
                self.fisRenderJob.Enable()

    @telemetry.ZONE_METHOD
    def Initialize(self, scene):
        self.uiBackdropScene = trinity.Tr2Sprite2dScene()
        self.uiBackdropScene.isFullscreen = True
        self.uiBackdropScene.backgroundColor = (0, 0, 0, 1)
        self.characterRenderJob.Set2DBackdropScene(self.uiBackdropScene)
        self.primaryJob = SceneContext(scene=scene,
                                       renderJob=self.fisRenderJob)

    def _ApplyCamera(self, jobContext, camera):
        jobContext.camera = camera
        if jobContext.renderJob is not None:
            if isinstance(camera, util.Camera):
                jobContext.renderJob.SetActiveCamera(None, camera.viewMatrix,
                                                     camera.projectionMatrix)
            else:
                jobContext.renderJob.SetActiveCamera(camera)

    @telemetry.ZONE_METHOD
    def SetActiveCamera(self, camera):
        if self.secondaryJob is None:
            self._ApplyCamera(self.primaryJob, camera)
        else:
            self._ApplyCamera(self.secondaryJob, camera)
        uicore.uilib.SetSceneCamera(camera)

    def _SetActiveCameraForScene(self, camera, sceneKey):
        if self.secondaryJob is not None and self.secondaryJob.sceneKey == sceneKey:
            self.SetActiveCamera(camera)
        elif self.primaryJob.sceneKey == sceneKey:
            self._ApplyCamera(self.primaryJob, camera)
            if self.secondaryJob is None:
                uicore.uilib.SetSceneCamera(camera)

    @telemetry.ZONE_METHOD
    def SetSecondaryScene(self, scene, sceneKey, sceneType):
        if sceneType == SCENE_TYPE_SPACE:
            newJob = self.secondaryJob is None
            if newJob:
                from trinity.sceneRenderJobSpace import CreateSceneRenderJobSpace
                self.secondaryJob = SceneContext(scene=scene,
                                                 sceneKey=sceneKey,
                                                 sceneType=sceneType)
                self.secondaryJob.renderJob = CreateSceneRenderJobSpace(
                    'SpaceSceneSecondary')
                self._CreateJobFiS(self.secondaryJob.renderJob)
            else:
                self.secondaryJob.scene = scene
                self.secondaryJob.sceneKey = sceneKey
            self.secondaryJob.renderJob.SetActiveScene(scene, sceneKey)
            self.secondaryJob.renderJob.UseFXAA(
                self.primaryJob.sceneType != SCENE_TYPE_SPACE)
            if newJob:
                self.secondaryJob.renderJob.Enable()

    def ClearSecondaryScene(self):
        if self.secondaryJob is None:
            return
        if self.secondaryJob.renderJob is not None:
            self.secondaryJob.renderJob.Disable()
        self.secondaryJob = None

    def SetActiveScene(self, scene, sceneKey=None):
        sceneType = SCENE_TYPE_INTERIOR
        if getattr(scene, '__bluetype__', None) == 'trinity.EveSpaceScene':
            sceneType = SCENE_TYPE_SPACE
        if sceneKey in self.overlaySceneKeys:
            self.primaryJob.renderJob.SuspendRendering()
            self.SetSecondaryScene(scene, sceneKey, sceneType)
        elif sceneType == SCENE_TYPE_SPACE:
            self.primaryJob.sceneKey = sceneKey
            self.primaryJob.scene = scene
            self.primaryJob.renderJob.SetActiveScene(scene, sceneKey)
        else:
            self.primaryJob.scene = scene
            self.primaryJob.renderJob.SetScene(scene)

    def RegisterJob(self, job):
        wr = blue.BluePythonWeakRef(job)
        if self.primaryJob.sceneType == SCENE_TYPE_INTERIOR:
            job.UseFXAA(True)

        def ClearDereferenced():
            self.registeredJobs.remove(wr)

        wr.callback = ClearDereferenced
        self.registeredJobs.append(wr)

    def GetRegisteredCamera(self, key, defaultOnActiveCamera=0):
        if key in self.registeredCameras:
            return self.registeredCameras[key]
        if defaultOnActiveCamera:
            if self.secondaryJob is not None:
                return self.secondaryJob.camera
            return self.primaryJob.camera
        self.LogNotice('No camera registered for:', key,
                       self.registeredCameras)

    def UnregisterCamera(self, key):
        if key in self.registeredCameras:
            self.LogNotice('sceneManager::UnregisterCamera', key,
                           self.registeredCameras[key])
            del self.registeredCameras[key]

    def RegisterCamera(self, key, camera):
        self.LogNotice('sceneManager::RegisterCamera', key, camera)
        self.registeredCameras[key] = camera
        self.SetCameraOffset(camera)

    def SetCameraOffset(self, camera):
        cameraOffsetOverride = self.cameraOffsetOverride
        if cameraOffsetOverride:
            camera.centerOffset = cameraOffsetOverride * -0.01
        else:
            camera.centerOffset = gfxsettings.Get(
                gfxsettings.UI_CAMERA_OFFSET) * -0.01
        defaultCamera = self.GetRegisteredCamera('default')
        if defaultCamera and camera is defaultCamera:
            sm.ScatterEvent('OnSetCameraOffset', camera, camera.centerOffset)

    def SetCameraOffsetOverride(self, cameraOffsetOverride):
        self.cameraOffsetOverride = cameraOffsetOverride
        self.CheckCameraOffsets()

    def GetCameraOffset(self, cameraID):
        camera = self.GetRegisteredCamera(cameraID)
        if camera:
            return camera.centerOffset
        return 0.0

    def CheckCameraOffsets(self):
        for cam in self.registeredCameras.itervalues():
            self.SetCameraOffset(cam)

    def UnregisterScene(self, key):
        if key in self.registeredScenes:
            del self.registeredScenes[key]

    def RegisterScene(self, scene, key):
        self.registeredScenes[key] = scene

    def GetRegisteredScene(self, key, defaultOnActiveScene=0):
        if key in self.registeredScenes:
            return self.registeredScenes[key]
        if key in self.sceneLoadedEvents and not self.sceneLoadedEvents[
                key].is_set():
            self.sceneLoadedEvents[key].wait()
            return self.registeredScenes[key]
        if defaultOnActiveScene:
            return self.primaryJob.scene

    def SetRegisteredScenes(self, key):
        """
        Register two scenes at once. Will skip scene if it does not exist.
        """
        if key == 'default' and self.secondaryJob is not None:
            if self.primaryJob.renderJob.enabled:
                self.primaryJob.renderJob.Start()
            else:
                self.primaryJob.renderJob.Enable()
            self.ClearSecondaryScene()
        if self.primaryJob.sceneType != SCENE_TYPE_INTERIOR or key in self.overlaySceneKeys:
            scene = self.registeredScenes.get(key, None)
            camera = self.registeredCameras.get(key, None)
            self.SetActiveScene(scene, key)
            if camera:
                self.SetActiveCamera(camera)

    def GetActiveScene(self):
        """
        This is a temporary function used for picking in Scene while we are transitioning
        over.
        """
        if self.secondaryJob is not None:
            return self.secondaryJob.scene
        return self.primaryJob.scene

    def Get2DBackdropScene(self):
        return self.uiBackdropScene

    @telemetry.ZONE_METHOD
    def Show2DBackdropScene(self, updateRenderJob=False):
        self.showUIBackdropScene = True
        if updateRenderJob:
            self.characterRenderJob.Set2DBackdropScene(self.uiBackdropScene)

    @telemetry.ZONE_METHOD
    def Hide2DBackdropScene(self, updateRenderJob=False):
        self.showUIBackdropScene = False
        if updateRenderJob:
            self.characterRenderJob.Set2DBackdropScene(None)

    def GetScene(self, location=None):
        """
        location: optional (systemID, constellationID, regionID) tuple, defaults to current location
        return a scene for the location
        """
        if location is None:
            location = (eve.session.solarsystemid2,
                        eve.session.constellationid, eve.session.regionid)
        resPath = cfg.GetNebula(*location)
        return resPath

    def GetSceneForSystem(self, solarSystemID):
        _, regionID, constellationID, _, _ = sm.GetService(
            'map').GetParentLocationID(solarSystemID)
        return self.GetScene((solarSystemID, constellationID, regionID))

    def GetNebulaPathForSystem(self, solarSystemID):
        scene = trinity.Load(self.GetSceneForSystem(solarSystemID))
        return scene.envMapResPath

    def DeriveTextureFromSceneName(self, scenePath):
        """
        This method loads the scene to get the envMap1ResPath which is then returned.
        """
        scene = trinity.Load(scenePath)
        if scene is None:
            return ''
        return scene.envMap1ResPath

    def CleanupSpaceResources(self):
        """ Clears resources shared by space scenes, like the dustfield. """
        self._sharedResources = {}

    def _GetSharedResource(self, path, key=None):
        """ Intended to share things like stars, background effect, dustfield etc between inflight scenes. """
        comboKey = (path, key)
        if comboKey not in self._sharedResources:
            self._sharedResources[comboKey] = trinity.Load(path)
        return self._sharedResources[comboKey]

    def _PrepareBackgroundLandscapes(self,
                                     scene,
                                     solarSystemID,
                                     constellationID=None):
        starSeed = 0
        securityStatus = 1
        if constellationID is None:
            constellationID = sm.GetService(
                'map').GetConstellationForSolarSystem(solarSystemID)
        if bool(solarSystemID) and bool(constellationID):
            starSeed = int(constellationID)
            securityStatus = sm.GetService('map').GetSecurityStatus(
                solarSystemID)
        if not gfxutils.BlockStarfieldOnLionOSX():
            scene.starfield = self._GetSharedResource(
                'res:/dx9/scene/starfield/spritestars.red')
            if scene.starfield is not None:
                scene.starfield.seed = starSeed
                scene.starfield.minDist = 40
                scene.starfield.maxDist = 80
                if util.IsWormholeSystem(solarSystemID):
                    scene.starfield.numStars = 0
                else:
                    scene.starfield.numStars = 500 + int(250 * securityStatus)
        if scene.backgroundEffect is None:
            scene.backgroundEffect = self._GetSharedResource(
                'res:/dx9/scene/starfield/starfieldNebula.red')
            node = nodemanager.FindNode(scene.backgroundEffect.resources,
                                        'NebulaMap',
                                        'trinity.TriTexture2DParameter')
            if node is not None:
                node.resourcePath = scene.envMap1ResPath
        scene.backgroundRenderingEnabled = True

    def _SetupUniverseStars(self, scene, solarsystemID):
        if gfxsettings.Get(
                gfxsettings.UI_EFFECTS_ENABLED) and solarsystemID is not None:
            universe = self._GetSharedResource(
                'res:/dx9/scene/starfield/universe.red')
            scene.backgroundObjects.append(universe)
            here = sm.GetService('map').GetItem(solarsystemID)
            if here:
                scale = 10000000000.0
                position = (here.x / scale, here.y / scale, -here.z / scale)
                universe.children[0].translation = position

    def ApplySolarsystemAttributes(self, scene, camera, solarsystemID=None):
        """ Setup solarsystem stuff, stars, route etc """
        if solarsystemID is None:
            solarsystemID = session.solarsystemid
        if scene.dustfield is None:
            scene.dustfield = self._GetSharedResource(
                'res:/dx9/scene/dustfield.red')
        scene.dustfieldConstraint = scene.dustfield.Find(
            'trinity.EveDustfieldConstraint')[0]
        if scene.dustfieldConstraint is not None:
            scene.dustfieldConstraint.camera = camera
        scene.sunDiffuseColor = (1.5, 1.5, 1.5, 1.0)
        self._SetupUniverseStars(scene, solarsystemID)
        self._PrepareBackgroundLandscapes(scene, solarsystemID)
        scene.gpuParticlePoolManager = self.particlePoolManager

    def ApplySceneInflightAttributes(self, scene, camera, bp=None):
        """ Apply attributes that require the ballpark being ready """
        if bp is None:
            bp = sm.GetService('michelle').GetBallpark()
        scene.ballpark = bp
        if camera and bp is not None:
            myShipBall = bp.GetBallById(bp.ego)
            vel = geo2.Vector(myShipBall.vx, myShipBall.vy, myShipBall.vz)
            if geo2.Vec3Length(vel) > 0.0:
                vel = geo2.Vec3Normalize(vel)
                pitch = asin(-vel[1])
                yaw = atan2(vel[0], vel[2])
                yaw = yaw - 0.3
                pitch = pitch - 0.15
                camera.SetOrbit(yaw, pitch)

    def ApplyScene(self, scene, camera, registerKey=None):
        """ Set the active scene and camera to the ones provided and store under the registerKey if provided. """
        if registerKey is not None:
            self.RegisterCamera(registerKey, camera)
            self.RegisterScene(scene, registerKey)
            self.SetActiveScene(scene, registerKey)
            if camera:
                self._SetActiveCameraForScene(camera, registerKey)
        else:
            self.SetActiveScene(scene, registerKey)
            if camera:
                self.SetActiveCamera(camera)
        sm.ScatterEvent('OnLoadScene', scene, registerKey)

    def _GetCamera(self, key, setupCamera):
        if key == 'default':
            return sm.GetService('camera').GetSpaceCamera()
        camera = self.GetRegisteredCamera(key)
        if setupCamera and camera is None:
            camera = self._GetSharedResource('res:/dx9/scene/camera.red', key)
            camera.noise = False
        if camera:
            evecamera.ApplyCameraDefaults(camera)
            if key == 'default':
                camera.audio2Listener = audio2.GetListener(0)
        return camera

    @telemetry.ZONE_METHOD
    def LoadScene(self,
                  scenefile,
                  inflight=0,
                  registerKey=None,
                  setupCamera=True,
                  applyScene=True):
        scene = None
        camera = None
        try:
            if registerKey:
                self.sceneLoadedEvents[registerKey] = locks.Event(registerKey)
            self.SetSceneType(SCENE_TYPE_SPACE)
            sceneFromFile = trinity.Load(scenefile)
            if sceneFromFile is None:
                return
            scene = sceneFromFile
            camera = self._GetCamera(registerKey, setupCamera)
            if inflight:
                self.ApplySolarsystemAttributes(scene, camera)
                self.ApplySceneInflightAttributes(scene, camera)
            if applyScene:
                self.ApplyScene(scene, camera, registerKey)
        except Exception:
            log.LogException('sceneManager::LoadScene')
            sys.exc_clear()
        finally:
            if registerKey and registerKey in self.sceneLoadedEvents:
                self.sceneLoadedEvents.pop(registerKey).set()

        return (scene, camera)
示例#4
0
class SceneManager(service.Service):
    __guid__ = 'svc.sceneManager'
    __exportedcalls__ = {
        'LoadScene': [],
        'GetScene': [],
        'GetIncarnaRenderJob': [],
        'EnableIncarnaRendering': []
    }
    __startupdependencies__ = ['settings', 'device']
    __notifyevents__ = [
        'OnGraphicSettingsChanged', 'OnSessionChanged', 'OnCameraLookAt'
    ]

    def Run(self, ms):
        service.Service.Run(self, ms)
        self.registeredScenes = {}
        self.registeredCameras = {}
        self.sceneLoadedEvents = {}
        self.registeredJobs = []
        self.cameraOffsetOverride = None
        self.uiBackdropScene = None
        self.ProcessImportsAndCreateScenes()
        self.primaryJob = SceneContext()
        self.secondaryJob = None
        self.loadingClearJob = trinity.CreateRenderJob()
        self.loadingClearJob.name = 'loadingClear'
        self.loadingClearJob.Clear((0, 0, 0, 1))
        self.loadingClearJob.enabled = False
        self.overlaySceneKeys = [
            ViewState.StarMap, ViewState.SystemMap, ViewState.Planet,
            ViewState.ShipTree, ViewState.DockPanel
        ]
        self._sharedResources = {}
        self.routeVisualizer = None
        self.podDeathScene = None
        self._persistedSpaceObjects = {}
        self._updateCameras = []
        if '/skiprun' not in blue.pyos.GetArg():
            self._EnableLoadingClear()
        limit = gfxsettings.Get(gfxsettings.GFX_LOD_QUALITY) * 30
        self.explosionManager = util.ExplosionManager(limit)

    def ProcessImportsAndCreateScenes(self):
        from trinity.sceneRenderJobSpace import CreateSceneRenderJobSpace
        from trinity.eveSceneRenderJobInterior import CreateEveSceneRenderJobInterior
        from trinity.sceneRenderJobCharacters import CreateSceneRenderJobCharacters
        self.fisRenderJob = CreateSceneRenderJobSpace('SpaceScenePrimary')
        self.incarnaRenderJob = CreateEveSceneRenderJobInterior()
        self.characterRenderJob = CreateSceneRenderJobCharacters()
        self._CreateJobInterior()
        self._CreateJobCharCreation()
        self._CreateJobFiS()

    def _UpdateActiveCamera(self):
        cam = self.GetActiveCamera()
        if cam:
            self._UpdateCamera(cam)
        for camera in self._updateCameras:
            self._UpdateCamera(camera)

    def _UpdateCamera(self, camera):
        try:
            camera._Update()
        except DestinyBallInvalid as e:
            log.LogWarn('DestinyBallInvalid while updating camera')
        except Exception:
            LogException('Unexpected exception raised from UpdateCamera')

    def RegisterForCameraUpdate(self, camera):
        if camera not in self._updateCameras:
            self._updateCameras.append(camera)

    def UnregisterForCameraUpdate(self, camera):
        if camera in self._updateCameras:
            self._updateCameras.remove(camera)

    def _EnableLoadingClear(self):
        if not self.loadingClearJob.enabled:
            self.loadingClearJob.enabled = True
            trinity.renderJobs.recurring.insert(0, self.loadingClearJob)

    def _DisableLoadingClear(self):
        if self.loadingClearJob.enabled:
            self.loadingClearJob.enabled = False
            trinity.renderJobs.recurring.remove(self.loadingClearJob)

    def EnableIncarnaRendering(self):
        self._DisableLoadingClear()
        if self.secondaryJob is None:
            self.incarnaRenderJob.Enable()

    def RefreshJob(self, camera):
        sceneType = self.primaryJob.sceneType
        if sceneType == SCENE_TYPE_INTERIOR or sceneType == SCENE_TYPE_CHARACTER_CREATION:
            self.primaryJob.renderJob.SetActiveCamera(camera)
            uicore.uilib.SetSceneView(camera.viewMatrix,
                                      camera.projectionMatrix)

    def DeactivateFISCamera(self):
        currCam = self.GetActivePrimaryCamera()
        if currCam and hasattr(currCam, 'OnDeactivated'):
            currCam.OnDeactivated()

    def _CreateJobInterior(self):
        rj = self.incarnaRenderJob
        rj.CreateBasicRenderSteps()
        rj.EnableSceneUpdate(True)
        rj.EnableVisibilityQuery(True)
        rj.AddStep('CAMERA_UPDATE',
                   trinity.TriStepPythonCB(self._UpdateActiveCamera))

    def _CreateJobCharCreation(self):
        self.characterRenderJob.CreateBasicRenderSteps()
        self.characterRenderJob.EnableShadows(True)
        self.characterRenderJob.EnableScatter(True)
        self.characterRenderJob.EnableSculpting(True)
        self.characterRenderJob.Set2DBackdropScene(self.uiBackdropScene)

    def _CreateJobFiS(self, rj=None):
        if rj is None:
            rj = self.fisRenderJob
        rj.CreateBasicRenderSteps()
        rj.EnablePostProcessing(True)
        rj.AddStep('CAMERA_UPDATE',
                   trinity.TriStepPythonCB(self._UpdateActiveCamera))

    def GetFiSPostProcessingJob(self):
        return self.fisRenderJob.postProcessingJob

    def ApplyClothSimulationSettings(self):
        if 'character' not in sm.services:
            return
        if self.primaryJob.sceneType == SCENE_TYPE_INTERIOR:
            clothSimulation = sm.GetService('device').GetAppFeatureState(
                'Interior.clothSimulation', False)
            sm.GetService('character').EnableClothSimulation(clothSimulation)
        elif self.primaryJob.sceneType == SCENE_TYPE_CHARACTER_CREATION:
            clothSimulation = sm.GetService('device').GetAppFeatureState(
                'CharacterCreation.clothSimulation', True)
            sm.GetService('character').EnableClothSimulation(clothSimulation)

    def OnGraphicSettingsChanged(self, changes):
        self.incarnaRenderJob.SetSettingsBasedOnPerformancePreferences()
        self.fisRenderJob.SetSettingsBasedOnPerformancePreferences()
        self.characterRenderJob.SetSettingsBasedOnPerformancePreferences()
        if self.secondaryJob is not None:
            self.secondaryJob.renderJob.SetSettingsBasedOnPerformancePreferences(
            )
        for each in self.registeredJobs:
            each.object.SetSettingsBasedOnPerformancePreferences()

        if gfxsettings.GFX_INTERIOR_GRAPHICS_QUALITY in changes or gfxsettings.GFX_CHAR_CLOTH_SIMULATION in changes:
            self.ApplyClothSimulationSettings()
        if gfxsettings.GFX_LOD_QUALITY in changes:
            limit = gfxsettings.Get(gfxsettings.GFX_LOD_QUALITY) * 30
            self.explosionManager.SetLimit(limit)
        if gfxsettings.UI_CAMERA_OFFSET in changes:
            self.UpdateCameraOffset()
            sm.GetService('cameraClient').UpdateCameraOffset()
        if gfxsettings.UI_CAMERA_INERTIA in changes:
            sm.GetService('cameraClient').CheckMouseLookSpeed()
        if session.userid is not None:
            effectsEnabled = gfxsettings.Get(gfxsettings.UI_EFFECTS_ENABLED)
            if gfxsettings.UI_TRAILS_ENABLED in changes or gfxsettings.UI_EFFECTS_ENABLED in changes:
                trailsEnabled = effectsEnabled and gfxsettings.Get(
                    gfxsettings.UI_TRAILS_ENABLED)
                trinity.settings.SetValue('eveSpaceObjectTrailsEnabled',
                                          trailsEnabled)
            if gfxsettings.UI_GODRAYS in changes:
                scene = self.GetRegisteredScene('default')
                if scene is not None and scene.sunBall is not None:
                    scene.sunBall.HandleGodraySetting()

    def GetIncarnaRenderJob(self):
        return self.incarnaRenderJob

    def GetIncarnaRenderJobVisualizationsMenu(self):
        return self.incarnaRenderJob.GetInsiderVisualizationMenu()

    def SetupIncarnaBackground(self, scene, sceneTranslation, sceneRotation):
        if scene is not None:
            self.incarnaRenderJob.SetBackgroundScene(scene)
            self.backgroundView = trinity.TriView()
            self.backgroundProjection = trinity.TriProjection()
            backGroundCameraUpdateFunction = self.incarnaRenderJob.GetBackgroundCameraUpdateFunction(
                self.backgroundView, self.backgroundProjection, 10.0, 40000.0,
                sceneTranslation, sceneRotation)
            self.incarnaRenderJob.SetBackgroundCameraViewAndProjection(
                self.backgroundView, self.backgroundProjection,
                backGroundCameraUpdateFunction)

    @telemetry.ZONE_METHOD
    def OnSessionChanged(self, isremote, session, change):
        if 'locationid' in change:
            newLocationID = change['locationid'][1]
            if util.IsSolarSystem(
                    newLocationID
            ) and self.primaryJob.sceneType != SCENE_TYPE_SPACE:
                log.LogWarn(
                    'SceneManager: I detected a session change into space but no one has bothered to update my scene type!'
                )
                self.SetSceneType(SCENE_TYPE_SPACE)

    @telemetry.ZONE_METHOD
    def SetSceneType(self, sceneType):
        if self.primaryJob.sceneType == sceneType:
            if sceneType == SCENE_TYPE_INTERIOR:
                self._EnableLoadingClear()
            return
        if sceneType != SCENE_TYPE_SPACE:
            self.DeactivateFISCamera()
        self.primaryJob = SceneContext(sceneType=sceneType)
        if sceneType == SCENE_TYPE_INTERIOR:
            log.LogInfo('Setting up WiS interior scene rendering')
            self.primaryJob.renderJob = self.incarnaRenderJob
            self.characterRenderJob.Disable()
            self.fisRenderJob.SetActiveScene(None)
            self.fisRenderJob.Disable()
            for each in self.registeredJobs:
                each.object.UseFXAA(True)

            self.ApplyClothSimulationSettings()
            if getattr(self.secondaryJob, 'sceneType',
                       None) == SCENE_TYPE_SPACE:
                self.secondaryJob.renderJob.UseFXAA(True)
            else:
                self._EnableLoadingClear()
        elif sceneType == SCENE_TYPE_CHARACTER_CREATION:
            log.LogInfo('Setting up character creation scene rendering')
            self.primaryJob.renderJob = self.characterRenderJob
            self.incarnaRenderJob.SetScene(None)
            self.incarnaRenderJob.SetBackgroundScene(None)
            self.incarnaRenderJob.Disable()
            self.fisRenderJob.SetActiveScene(None)
            self.fisRenderJob.Disable()
            self.ApplyClothSimulationSettings()
            self._DisableLoadingClear()
            self.characterRenderJob.Enable()
        elif sceneType == SCENE_TYPE_SPACE:
            log.LogInfo('Setting up space scene rendering')
            self.primaryJob.renderJob = self.fisRenderJob
            self.incarnaRenderJob.SetScene(None)
            self.incarnaRenderJob.SetBackgroundScene(None)
            self.incarnaRenderJob.Disable()
            self.characterRenderJob.SetScene(None)
            self.characterRenderJob.Disable()
            self.fisRenderJob.UseFXAA(False)
            for each in self.registeredJobs:
                each.object.UseFXAA(False)

            self._DisableLoadingClear()
            if getattr(self.secondaryJob, 'sceneType',
                       None) == SCENE_TYPE_SPACE:
                self.secondaryJob.renderJob.UseFXAA(False)
            if self.secondaryJob is None:
                self.fisRenderJob.Enable()

    @telemetry.ZONE_METHOD
    def Initialize(self, scene):
        self.uiBackdropScene = trinity.Tr2Sprite2dScene()
        self.uiBackdropScene.isFullscreen = True
        self.uiBackdropScene.backgroundColor = (0, 0, 0, 1)
        self.characterRenderJob.Set2DBackdropScene(self.uiBackdropScene)
        self.primaryJob = SceneContext(scene=scene,
                                       renderJob=self.fisRenderJob)

    def _ApplyCamera(self, jobContext, camera, **kwargs):
        if jobContext == self.primaryJob:
            currCam = self.GetActivePrimaryCamera()
        else:
            currCam = self.GetActiveSecondaryCamera()
        jobContext.camera = camera
        if jobContext.renderJob is not None:
            if isinstance(camera, CameraBase):
                jobContext.renderJob.SetActiveCamera(camera.GetTrinityCamera())
            elif isinstance(camera, trinity.EveCamera):
                jobContext.renderJob.SetActiveCamera(camera)
            else:
                jobContext.renderJob.SetActiveCamera(None, camera.viewMatrix,
                                                     camera.projectionMatrix)
        if hasattr(camera, 'cameraID'):
            sm.ScatterEvent('OnActiveCameraChanged', camera.cameraID)
            if camera.cameraID in evecamera.INSPACE_CAMERAS:
                self.UpdateSceneCameraReferences(camera)
        if hasattr(camera, 'OnActivated'):
            camera.OnActivated(lastCamera=currCam, **kwargs)
        if currCam and hasattr(currCam, 'OnDeactivated') and currCam != camera:
            currCam.OnDeactivated()
        self.UpdateBracketProjectionCamera()

    def OnCameraLookAt(self, isEgo, itemID):
        scene = self.GetRegisteredScene('default')
        if scene is None:
            return
        if scene.dustfield is not None:
            scene.dustfield.display = isEgo
        if scene.cloudfieldConstraint is not None:
            scene.cloudfieldConstraint.applyMovement = isEgo
            if isEgo:
                scene.cloudfield.particleEmitters[0].rate = 400
            else:
                scene.cloudfield.particleEmitters[0].rate = 0

    def UpdateSceneCameraReferences(self, camera):
        scene = self.GetRegisteredScene('default')
        if not scene:
            return
        if scene.dustfieldConstraint:
            scene.dustfieldConstraint.cameraView = camera.viewMatrix
        if scene.cloudfieldConstraint:
            scene.cloudfieldConstraint.cameraView = camera.viewMatrix
        for distanceField in scene.distanceFields:
            distanceField.cameraView = camera.viewMatrix

    def UpdateBracketProjectionCamera(self):
        camera = self.GetActiveCamera()
        if camera:
            uicore.uilib.SetSceneCamera(camera)

    def SetPrimaryCamera(self, cameraID, **kwargs):
        activeCam = self.GetActivePrimaryCamera()
        if activeCam and activeCam.cameraID == cameraID:
            return
        camera = self.GetOrCreateCamera(cameraID)
        self._ApplyCamera(self.primaryJob, camera, **kwargs)
        return camera

    def SetSecondaryCamera(self, cameraID, **kwargs):
        activeCam = self.GetActiveSecondaryCamera()
        if activeCam and activeCam.cameraID == cameraID:
            return
        camera = self.GetOrCreateCamera(cameraID)
        self._ApplyCamera(self.secondaryJob, camera, **kwargs)
        return camera

    @telemetry.ZONE_METHOD
    def SetSecondaryScene(self, scene, sceneKey, sceneType):
        if sceneType == SCENE_TYPE_SPACE:
            newJob = self.secondaryJob is None
            if newJob:
                from trinity.sceneRenderJobSpace import CreateSceneRenderJobSpace
                self.secondaryJob = SceneContext(scene=scene,
                                                 sceneKey=sceneKey,
                                                 sceneType=sceneType)
                self.secondaryJob.renderJob = CreateSceneRenderJobSpace(
                    'SpaceSceneSecondary')
                self._CreateJobFiS(self.secondaryJob.renderJob)
            else:
                self.secondaryJob.scene = scene
                self.secondaryJob.sceneKey = sceneKey
            self.secondaryJob.renderJob.SetActiveScene(scene, sceneKey)
            self.secondaryJob.renderJob.UseFXAA(
                self.primaryJob.sceneType != SCENE_TYPE_SPACE)
            if newJob:
                self.secondaryJob.renderJob.Enable()

    def ClearSecondaryScene(self):
        if self.secondaryJob is None:
            return
        if self.secondaryJob.renderJob is not None:
            self.secondaryJob.renderJob.Disable()
        self.secondaryJob = None

    def SetActiveScene(self, scene, sceneKey=None):
        sceneType = SCENE_TYPE_INTERIOR
        if getattr(scene, '__bluetype__', None) == 'trinity.EveSpaceScene':
            sceneType = SCENE_TYPE_SPACE
        if sceneKey in self.overlaySceneKeys:
            self.primaryJob.renderJob.SuspendRendering()
            self.SetSecondaryScene(scene, sceneKey, sceneType)
        elif sceneType == SCENE_TYPE_SPACE:
            self.primaryJob.sceneKey = sceneKey
            self.primaryJob.scene = scene
            self.primaryJob.renderJob.SetActiveScene(scene, sceneKey)
        else:
            self.primaryJob.scene = scene
            self.primaryJob.renderJob.SetScene(scene)
        self.UpdateBracketProjectionCamera()

    def RegisterJob(self, job):
        wr = blue.BluePythonWeakRef(job)
        if self.primaryJob.sceneType == SCENE_TYPE_INTERIOR:
            job.UseFXAA(True)

        def ClearDereferenced():
            self.registeredJobs.remove(wr)

        wr.callback = ClearDereferenced
        self.registeredJobs.append(wr)

    def GetRegisteredCamera(self, key):
        if key in self.registeredCameras:
            return self.registeredCameras[key]
        self.LogNotice('No camera registered for:', key,
                       self.registeredCameras)

    def GetActiveSpaceCamera(self):
        return self.GetActivePrimaryCamera()

    def GetActivePrimaryCamera(self):
        return self.primaryJob.camera

    def GetActiveCamera(self):
        if self.secondaryJob is not None:
            return self.GetActiveSecondaryCamera()
        return self.GetActivePrimaryCamera()

    def GetActiveSecondaryCamera(self):
        return self.secondaryJob.camera

    def UnregisterCamera(self, key):
        if key in self.registeredCameras:
            self.LogNotice('sceneManager::UnregisterCamera', key,
                           self.registeredCameras[key])
            cam = self.registeredCameras[key]
            if cam == self.GetActiveCamera():
                sm.ScatterEvent('OnActiveCameraChanged', None)
            if cam and hasattr(cam, 'OnDeactivated'):
                cam.OnDeactivated()
            del self.registeredCameras[key]

    def RegisterCamera(self, camera):
        cameraID = camera.cameraID
        if cameraID in self.registeredCameras:
            return
        self.LogNotice('sceneManager::RegisterCamera', cameraID, camera)
        self.registeredCameras[camera.cameraID] = camera
        camera.centerOffset = self.GetCameraOffset()

    def GetCameraOffset(self):
        if self.cameraOffsetOverride:
            return self.cameraOffsetOverride * -0.01
        elif gfxsettings.IsInitialized(gfxsettings.SETTINGS_GROUP_UI):
            return gfxsettings.Get(gfxsettings.UI_CAMERA_OFFSET) * -0.01
        else:
            return 0.0

    def SetCameraOffsetOverride(self, cameraOffsetOverride):
        self.cameraOffsetOverride = cameraOffsetOverride
        self.UpdateCameraOffset()

    def UpdateCameraOffset(self):
        offset = self.GetCameraOffset()
        for cam in self.registeredCameras.itervalues():
            cam.centerOffset = offset

        sm.ScatterEvent('OnSetCameraOffset', offset)

    def UnregisterScene(self, key, ignoreCamera=False):
        if key in self.registeredScenes:
            del self.registeredScenes[key]
            if not ignoreCamera and key == 'default':
                cam = self.GetActivePrimaryCamera()
                if cam:
                    cam.OnDeactivated()

    def RegisterScene(self, scene, key):
        self.registeredScenes[key] = scene

    def GetRegisteredScene(self, key, defaultOnActiveScene=0):
        if key in self.registeredScenes:
            return self.registeredScenes[key]
        if self.IsLoadingScene(key):
            self.sceneLoadedEvents[key].wait()
            return self.registeredScenes[key]
        if defaultOnActiveScene:
            return self.primaryJob.scene

    def IsLoadingScene(self, key):
        return key in self.sceneLoadedEvents and not self.sceneLoadedEvents[
            key].is_set()

    def SetRegisteredScenes(self, key):
        if key == 'default' and self.secondaryJob is not None:
            if self.primaryJob.renderJob.enabled:
                self.primaryJob.renderJob.Start()
            else:
                self.primaryJob.renderJob.Enable()
            self.ClearSecondaryScene()
        if self.primaryJob.sceneType != SCENE_TYPE_INTERIOR or key in self.overlaySceneKeys:
            scene = self.registeredScenes.get(key, None)
            self.SetActiveScene(scene, key)

    def GetActiveScene(self):
        if self.secondaryJob is not None:
            return self.secondaryJob.scene
        return self.primaryJob.scene

    def Get2DBackdropScene(self):
        return self.uiBackdropScene

    @telemetry.ZONE_METHOD
    def Show2DBackdropScene(self, updateRenderJob=False):
        self.showUIBackdropScene = True
        if updateRenderJob:
            self.characterRenderJob.Set2DBackdropScene(self.uiBackdropScene)

    @telemetry.ZONE_METHOD
    def Hide2DBackdropScene(self, updateRenderJob=False):
        self.showUIBackdropScene = False
        if updateRenderJob:
            self.characterRenderJob.Set2DBackdropScene(None)

    def GetScene(self, location=None):
        if location is None:
            location = (eve.session.solarsystemid2,
                        eve.session.constellationid, eve.session.regionid)
        resPath = cfg.GetNebula(*location)
        return resPath

    def GetSceneForSystem(self, solarSystemID):
        _, regionID, constellationID, _, _ = sm.GetService(
            'map').GetParentLocationID(solarSystemID)
        return self.GetScene((solarSystemID, constellationID, regionID))

    def GetNebulaPathForSystem(self, solarSystemID):
        scene = trinity.Load(self.GetSceneForSystem(solarSystemID))
        return scene.envMapResPath

    def DeriveTextureFromSceneName(self, scenePath):
        scene = trinity.Load(scenePath)
        if scene is None:
            return ''
        return scene.envMap1ResPath

    def CleanupSpaceResources(self):
        self._sharedResources = {}

    def RegisterPersistentSpaceObject(self, key, object):
        if key in self._persistedSpaceObjects:
            self.RemovePersistentSpaceObject(key)
        self._persistedSpaceObjects[key] = object
        scene = self.GetRegisteredScene('default', False)
        if scene is not None:
            scene.objects.append(object)

    def GetPersistentSpaceObject(self, key):
        obj = None
        if key in self._persistedSpaceObjects:
            obj = self._persistedSpaceObjects[obj]
        return obj

    def RemovePersistentSpaceObject(self, key):
        obj = self._persistedSpaceObjects[key]
        scene = self.GetRegisteredScene('default', False)
        if scene is not None:
            scene.objects.fremove(obj)
        del self._persistedSpaceObjects[key]

    def _GetSharedResource(self, path, key=None):
        comboKey = (path, key)
        if comboKey not in self._sharedResources:
            self._sharedResources[comboKey] = trinity.Load(path)
        return self._sharedResources[comboKey]

    def _PrepareBackgroundLandscapes(self,
                                     scene,
                                     solarSystemID,
                                     constellationID=None):
        starSeed = 0
        securityStatus = 1
        if constellationID is None:
            constellationID = sm.GetService(
                'map').GetConstellationForSolarSystem(solarSystemID)
        if bool(solarSystemID) and bool(constellationID):
            starSeed = int(constellationID)
            securityStatus = sm.GetService('map').GetSecurityStatus(
                solarSystemID)
        scene.starfield = self._GetSharedResource(
            'res:/dx9/scene/starfield/spritestars.red')
        if scene.starfield is not None:
            scene.starfield.seed = starSeed
            scene.starfield.minDist = 40
            scene.starfield.maxDist = 80
            if util.IsWormholeSystem(solarSystemID):
                scene.starfield.numStars = 0
            else:
                scene.starfield.numStars = 500 + int(250 * securityStatus)

    def _SetupUniverseStars(self, scene, solarsystemID):
        if gfxsettings.Get(
                gfxsettings.UI_EFFECTS_ENABLED) and solarsystemID is not None:
            universe = self._GetSharedResource(
                'res:/dx9/scene/starfield/universe.red')
            scene.backgroundObjects.append(universe)
            here = sm.GetService('map').GetItem(solarsystemID)
            if here:
                scale = 10000000000.0
                position = (here.x / scale, here.y / scale, -here.z / scale)
                universe.children[0].translation = position

    def AddPersistentSpaceObjects(self, scene):
        for spaceObject in self._persistedSpaceObjects.values():
            scene.objects.append(spaceObject)

    def ApplySolarsystemAttributes(self, scene, camera, solarsystemID=None):
        if solarsystemID is None:
            solarsystemID = session.solarsystemid
        if scene.dustfield is None:
            scene.dustfield = self._GetSharedResource(
                'res:/dx9/scene/dustfield.red')
        scene.dustfieldConstraint = scene.dustfield.Find(
            'trinity.EveDustfieldConstraint')[0]
        if camera and scene.dustfieldConstraint is not None:
            scene.dustfieldConstraint.cameraView = camera.viewMatrix
        scene.sunDiffuseColor = (1.5, 1.5, 1.5, 1.0)
        self._SetupUniverseStars(scene, solarsystemID)
        self._PrepareBackgroundLandscapes(scene, solarsystemID)

    def ApplySceneInflightAttributes(self, scene, camera, bp=None):
        if bp is None:
            bp = sm.GetService('michelle').GetBallpark()
        scene.ballpark = bp

    def ApplyScene(self, scene, registerKey=None):
        if registerKey is not None:
            self.RegisterScene(scene, registerKey)
            self.SetActiveScene(scene, registerKey)
        else:
            self.SetActiveScene(scene, registerKey)
        sm.ScatterEvent('OnLoadScene', scene, registerKey)

    def GetOrCreateCamera(self, cameraID):
        if cameraID in self.registeredCameras:
            return self.GetRegisteredCamera(cameraID)
        else:
            return self._CreateAndRegisterCamera(cameraID)

    def _CreateAndRegisterCamera(self, key, **kwargs):
        cameraCls = cameraClsByCameraID[key]
        camera = cameraCls(**kwargs)
        self.RegisterCamera(camera)
        return camera

    @telemetry.ZONE_METHOD
    def LoadScene(self, scenefile, registerKey=None, applyScene=True):
        scene = None
        try:
            if registerKey:
                self.sceneLoadedEvents[registerKey] = locks.Event(registerKey)
            self.SetSceneType(SCENE_TYPE_SPACE)
            sceneFromFile = trinity.Load(scenefile)
            if sceneFromFile is None:
                return
            scene = sceneFromFile
            if applyScene:
                self.ApplyScene(scene, registerKey)
        except Exception:
            log.LogException('sceneManager::LoadScene')
            sys.exc_clear()
        finally:
            if registerKey and registerKey in self.sceneLoadedEvents:
                self.sceneLoadedEvents.pop(registerKey).set()

        return (scene, None)

    def ApplySpaceScene(self):
        scene = self.GetActiveScene()
        if not scene:
            return
        camera = self.GetActivePrimaryCamera()
        self.ApplySolarsystemAttributes(scene, camera)
        self.ApplySceneInflightAttributes(scene, camera)
        self.AddPersistentSpaceObjects(scene)
示例#5
0
class SceneManager(service.Service):
    __guid__ = 'svc.sceneManager'
    __exportedcalls__ = {
        'LoadScene': [],
        'GetScene': [],
        'GetIncarnaRenderJob': [],
        'EnableIncarnaRendering': []
    }
    __startupdependencies__ = ['settings', 'device']
    __notifyevents__ = [
        'OnGraphicSettingsChanged', 'OnSessionChanged', 'OnReleaseBallpark'
    ]

    def __init__(self):
        service.Service.__init__(self)
        self.uiBackdropScene = None
        self.ProcessImportsAndCreateScenes()
        self.primaryJob = SceneContext()
        self.secondaryJob = None
        self.loadingClearJob = trinity.CreateRenderJob()
        self.loadingClearJob.name = 'loadingClear'
        self.loadingClearJob.Clear((0, 0, 0, 1))
        self.loadingClearJob.enabled = False
        self.overlaySceneKeys = ['starmap', 'systemmap', 'planet']
        if '/skiprun' not in blue.pyos.GetArg():
            self._EnableLoadingClear()
        limit = settings.public.device.Get('lodQuality', 3) * 30
        self.explosionManager = util.ExplosionManager(limit)
        self.routeVisualizer = None

    def ProcessImportsAndCreateScenes(self):
        from trinity.sceneRenderJobSpace import CreateSceneRenderJobSpace
        from trinity.eveSceneRenderJobInterior import CreateEveSceneRenderJobInterior
        from trinity.sceneRenderJobCharacters import CreateSceneRenderJobCharacters
        self.fisRenderJob = CreateSceneRenderJobSpace('SpaceScenePrimary')
        self.incarnaRenderJob = CreateEveSceneRenderJobInterior()
        self.characterRenderJob = CreateSceneRenderJobCharacters()
        self._CreateJobInterior()
        self._CreateJobCharCreation()
        self._CreateJobFiS()

    def _EnableLoadingClear(self):
        if not self.loadingClearJob.enabled:
            self.loadingClearJob.enabled = True
            trinity.renderJobs.recurring.insert(0, self.loadingClearJob)

    def _DisableLoadingClear(self):
        if self.loadingClearJob.enabled:
            self.loadingClearJob.enabled = False
            trinity.renderJobs.recurring.remove(self.loadingClearJob)

    def EnableIncarnaRendering(self):
        self._DisableLoadingClear()
        if self.secondaryJob is None:
            self.incarnaRenderJob.Enable()

    def RefreshJob(self, camera):
        sceneType = self.primaryJob.sceneType
        if sceneType == SCENE_TYPE_INTERIOR or sceneType == SCENE_TYPE_CHARACTER_CREATION:
            self.primaryJob.renderJob.SetActiveCamera(camera)
            uicore.uilib.SetSceneView(camera.viewMatrix,
                                      camera.projectionMatrix)

    def _CreateJobInterior(self):
        rj = self.incarnaRenderJob
        rj.CreateBasicRenderSteps()
        rj.EnableSceneUpdate(True)
        rj.EnableVisibilityQuery(True)

    def _CreateJobCharCreation(self):
        self.characterRenderJob.CreateBasicRenderSteps()
        self.characterRenderJob.EnableShadows(True)
        self.characterRenderJob.EnableScatter(True)
        self.characterRenderJob.EnableSculpting(True)
        self.characterRenderJob.Set2DBackdropScene(self.uiBackdropScene)

    def _CreateJobFiS(self, rj=None):
        if rj is None:
            rj = self.fisRenderJob
        rj.CreateBasicRenderSteps()
        rj.EnablePostProcessing(True)
        rj.EnablePostRenderCallbacks(True)

    def GetFiSPostProcessingJob(self):
        return self.fisRenderJob.postProcessingJob

    def ApplyClothSimulationSettings(self):
        if 'character' not in sm.services:
            return
        if self.primaryJob.sceneType == SCENE_TYPE_INTERIOR:
            clothSimulation = sm.GetService('device').GetAppFeatureState(
                'Interior.clothSimulation', False)
            sm.GetService('character').EnableClothSimulation(clothSimulation)
        elif self.primaryJob.sceneType == SCENE_TYPE_CHARACTER_CREATION:
            clothSimulation = sm.GetService('device').GetAppFeatureState(
                'CharacterCreation.clothSimulation', True)
            sm.GetService('character').EnableClothSimulation(clothSimulation)

    def OnGraphicSettingsChanged(self, changes):
        deviceSvc = sm.GetService('device')
        self.interiorGraphicsQuality = settings.public.device.Get(
            'interiorGraphicsQuality',
            deviceSvc.GetDefaultInteriorGraphicsQuality())
        self.shadowQuality = settings.public.device.Get(
            'shadowQuality', deviceSvc.GetDefaultShadowQuality())
        self.postProcessingQuality = settings.public.device.Get(
            'postProcessingQuality',
            deviceSvc.GetDefaultPostProcessingQuality())
        self.antiAliasingQuality = settings.public.device.Get(
            'antiAliasing', 0)
        self.incarnaRenderJob.SetSettingsBasedOnPerformancePreferences()
        self.fisRenderJob.SetSettingsBasedOnPerformancePreferences()
        self.characterRenderJob.SetSettingsBasedOnPerformancePreferences()
        if self.secondaryJob is not None:
            self.secondaryJob.renderJob.SetSettingsBasedOnPerformancePreferences(
            )
        for each in self.registeredJobs:
            each.object.SetSettingsBasedOnPerformancePreferences()

        if 'interiorGraphics' in changes:
            self.ApplyClothSimulationSettings()
        if 'LOD' in changes:
            limit = settings.public.device.Get('lodQuality', 3) * 30
            self.explosionManager.SetLimit(limit)

    def GetIncarnaRenderJob(self):
        return self.incarnaRenderJob

    def GetIncarnaRenderJobVisualizationsMenu(self):
        return self.incarnaRenderJob.GetInsiderVisualizationMenu()

    def SetupIncarnaBackground(self, scene, sceneTranslation, sceneRotation):
        if scene is not None:
            self.incarnaRenderJob.SetBackgroundScene(scene)
            self.backgroundView = trinity.TriView()
            self.backgroundProjection = trinity.TriProjection()
            backGroundCameraUpdateFunction = self.incarnaRenderJob.GetBackgroundCameraUpdateFunction(
                self.backgroundView, self.backgroundProjection, 10.0, 40000.0,
                sceneTranslation, sceneRotation)
            self.incarnaRenderJob.SetBackgroundCameraViewAndProjection(
                self.backgroundView, self.backgroundProjection,
                backGroundCameraUpdateFunction)

    @telemetry.ZONE_METHOD
    def OnSessionChanged(self, isremote, session, change):
        if 'locationid' in change:
            newLocationID = change['locationid'][1]
            if util.IsSolarSystem(
                    newLocationID
            ) and self.primaryJob.sceneType != SCENE_TYPE_SPACE:
                log.LogWarn(
                    'SceneManager: I detected a session change into space but no one has bothered to update my scene type!'
                )
                self.SetSceneType(SCENE_TYPE_SPACE)

    def OnReleaseBallpark(self):
        scene = self.GetRegisteredScene('default')
        if getattr(scene, 'ballpark', None):
            self.SetActiveScene(None, 'default')

    @telemetry.ZONE_METHOD
    def SetSceneType(self, sceneType):
        if self.primaryJob.sceneType == sceneType:
            if sceneType == SCENE_TYPE_INTERIOR:
                self._EnableLoadingClear()
            return
        self.primaryJob = SceneContext(sceneType=sceneType)
        if sceneType == SCENE_TYPE_INTERIOR:
            log.LogInfo('Setting up WiS interior scene rendering')
            self.primaryJob.renderJob = self.incarnaRenderJob
            self.characterRenderJob.Disable()
            self.fisRenderJob.SetActiveScene(None)
            self.fisRenderJob.Disable()
            for each in self.registeredJobs:
                each.object.UseFXAA(True)

            self.ApplyClothSimulationSettings()
            if getattr(self.secondaryJob, 'sceneType',
                       None) == SCENE_TYPE_SPACE:
                self.secondaryJob.renderJob.UseFXAA(True)
            else:
                self._EnableLoadingClear()
        elif sceneType == SCENE_TYPE_CHARACTER_CREATION:
            log.LogInfo('Setting up character creation scene rendering')
            self.primaryJob.renderJob = self.characterRenderJob
            self.incarnaRenderJob.SetScene(None)
            self.incarnaRenderJob.SetBackgroundScene(None)
            self.incarnaRenderJob.Disable()
            self.fisRenderJob.SetActiveScene(None)
            self.fisRenderJob.Disable()
            self.ApplyClothSimulationSettings()
            self._DisableLoadingClear()
            self.characterRenderJob.Enable()
        elif sceneType == SCENE_TYPE_SPACE:
            log.LogInfo('Setting up space scene rendering')
            self.primaryJob.renderJob = self.fisRenderJob
            self.incarnaRenderJob.SetScene(None)
            self.incarnaRenderJob.SetBackgroundScene(None)
            self.incarnaRenderJob.Disable()
            self.characterRenderJob.SetScene(None)
            self.characterRenderJob.Disable()
            self.fisRenderJob.UseFXAA(False)
            for each in self.registeredJobs:
                each.object.UseFXAA(False)

            self._DisableLoadingClear()
            if getattr(self.secondaryJob, 'sceneType',
                       None) == SCENE_TYPE_SPACE:
                self.secondaryJob.renderJob.UseFXAA(False)
            if self.secondaryJob is None:
                self.fisRenderJob.Enable()

    @telemetry.ZONE_METHOD
    def Initialize(self, scene):
        self.uiBackdropScene = trinity.Tr2Sprite2dScene()
        self.uiBackdropScene.isFullscreen = True
        self.uiBackdropScene.backgroundColor = (0, 0, 0, 1)
        self.characterRenderJob.Set2DBackdropScene(self.uiBackdropScene)
        self.primaryJob = SceneContext(scene=scene,
                                       renderJob=self.fisRenderJob)

    @telemetry.ZONE_METHOD
    def SetActiveCamera(self, camera):
        if self.secondaryJob is None:
            self.primaryJob.camera = camera
            if self.primaryJob.renderJob is not None:
                self.primaryJob.renderJob.SetActiveCamera(camera)
        else:
            self.secondaryJob.camera = camera
            self.secondaryJob.renderJob.SetActiveCamera(camera)
        uicore.uilib.SetSceneCamera(camera)

    @telemetry.ZONE_METHOD
    def SetSecondaryScene(self, scene, sceneKey, sceneType):
        if sceneType == SCENE_TYPE_SPACE:
            newJob = self.secondaryJob is None
            if newJob:
                from trinity.sceneRenderJobSpace import CreateSceneRenderJobSpace
                self.secondaryJob = SceneContext(scene=scene,
                                                 sceneKey=sceneKey,
                                                 sceneType=sceneType)
                self.secondaryJob.renderJob = CreateSceneRenderJobSpace(
                    'SpaceSceneSecondary')
                self._CreateJobFiS(self.secondaryJob.renderJob)
            else:
                self.secondaryJob.scene = scene
                self.secondaryJob.sceneKey = sceneKey
            self.secondaryJob.renderJob.SetActiveScene(scene, sceneKey)
            self.secondaryJob.renderJob.UseFXAA(
                self.primaryJob.sceneType != SCENE_TYPE_SPACE)
            if newJob:
                self.secondaryJob.renderJob.Enable()

    def ClearSecondaryScene(self):
        if self.secondaryJob is None:
            return
        if self.secondaryJob.renderJob is not None:
            self.secondaryJob.renderJob.Disable()
        self.secondaryJob = None

    def SetActiveScene(self, scene, sceneKey=None):
        sceneType = SCENE_TYPE_INTERIOR
        if getattr(scene, '__bluetype__', None) == 'trinity.EveSpaceScene':
            sceneType = SCENE_TYPE_SPACE
        if sceneKey in self.overlaySceneKeys:
            self.primaryJob.renderJob.Pause()
            self.SetSecondaryScene(scene, sceneKey, sceneType)
        elif sceneType == SCENE_TYPE_SPACE:
            self.primaryJob.sceneKey = sceneKey
            self.primaryJob.scene = scene
            self.primaryJob.renderJob.SetActiveScene(scene, sceneKey)
        else:
            self.primaryJob.scene = scene
            self.primaryJob.renderJob.SetScene(scene)

    def Run(self, ms):
        service.Service.Run(self, ms)
        self.registeredScenes = {}
        self.registeredCameras = {}
        self.sceneLoadedEvents = {}
        self.registeredJobs = []
        self.maxFov = 1
        self.minFov = 0.05
        self.interiorGraphicsQuality = settings.public.device.Get(
            'interiorGraphicsQuality',
            self.device.GetDefaultInteriorGraphicsQuality())
        self.shadowQuality = settings.public.device.Get(
            'shadowQuality', self.device.GetDefaultShadowQuality())
        self.postProcessingQuality = settings.public.device.Get(
            'postProcessingQuality',
            self.device.GetDefaultPostProcessingQuality())
        self.antiAliasingQuality = settings.public.device.Get(
            'antiAliasing', 0)

    def RegisterJob(self, job):
        wr = blue.BluePythonWeakRef(job)
        if self.primaryJob.sceneType == SCENE_TYPE_INTERIOR:
            job.UseFXAA(True)

        def ClearDereferenced():
            self.registeredJobs.remove(wr)

        wr.callback = ClearDereferenced
        self.registeredJobs.append(wr)

    def GetRegisteredCamera(self, key, defaultOnActiveCamera=0):
        if key in self.registeredCameras:
            return self.registeredCameras[key]
        if defaultOnActiveCamera:
            if self.secondaryJob is not None:
                return self.secondaryJob.camera
            return self.primaryJob.camera

    def UnregisterCamera(self, key):
        if key in self.registeredCameras:
            del self.registeredCameras[key]

    def RegisterCamera(self, key, camera):
        self.registeredCameras[key] = camera
        self.SetCameraOffset(camera)

    def SetCameraOffset(self, camera):
        camera.centerOffset = settings.user.ui.Get('cameraOffset', 0) * -0.0075

    def CheckCameraOffsets(self):
        for cam in self.registeredCameras.itervalues():
            self.SetCameraOffset(cam)

    def UnregisterScene(self, key):
        if key in self.registeredScenes:
            del self.registeredScenes[key]

    def RegisterScene(self, scene, key):
        self.registeredScenes[key] = scene

    def GetRegisteredScene(self, key, defaultOnActiveScene=0):
        if key in self.registeredScenes:
            return self.registeredScenes[key]
        if key in self.sceneLoadedEvents and not self.sceneLoadedEvents[
                key].is_set():
            self.sceneLoadedEvents[key].wait()
            return self.registeredScenes[key]
        if defaultOnActiveScene:
            return self.primaryJob.scene

    def SetRegisteredScenes(self, key):
        if key == 'default' and self.secondaryJob is not None:
            if self.primaryJob.renderJob.enabled:
                self.primaryJob.renderJob.Start()
            else:
                self.primaryJob.renderJob.Enable()
            self.ClearSecondaryScene()
        if self.primaryJob.sceneType != SCENE_TYPE_INTERIOR or key in self.overlaySceneKeys:
            scene = self.registeredScenes.get(key, None)
            camera = self.registeredCameras.get(key, None)
            self.SetActiveScene(scene, key)
            if camera:
                self.SetActiveCamera(camera)

    def GetActiveScene(self):
        if self.secondaryJob is not None:
            return self.secondaryJob.scene
        return self.primaryJob.scene

    def Get2DBackdropScene(self):
        return self.uiBackdropScene

    @telemetry.ZONE_METHOD
    def Show2DBackdropScene(self, updateRenderJob=False):
        self.showUIBackdropScene = True
        if updateRenderJob:
            self.characterRenderJob.Set2DBackdropScene(self.uiBackdropScene)

    @telemetry.ZONE_METHOD
    def Hide2DBackdropScene(self, updateRenderJob=False):
        self.showUIBackdropScene = False
        if updateRenderJob:
            self.characterRenderJob.Set2DBackdropScene(None)

    def GetScene(self, location=None):
        if location is None:
            location = (eve.session.solarsystemid2,
                        eve.session.constellationid, eve.session.regionid)
        resPath = cfg.GetNebula(*location)
        return resPath

    def DeriveTextureFromSceneName(self, scenePath):
        scene = trinity.Load(scenePath)
        if scene is None:
            return ''
        return scene.envMap1ResPath

    def PrepareCamera(self, camera):
        camera.fieldOfView = self.maxFov
        camera.friction = 7.0
        camera.maxSpeed = 0.07
        camera.frontClip = 6.0
        camera.backClip = 10000000.0
        camera.idleScale = 0.65
        for each in camera.zoomCurve.keys:
            each.value = self.maxFov

    def PrepareBackgroundLandscapes(self, scene):
        starSeed = 0
        securityStatus = 1
        if eve.session.stationid is not None:
            return
        if scene is None:
            return
        if bool(eve.session.solarsystemid2):
            starSeed = int(eve.session.constellationid)
            securityStatus = sm.StartService('map').GetSecurityStatus(
                eve.session.solarsystemid)
        scene.starfield = trinity.Load(
            'res:/dx9/scene/starfield/spritestars.red')
        if scene.starfield is not None:
            scene.starfield.seed = starSeed
            scene.starfield.minDist = 40
            scene.starfield.maxDist = 80
            if util.IsWormholeSystem(eve.session.solarsystemid):
                scene.starfield.numStars = 0
            else:
                scene.starfield.numStars = 500 + int(250 * securityStatus)
        if scene.backgroundEffect is None:
            scene.backgroundEffect = trinity.Load(
                'res:/dx9/scene/starfield/starfieldNebula.red')
            node = nodemanager.FindNode(scene.backgroundEffect.resources,
                                        'NebulaMap',
                                        'trinity.TriTexture2DParameter')
            if node is not None:
                node.resourcePath = scene.envMap1ResPath
        if scene.starfield is None or scene.backgroundEffect is None:
            return
        scene.backgroundRenderingEnabled = True

    @telemetry.ZONE_METHOD
    def LoadScene(self,
                  scenefile,
                  sceneName='',
                  fov=None,
                  leaveUntouched=0,
                  inflight=0,
                  registerKey=None,
                  setupCamera=True):
        try:
            if registerKey:
                self.sceneLoadedEvents[registerKey] = locks.Event(registerKey)
            self.SetSceneType(SCENE_TYPE_SPACE)
            sceneFromFile = trinity.Load(scenefile)
            if sceneFromFile is None:
                return
            scene = sceneFromFile
            bp = sm.GetService('michelle').GetBallpark()
            camera = self.GetRegisteredCamera(registerKey)
            if setupCamera:
                if camera is None:
                    camera = trinity.Load('res:/dx9/scene/camera.red')
            if inflight:
                if scene.dustfield is None:
                    scene.dustfield = trinity.Load(
                        'res:/dx9/scene/dustfield.red')
                scene.dustfieldConstraint = scene.dustfield.Find(
                    'trinity.EveDustfieldConstraint')[0]
                if scene.dustfieldConstraint is not None:
                    scene.dustfieldConstraint.camera = camera
                scene.ballpark = bp
                scene.sunDiffuseColor = (1.5, 1.5, 1.5, 1.0)
                if settings.user.ui.Get(
                        'effectsEnabled',
                        1) and session.solarsystemid is not None:
                    universe = getattr(self, 'universe', None)
                    if not universe:
                        universe = trinity.Load(
                            'res:/dx9/scene/starfield/universe.red')
                        setattr(self, 'universe', universe)
                    scene.backgroundObjects.append(universe)
                    here = sm.GetService('map').GetItem(session.solarsystemid)
                    if here:
                        scale = 10000000000.0
                        position = (here.x / scale, here.y / scale,
                                    -here.z / scale)
                        universe.children[0].translation = position
            if leaveUntouched:
                self.SetActiveScene(scene, registerKey)
                return scene
            if camera:
                self.PrepareCamera(camera)
                if fov:
                    camera.fieldOfView = fov
            self.PrepareBackgroundLandscapes(scene)
            if registerKey:
                self.RegisterCamera(registerKey, camera)
                self.RegisterScene(scene, registerKey)
                activeScene = self.GetActiveScene()
                if activeScene is None or activeScene not in self.registeredScenes.values(
                ):
                    self.SetActiveScene(scene, registerKey)
                    if camera:
                        self.SetActiveCamera(camera)
            else:
                self.SetActiveScene(scene, registerKey)
                if camera:
                    self.SetActiveCamera(camera)
            if camera:
                camera.audio2Listener = audio2.GetListener(0)
            if camera and bp is not None:
                myShipBall = bp.GetBallById(bp.ego)
                vel = geo2.Vector(myShipBall.vx, myShipBall.vy, myShipBall.vz)
                if geo2.Vec3Length(vel) > 0.0:
                    vel = geo2.Vec3Normalize(vel)
                    pitch = asin(-vel[1])
                    yaw = atan2(vel[0], vel[2])
                    yaw = yaw - 0.3
                    pitch = pitch - 0.15
                    camera.SetOrbit(yaw, pitch)
            if inflight and settings.user.ui.Get('routeVisualizationEnabled',
                                                 True):
                if self.routeVisualizer:
                    self.routeVisualizer.Cleanup()
                self.routeVisualizer = RouteVisualizer()
            sm.ScatterEvent('OnLoadScene')
        except Exception:
            log.LogException('sceneManager::LoadScene')
            sys.exc_clear()
        finally:
            if registerKey and registerKey in self.sceneLoadedEvents:
                self.sceneLoadedEvents.pop(registerKey).set()

    def ToggleRouteVisualization(self):
        enabled = not settings.user.ui.Get('routeVisualizationEnabled', True)
        settings.user.ui.Set('routeVisualizationEnabled', enabled)
        if enabled:
            if self.routeVisualizer:
                self.routeVisualizer.Update()
            else:
                self.routeVisualizer = RouteVisualizer()
        elif self.routeVisualizer:
            self.routeVisualizer.Cleanup()
            self.routeVisualizer = None