NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

shipInfoPreviewScene.py (16203B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\info\shipInfoPreviewScene.py
      2 import math
      3 import evetypes
      4 import signals
      5 import trinity
      6 import blue
      7 import mathext
      8 import uthread2
      9 import geo2
     10 from carbon.client.script.environment.AudioUtil import PlaySound
     11 from carbonui import uiconst
     12 from carbonui.uianimations import animations
     13 from eve.client.script.environment.sofService import GetSofService
     14 from eve.client.script.ui.camera.sceneContainerCamera import SceneContainerCamera
     15 from eve.client.script.ui.control.scenecontainer import SceneContainer
     16 from eve.client.script.ui.shared.info.shipInfoConst import TALL_SHIP_POSITION_REPLACEMENTS, WIDE_SHIP_POSITION_REPLACEMENTS, SHIP_POSITIONS, FACTION_BACKGROUND_LOGOS_IDS, LIGHT_RIG_GRAPHIC_ID, get_faction_background
     17 from eve.client.script.ui.shared.skins.controller import GetSkinnedShipModel
     18 from fsdBuiltData.common.graphicIDs import GetGraphicFile
     19 import evegraphics.utils as gfxutils
     20 SCENE_GRAPHICID = 26811
     21 ENVIRONMENT_VFX_GRAPHICID = 27580
     22 SHIP_MATERIALIZATION_MULTIEFFECT_GRAPHICID = 27581
     23 TRANSITION_ZOOM_DEFAULT = 0.2
     24 MINIMUM_ZOOM_DISTANCE_DEFAULT = 5000
     25 ZOOM_RANGE = [1.5, 3.5]
     26 ZOOM_RANGES_BY_RATIO = [(1.0, [2.1, 4.5]), (1.35, [1.8, 3.5]), (1.5, [1.6, 3.5])]
     27 
     28 class ShipInfoPreviewSceneContainer(SceneContainer):
     29 
     30     def __init__(self, **kwargs):
     31         super(ShipInfoPreviewSceneContainer, self).__init__(**kwargs)
     32         self.environment = None
     33         self.shipReplacementMultiEffect = None
     34         self.model = None
     35         self.oldModel = None
     36         self.PrepareSpaceScene()
     37         self._targetCenterOffset = 0.0
     38         self._targetVerticalOffset = 0.0
     39         self._targetZoom = 0.0
     40         self._positionID = None
     41         self.radius = 1.0
     42         self._update_thread = uthread2.StartTasklet(self._update)
     43         self.additionalBackgroundTexture = None
     44         self.skin_state = None
     45         self._loaded = False
     46         self._lastBGType = -1.0
     47         self._pendingLoadData = None
     48         self._async_load_task = None
     49         self.on_load_complete = signals.Signal('ShipInfoPreviewSceneContainer_LoadComplete')
     50 
     51     def PrepareCamera(self):
     52         self.camera = ShipInfoPreviewCamera()
     53         self.camera.OnActivated()
     54 
     55     def PrepareSpaceScene(self, scenePath = None):
     56         if scenePath is None:
     57             scenePath = GetGraphicFile(SCENE_GRAPHICID)
     58         super(ShipInfoPreviewSceneContainer, self).PrepareSpaceScene(scenePath=scenePath)
     59         if not self.scene:
     60             return
     61         if not self.scene.postprocess:
     62             self.scene.postprocess = trinity.Tr2PostProcess2()
     63         self.bgEnvironment = blue.resMan.LoadObject('res:/dx9/scene/showinfo/showinfo_logo_background_01a.red')
     64         self.AddToScene(self.bgEnvironment, clear=0)
     65         self.bgEnvironment.StartControllers()
     66 
     67     def add_background_texture(self, texturePath):
     68         if self.additionalBackgroundTexture:
     69             self.remove_background_texture()
     70         self.additionalBackgroundTexture = blue.resMan.LoadObject('res:/dx9/scene/showinfo/showinfo_logo_background_01a.red')
     71         param = self.additionalBackgroundTexture.externalParameters.FindByName('Logo_resourcePath')
     72         param.SetValue(texturePath)
     73         child = self.additionalBackgroundTexture.effectChildren[0]
     74         trans = child.transformModifiers[2]
     75         trans.translation = (0, 0, -140000)
     76         self.AddToScene(self.additionalBackgroundTexture, clear=0)
     77         return self.additionalBackgroundTexture
     78 
     79     def remove_background_texture(self):
     80         if not self.additionalBackgroundTexture:
     81             return
     82         self.RemoveFromScene(self.additionalBackgroundTexture)
     83         self.additionalBackgroundTexture = None
     84 
     85     def _get_model_offset(self, model, typeID):
     86         modelOffset = getattr(model, 'shapeEllipsoidCenter', (0.0, 0.0, 0.0))
     87         locatorSets = getattr(model, 'locatorSets', None)
     88         if locatorSets:
     89             lookAtLocator = locatorSets.FindByName('camera_look_at')
     90             if lookAtLocator is not None and len(lookAtLocator.locators) > 0:
     91                 modelOffset = lookAtLocator.locators[0][0]
     92         invertedModelOffset = geo2.Vec3Scale(modelOffset, -1.0)
     93         return invertedModelOffset
     94 
     95     def preview_ship(self, typeID, subSystems = [], skin_state = None, skip_repositioning = False, snap = True, skip_animation = False):
     96         if self._async_load_task:
     97             self._pendingLoadData = (self._load_ship,
     98              typeID,
     99              subSystems,
    100              skin_state,
    101              skip_repositioning,
    102              snap,
    103              skip_animation)
    104         else:
    105             self._async_load_task = uthread2.StartTasklet(self._load_ship, typeID, subSystems, skin_state, skip_repositioning, snap, skip_animation)
    106 
    107     def preview_skin(self, typeID, subSystems = [], skin_state = None, skip_repositioning = False, snap = False, skip_animation = True):
    108         if self._async_load_task:
    109             self._pendingLoadData = (self._load_skin,
    110              typeID,
    111              subSystems,
    112              skin_state,
    113              skip_repositioning,
    114              snap,
    115              skip_animation)
    116         else:
    117             self._async_load_task = uthread2.StartTasklet(self._load_skin, typeID, subSystems, skin_state, skip_repositioning, snap, skip_animation)
    118 
    119     def _load_complete(self, snap = True, skip_animation = False):
    120         if self._pendingLoadData:
    121             func, typeID, subSystems, skin_state, skip_repositioning, snap, skip_animation = self._pendingLoadData
    122             self._pendingLoadData = None
    123             func(typeID, subSystems, skin_state, skip_repositioning, snap, skip_animation)
    124         else:
    125             self.on_load_complete(snap, skip_animation)
    126             self._async_load_task = None
    127 
    128     def _load_ship(self, typeID, subSystems = [], skin_state = None, skip_repositioning = False, snap = True, skip_animation = False):
    129         self.set_faction_background(evetypes.GetFactionID(typeID))
    130         self._load(typeID, subSystems, skin_state, skip_repositioning, snap, skip_animation)
    131 
    132     def _load_skin(self, typeID, subSystems = [], skin_state = None, skip_repositioning = False, snap = False, skip_animation = True):
    133         self._load(typeID, subSystems, skin_state, skip_repositioning, snap, skip_animation)
    134 
    135     def _load(self, typeID, subSystems = [], skin_state = None, skip_repositioning = False, snap = False, skip_animation = False):
    136         self._loaded = False
    137         if self.model and self.model in self.scene.objects:
    138             self.scene.objects.remove(self.model)
    139             self.model = None
    140         multiHullTypeIDList = None
    141         if subSystems and len(subSystems) > 0:
    142             multiHullTypeIDList = subSystems
    143         if skin_state is not None:
    144             self.model = GetSkinnedShipModel(skin=skin_state, typeID=typeID, multiHullTypeIDList=multiHullTypeIDList)
    145         self.skin_state = skin_state
    146         if not self.model:
    147             modelDNA = gfxutils.BuildSOFDNAFromTypeID(typeID, multiHullTypeIDList=multiHullTypeIDList)
    148             space_object_factory = GetSofService().spaceObjectFactory
    149             self.model = space_object_factory.BuildFromDNA(modelDNA)
    150         if self.destroyed:
    151             return
    152         self.model.rotationCurve = trinity.Tr2RotationAdapter()
    153         self.model.translationCurve = trinity.Tr2TranslationAdapter()
    154         self.model.translationCurve.value = self._get_model_offset(self.model, typeID)
    155         if self.model.boosters:
    156             self.model.boosters.alwaysOn = True
    157             self.model.boosters.alwaysOnIntensity = 0.7
    158         while len(self.model.observers) > 0:
    159             self.model.observers.pop()
    160 
    161         self.model.FreezeHighDetailMesh()
    162         if hasattr(self.model, 'dirtLevel'):
    163             self.model.dirtLevel = -1.5
    164         self.scene.objects.append(self.model)
    165         self.model.StartControllers()
    166         lightRigAsset = GetGraphicFile(LIGHT_RIG_GRAPHIC_ID)
    167         lightRig = trinity.Load(lightRigAsset)
    168         self.model.effectChildren.append(lightRig)
    169         trinity.WaitForResourceLoads()
    170         maxDelay = 5.0
    171         checkDelay = 50.0
    172         currentDelay = 0.0
    173         while not self.destroyed:
    174             if not self.model:
    175                 return
    176             if max(self.model.generatedShapeEllipsoidRadius) != -1:
    177                 break
    178             if currentDelay > maxDelay:
    179                 break
    180             blue.synchro.SleepWallclock(checkDelay)
    181             currentDelay += checkDelay / 1000.0
    182 
    183         self._loaded = True
    184         if self.destroyed:
    185             self._pendingLoadData = None
    186             self._async_load_task = None
    187             return
    188         if not skip_repositioning:
    189             self._fit_model_in_view(self.model)
    190             self.camera.animate_camera_fov(0.8, 1.1)
    191         self._load_complete(snap, skip_animation)
    192 
    193     def _fit_model_in_view(self, model):
    194         if model is None or not self.camera:
    195             return
    196         self.radius = model.GetBoundingSphereRadius() + 1
    197         zoom_range = self._get_zoom_range_for_model()
    198         self.SetZoomRange(zoom_range)
    199         self.SetZoom(TRANSITION_ZOOM_DEFAULT)
    200         self._targetZoom = TRANSITION_ZOOM_DEFAULT
    201         self.camera.SetInnerBoundRadius(self.model.shapeEllipsoidRadius)
    202         self.camera.centerOffset = self._targetCenterOffset = 0.5
    203         self.camera.verticalOffset = self._targetVerticalOffset = 0
    204         self.camera.atPosition = (0.0, 0.0, 0.0)
    205 
    206     def _get_long_axis_ratio(self):
    207         shield = self.model.generatedShapeEllipsoidRadius
    208         longAxisIdx = shield.index(max(shield))
    209         longAxis = shield[longAxisIdx]
    210         total = 0.0
    211         for idx, axis in enumerate(shield):
    212             if idx == longAxisIdx:
    213                 continue
    214             total += longAxis / axis
    215 
    216         return total / 2.0
    217 
    218     def _get_zoom_range_for_model(self):
    219         longAxisRatio = self._get_long_axis_ratio()
    220         chosen_zoom_range = [1.0, 1.0]
    221         for ratioStep, zoom_range in ZOOM_RANGES_BY_RATIO:
    222             if ratioStep > longAxisRatio:
    223                 return chosen_zoom_range
    224             chosen_zoom_range = zoom_range
    225 
    226         return chosen_zoom_range
    227 
    228     def SetZoomRange(self, zoomRange):
    229         maxRenderDist = self.camera.farClip or 400000.0
    230         min_zoom = zoomRange[0] * self.radius
    231         max_zoom = min(zoomRange[1] * self.radius, maxRenderDist - 2 * self.radius)
    232         self.SetMinMaxZoom(min_zoom, max_zoom)
    233 
    234     def update_offset(self):
    235         self.camera.centerOffset = mathext.lerp(self.camera.centerOffset, self._targetCenterOffset, 0.3)
    236         self.camera.verticalOffset = mathext.lerp(self.camera.verticalOffset, self._targetVerticalOffset, 0.3)
    237 
    238     @property
    239     def loaded(self):
    240         return self._loaded
    241 
    242     @property
    243     def centerOffset(self):
    244         return self._targetCenterOffset
    245 
    246     @centerOffset.setter
    247     def centerOffset(self, value):
    248         self._targetCenterOffset = value
    249 
    250     def SetCenterOffset(self, value):
    251         self.camera.centerOffset = self._targetCenterOffset = value
    252 
    253     @property
    254     def verticalOffset(self):
    255         return self._targetVerticalOffset
    256 
    257     @verticalOffset.setter
    258     def verticalOffset(self, value):
    259         self._targetVerticalOffset = value
    260 
    261     def _update(self):
    262         while not self.destroyed:
    263             self.update_offset()
    264             uthread2.Sleep(0.001)
    265 
    266     def set_faction_background(self, factionID):
    267         newBGType = get_faction_background(factionID)
    268         if newBGType == self._lastBGType:
    269             self.bgEnvironment.Start()
    270             return
    271         self._lastBGType = newBGType
    272         self.bgEnvironment.SetControllerVariable('Faction', newBGType)
    273         while len(self.bgEnvironment.effectChildren) == 0:
    274             uthread2.Sleep(0.01)
    275 
    276         while len(self.bgEnvironment.effectChildren[0].objects) == 0:
    277             uthread2.Sleep(0.01)
    278 
    279         backgroundLogo = self.bgEnvironment.effectChildren[0].objects[0]
    280         trans = backgroundLogo.transformModifiers.Find('trinity.EveChildModifierSRT')[0]
    281         trans.translation = (28000.0, -12000.0, -99000.0)
    282 
    283     def set_ship_state(self, tabID):
    284         pass
    285 
    286     def position_ship(self, positionID, duration, initialize = False, sound = None, soundOffset = 0):
    287         if not self._loaded:
    288             return
    289         if self.is_tall() and positionID in TALL_SHIP_POSITION_REPLACEMENTS:
    290             positionID = TALL_SHIP_POSITION_REPLACEMENTS[positionID]
    291         elif self.is_wide() and positionID in WIDE_SHIP_POSITION_REPLACEMENTS:
    292             positionID = WIDE_SHIP_POSITION_REPLACEMENTS[positionID]
    293         if positionID == self._positionID:
    294             return
    295         self._positionID = positionID
    296         pitch, yaw = SHIP_POSITIONS[positionID]
    297         if initialize:
    298             self.set_camera_angle_deg(pitch, yaw)
    299         else:
    300             self.turn_camera_deg(pitch, yaw, duration)
    301             if sound:
    302                 startSignal, stopSignal = sound
    303                 PlaySound(startSignal)
    304                 uthread2.StartTasklet(self._stop_sound, duration - soundOffset, stopSignal)
    305 
    306     def zoom_to(self, targetZoom, duration):
    307         animations.StopAllAnimations(self)
    308         animations.MorphScalar(self, 'zoom', self.zoom, targetZoom, duration)
    309 
    310     def _stop_sound(self, delay, signal):
    311         uthread2.Sleep(delay)
    312         PlaySound(signal)
    313 
    314     def is_tall(self):
    315         shield = self.model.generatedShapeEllipsoidRadius
    316         longAxis = shield.index(max(shield))
    317         if longAxis == 1:
    318             return True
    319         return False
    320 
    321     def is_wide(self):
    322         shield = self.model.generatedShapeEllipsoidRadius
    323         longAxis = shield.index(max(shield))
    324         if longAxis == 0:
    325             return True
    326         return False
    327 
    328     def get_bounding_sphere_radius(self):
    329         if self.model:
    330             return self.model.GetBoundingSphereRadius()
    331         return 0
    332 
    333     def turn_camera_deg(self, pitch, yaw, duration):
    334         pitchRad = math.radians(pitch)
    335         yawRad = math.radians(yaw)
    336         self.turn_camera(pitchRad, yawRad, duration)
    337 
    338     def turn_camera(self, pitch, yaw, duration):
    339         self.camera.turn_camera(pitch, yaw, duration, False)
    340 
    341     def set_camera_angle_deg(self, pitch, yaw):
    342         pitchRad = math.radians(pitch)
    343         yawRad = math.radians(yaw)
    344         self.set_camera_angle(pitchRad, yawRad)
    345 
    346     def set_camera_angle(self, pitch, yaw):
    347         self.camera.set_angle(pitch, yaw)
    348 
    349 
    350 class ShipInfoPreviewCamera(SceneContainerCamera):
    351 
    352     def __init__(self):
    353         super(ShipInfoPreviewCamera, self).__init__()
    354         self.kFovSpeed = 1.0
    355         self.originalPitch = 0.0
    356         self.originalYaw = 0.0
    357         self.lastAnimDuration = 0.0
    358         self.allowFreeInspection = True
    359 
    360     def UpdateViewportSize(self, width, height):
    361         if height:
    362             self._aspectRatio = float(width) / height
    363 
    364     def return_to_original_angle(self):
    365         self._turn_camera(self.originalPitch, self.originalYaw, self.lastAnimDuration)
    366 
    367     def turn_camera(self, pitch, yaw, duration, allowFreeInspection):
    368         self.originalPitch = pitch
    369         self.originalYaw = yaw
    370         self.lastAnimDuration = duration
    371         self.allowFreeInspection = allowFreeInspection
    372         self._turn_camera(pitch, yaw, duration)
    373 
    374     def _turn_camera(self, pitch, yaw, duration):
    375         self.StopUpdateThreads(skipFov=True)
    376         self.StopAnimations()
    377         yawDist = self.yaw - yaw
    378         if math.fabs(yawDist) > math.pi:
    379             if yawDist < 0:
    380                 yaw = yaw - 2 * math.pi
    381             else:
    382                 yaw = yaw + 2 * math.pi
    383         if math.fabs(self.pitch - pitch) > math.pi:
    384             pitch = pitch - 2 * math.pi
    385         animations.MorphScalar(self, 'yaw', self.yaw, yaw, duration=duration)
    386         animations.MorphScalar(self, 'pitch', self.pitch, pitch, duration=duration)
    387 
    388     def set_angle(self, pitch, yaw):
    389         self.StopUpdateThreads(skipFov=True)
    390         self.StopAnimations()
    391         self.pitch = pitch
    392         self.yaw = yaw
    393 
    394     def animate_camera_fov(self, finalValue, startValue = None):
    395         if startValue is not None:
    396             self.fov = startValue
    397         self.SetFovTarget(finalValue)