shipSKINRSceneContainer.py (15633B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\cosmetics\ship\pages\studio\shipSKINRSceneContainer.py 2 import logging 3 import blue 4 import geo2 5 import trinity 6 import uthread 7 import uthread2 8 from carbon.client.script.environment.AudioUtil import PlaySound 9 from carbonui.uianimations import animations 10 from cosmetics.client.ships.skins.live_data import current_skin_design_signals, current_skin_design 11 from cosmetics.common.ships.skins.static_data.component_category import ComponentCategory 12 from cosmetics.common.ships.skins.static_data.pattern_attribute import PatternAttribute 13 from cosmetics.common.ships.skins.static_data.slot_name import SlotID, PATTERN_SLOT_IDS, PATTERN_SLOT_ID_BY_PATTERN_MATERIAL_ID 14 from eve.client.script.environment.sofService import GetSofService 15 from eve.client.script.environment.spaceObject.cosmeticsManager import CosmeticsManager 16 from eve.client.script.environment.spaceObject.spaceObject import modify_dna 17 from eve.client.script.ui.camera.skinrShipSceneContainerCamera import SkinrShipSceneContainerCamera 18 from eve.client.script.ui.control.scenecontainer import SceneContainer 19 from eve.client.script.ui.cosmetics.ship.const import ANIM_DURATION_LONG, ANIM_DURATION_EXTRA_LONG, SkinrPage 20 from eve.client.script.ui.cosmetics.ship.pages.studio import studioSignals, nebulaConsts 21 from eve.client.script.ui.cosmetics.ship.pages.studio.patternProjectorGizmo import PatternProjectorGizmo 22 from eve.client.script.ui.cosmetics.ship.pages.studio.studioUtil import is_green_screen_enabled 23 from evegraphics import utils as gfxutils 24 from fsdBuiltData.common.graphicIDs import GetGraphicFile 25 from cosmetics.client.ships.qa.settings import visualize_shape_ellipsoid 26 log = logging.getLogger(__name__) 27 TRANSITION_ZOOM_DEFAULT = 0.5 28 ZOOM_RANGE = [1.6, 3.6] 29 SCENE_GRAPHICID = 26811 30 SHIP_MATERIALIZATION_MULTIEFFECT_GRAPHICID = 27581 31 SKINR_ENVIRONMENT_VFX_GRAPHICID = 27580 32 33 class ShipSKINRSceneContainer(SceneContainer): 34 _model_dna = None 35 _type_id = None 36 37 def __init__(self, **kwargs): 38 log.info('SKIN PREVIEW - PaintPreviewSceneContainer: Start constructing') 39 super(ShipSKINRSceneContainer, self).__init__(**kwargs) 40 self.pattern_projector_gizmo = PatternProjectorGizmo() 41 self.environment = None 42 self.shipReplacementMultiEffect = None 43 self._lastSwapTriggerTimeStamp = 0.0 44 self.model = None 45 self.oldModel = None 46 self._current_skin_design = None 47 self._load_ship_thread = None 48 self.PrepareSpaceScene() 49 if self.camera: 50 self.camera.farClip = 1000000 51 self.camera.nearClip = 10 52 self.cosmetics_manager = CosmeticsManager() 53 log.info('SKIN PREVIEW - PaintPreviewSceneContainer: Finish constructing') 54 self.connect_signals() 55 56 def Close(self): 57 super(ShipSKINRSceneContainer, self).Close() 58 self.disconnect_signals() 59 60 def connect_signals(self): 61 current_skin_design_signals.on_component_attribute_changed.connect(self.on_current_design_component_attribute_changed) 62 current_skin_design_signals.on_pattern_blend_mode_changed.connect(self.on_pattern_blend_mode_changed) 63 current_skin_design_signals.on_slot_fitting_changed.connect(self.on_slot_fitting_changed) 64 nebulaConsts.SELECTED_SKINR_BACKGROUND.on_change.connect(self.on_nebula_changed) 65 visualize_shape_ellipsoid.on_change.connect(self.on_visualize_shape_ellipsoid) 66 studioSignals.on_page_opened.connect(self.on_page_opened) 67 68 def disconnect_signals(self): 69 current_skin_design_signals.on_component_attribute_changed.disconnect(self.on_current_design_component_attribute_changed) 70 current_skin_design_signals.on_pattern_blend_mode_changed.disconnect(self.on_pattern_blend_mode_changed) 71 current_skin_design_signals.on_slot_fitting_changed.disconnect(self.on_slot_fitting_changed) 72 nebulaConsts.SELECTED_SKINR_BACKGROUND.on_change.disconnect(self.on_nebula_changed) 73 studioSignals.on_page_opened.disconnect(self.on_page_opened) 74 75 def on_page_opened(self, page_id, page_args, last_page_id, animate = True): 76 if nebulaConsts.skinr_nebula_backgrounds_enabled(): 77 if last_page_id is SkinrPage.STUDIO_DESIGNER: 78 self.on_nebula_changed(nebulaConsts.BackgroundEnum.Empty) 79 elif page_id is SkinrPage.STUDIO_DESIGNER: 80 self.on_nebula_changed(nebulaConsts.SELECTED_SKINR_BACKGROUND.get()) 81 82 def on_visualize_shape_ellipsoid(self, value): 83 if value is True: 84 childEffect = trinity.Load('res:/fisfx/utils/ShieldEllipsoidTester.red') 85 r = self.model.shapeEllipsoidRadius 86 childEffect.scaling = (r[0] * 2.0, r[1] * 2.0, r[2] * 2.0) 87 childEffect.translation = self.model.shapeEllipsoidCenter 88 self.model.effectChildren.append(childEffect) 89 elif len(self.model.effectChildren) > 0: 90 self.model.effectChildren.pop() 91 92 def on_slot_fitting_changed(self, slot_id, component_instance): 93 if component_instance: 94 data = component_instance.get_component_data() 95 if data: 96 self._play_apply_sound(data.category) 97 self.cosmetics_manager.apply_component(slot_id, component_instance) 98 99 def on_nebula_changed(self, value): 100 if not nebulaConsts.skinr_nebula_backgrounds_enabled() and value is not nebulaConsts.BackgroundEnum.Empty: 101 return 102 res_path = nebulaConsts.SKINR_NEBULA_RES_PATHS[value] 103 self.scene.backgroundEffect.resources.FindByName('AlphaMap').resourcePath = res_path[:-4] + '_refl.dds' 104 self.scene.backgroundEffect.resources.FindByName('NebulaMap').resourcePath = res_path 105 self.scene.envMapResPath = res_path[:-4] + '_refl.dds' 106 self.scene.envMap1ResPath = res_path 107 self.scene.envMap2ResPath = res_path[:-4] + '_blur.dds' 108 self.scene.backgroundRenderingEnabled = value is not nebulaConsts.BackgroundEnum.Empty 109 self.environment.display = value is nebulaConsts.BackgroundEnum.Empty 110 111 def _play_apply_sound(self, category): 112 if category == ComponentCategory.MATERIAL: 113 PlaySound('nanocoating_button_select_color_play') 114 elif category == ComponentCategory.METALLIC: 115 PlaySound('nanocoating_button_push_detailing_play') 116 elif category == ComponentCategory.PATTERN: 117 PlaySound('nanocoating_button_select_pattern_play') 118 119 def on_pattern_blend_mode_changed(self, value): 120 self.cosmetics_manager.SetBlendMode(self.model, value) 121 122 def on_current_design_component_attribute_changed(self, slot_id, attribute_id, value): 123 if slot_id not in PATTERN_SLOT_IDS: 124 return 125 if attribute_id == PatternAttribute.MIRROR: 126 self.cosmetics_manager.SetMirroredState(slot_id, value) 127 elif attribute_id == PatternAttribute.PROJECT_TO_AREA_1: 128 self.cosmetics_manager.SetTargetMaterialArea(slot_id, SlotID.PRIMARY_NANOCOATING, value) 129 elif attribute_id == PatternAttribute.PROJECT_TO_AREA_2: 130 self.cosmetics_manager.SetTargetMaterialArea(slot_id, SlotID.SECONDARY_NANOCOATING, value) 131 elif attribute_id == PatternAttribute.PROJECT_TO_AREA_3: 132 self.cosmetics_manager.SetTargetMaterialArea(slot_id, SlotID.TERTIARY_NANOCOATING, value) 133 elif attribute_id == PatternAttribute.PROJECT_TO_AREA_4: 134 self.cosmetics_manager.SetTargetMaterialArea(slot_id, SlotID.TECH_AREA, value) 135 elif attribute_id == PatternAttribute.SCALE: 136 self.cosmetics_manager.ApplyScaling(slot_id, value) 137 elif attribute_id == PatternAttribute.ROTATION: 138 self.cosmetics_manager.ApplyRotation(slot_id, value) 139 elif attribute_id == PatternAttribute.POSITION: 140 self.cosmetics_manager.ApplyTranslation(slot_id, value) 141 142 def PrepareCamera(self): 143 self.camera = SkinrShipSceneContainerCamera() 144 self.camera.OnActivated() 145 146 def turn_camera(self, yaw, pitch, duration): 147 self.camera.StopUpdateThreads() 148 self.camera.StopAnimations() 149 animations.MorphScalar(self.camera, 'yaw', self.camera.yaw, yaw, duration=duration) 150 animations.MorphScalar(self.camera, 'pitch', self.camera.pitch, pitch, duration=duration) 151 152 def rotate_ship_in(self, duration): 153 q1 = geo2.QuaternionRotationSetYawPitchRoll(-0.1, -0.05, 0.0) 154 q2 = geo2.QuaternionRotationSetYawPitchRoll(0.0, 0.0, 0.0) 155 animations.MorphQuaternion(self.model.rotationCurve, 'value', q1, q2, duration) 156 157 def SetPattern(self, pattern_id): 158 self.cosmetics_manager.SetProjectionTexture(pattern_id) 159 160 def GetCurrentShip(self): 161 return self.model 162 163 def GetCurrentCamera(self): 164 return self.camera 165 166 def PrepareSpaceScene(self, scenePath = None): 167 log.info('SKIN PREVIEW - PaintPreviewSceneContainer: PrepareSpaceScene started') 168 if scenePath is None: 169 scenePath = GetGraphicFile(SCENE_GRAPHICID) 170 super(ShipSKINRSceneContainer, self).PrepareSpaceScene(scenePath=scenePath) 171 log.info('SKIN PREVIEW - PaintPreviewSceneContainer: PrepareSpaceScene prepared base scene') 172 if not self.scene: 173 return 174 if not self.scene.postprocess: 175 self.scene.postprocess = trinity.Tr2PostProcess2() 176 log.info('SKIN PREVIEW - PaintPreviewSceneContainer: PrepareSpaceScene added postprocess') 177 if not is_green_screen_enabled(): 178 environmentResourcePath = GetGraphicFile(SKINR_ENVIRONMENT_VFX_GRAPHICID) 179 self.environment = blue.resMan.LoadObject(environmentResourcePath) 180 if self.environment is not None: 181 self.AddToScene(self.environment, clear=0) 182 self.environment.StartControllers() 183 else: 184 self.renderJob.GetStep('CLEAR').color = (0, 1, 0, 0) 185 log.info('SKIN PREVIEW - PaintPreviewSceneContainer: PrepareSpaceScene added environment') 186 multiEffectResourcePath = GetGraphicFile(SHIP_MATERIALIZATION_MULTIEFFECT_GRAPHICID) 187 sme = blue.resMan.LoadObject(multiEffectResourcePath) 188 self.shipReplacementMultiEffect = sme 189 if self.shipReplacementMultiEffect is not None: 190 self.AddToScene(self.shipReplacementMultiEffect, clear=0) 191 if self.environment is not None: 192 self.shipReplacementMultiEffect.SetParameter('skinrEnv', self.environment) 193 self.shipReplacementMultiEffect.SetControllerVariable('object_materialize', 0.0) 194 self.shipReplacementMultiEffect.StartControllers() 195 log.info('SKIN PREVIEW - PaintPreviewSceneContainer: PrepareSpaceScene added ship replacement multieffect') 196 if self.pattern_projector_gizmo is not None and self.scene: 197 self.pattern_projector_gizmo.load_and_place_in_scene(self.scene) 198 log.info('SKIN PREVIEW - PaintPreviewSceneContainer: PrepareSpaceScene finished') 199 200 def preview_type(self, type_id, skinDesign = None, animate = True): 201 log.info('SKIN PREVIEW - Preview: commanded preview for type: {type_id}'.format(type_id=type_id)) 202 model_dna = modify_dna(base_dna=gfxutils.BuildSOFDNAFromTypeID(type_id), patternMat1='green_lime_emissive', patternName='cosm_blank_projection') 203 type_changed = type_id != self._type_id 204 self._type_id = type_id 205 self._model_dna = model_dna 206 if skinDesign: 207 self._current_skin_design = skinDesign 208 if animate or type_changed: 209 self._animate_model_swap() 210 else: 211 trinity.WaitForResourceLoads() 212 self.cosmetics_manager.apply_design(self._current_skin_design) 213 214 def _animate_model_swap(self): 215 if self._load_ship_thread: 216 self._lastSwapTriggerTimeStamp = blue.os.GetSimTime() 217 else: 218 PlaySound('nanocoating_ship_paint2_play') 219 if self.shipReplacementMultiEffect is not None: 220 self.shipReplacementMultiEffect.SetControllerVariable('object_materialize', 0.0) 221 log.info('SKIN PREVIEW - Preview: queued delayed load') 222 self._load_ship_thread = uthread.new(self._load_ship_async) 223 224 def _load_ship_async(self): 225 try: 226 self._lastSwapTriggerTimeStamp = blue.os.GetSimTime() 227 SECOND = 10000000.0 228 timeUntilReveal = SECOND * ANIM_DURATION_LONG 229 while self._lastSwapTriggerTimeStamp + timeUntilReveal > blue.os.GetSimTime(): 230 uthread2.Sleep(0.15) 231 232 finally: 233 if self.destroyed: 234 return 235 self._load_ship() 236 trinity.WaitForResourceLoads() 237 self._swap_out_old_ship() 238 self._load_ship_thread = None 239 log.info('SKIN PREVIEW - Preview: delayed load removed from queue') 240 241 def _load_ship(self): 242 log.info('SKIN PREVIEW - Preview: load started for type {type_id}'.format(type_id=self._type_id)) 243 if self.destroyed: 244 return 245 space_object_factory = GetSofService().spaceObjectFactory 246 self.model = space_object_factory.BuildFromDNA(self._model_dna) 247 self.model.rotationCurve = trinity.Tr2RotationAdapter() 248 self.cosmetics_manager.SetTypeID(self._type_id) 249 self.cosmetics_manager.SetModel(self.model) 250 self.cosmetics_manager.apply_design(self._current_skin_design) 251 self.model.SetControllerVariable('boosterOn', 1.0) 252 log.info('SKIN PREVIEW - Preview: model set for type {type_id}'.format(type_id=self._type_id)) 253 while len(self.model.observers) > 0: 254 self.model.observers.pop() 255 256 self.model.FreezeHighDetailMesh() 257 if hasattr(self.model, 'dirtLevel'): 258 self.model.dirtLevel = -1.5 259 log.info('SKIN PREVIEW - Preview: load finished for type {type_id}'.format(type_id=self._type_id)) 260 261 def _swap_out_old_ship(self): 262 log.info('SKIN PREVIEW - SwapOutOldShip: started') 263 if self.destroyed: 264 return 265 if self.oldModel is not None and self.oldModel in self.scene.objects: 266 self.scene.objects.remove(self.oldModel) 267 log.info('SKIN PREVIEW - SwapOutOldShip: Old Model removed') 268 if self.scene and self.model is not None: 269 self.scene.objects.append(self.model) 270 log.info('SKIN PREVIEW - SwapOutOldShip: model added to scene') 271 self._fit_model_in_view(self.model) 272 log.info('SKIN PREVIEW - SwapOutOldShip: model fit in view') 273 if self.shipReplacementMultiEffect is not None: 274 self.shipReplacementMultiEffect.SetParameter('skinrAsset', self.model) 275 self.shipReplacementMultiEffect.StartControllers() 276 self.shipReplacementMultiEffect.SetControllerVariable('object_materialize', 1.0) 277 log.info('SKIN PREVIEW - SwapOutOldShip: replacement multieffect applied') 278 self.model.StartControllers() 279 self.oldModel = self.model 280 self.rotate_ship_in(ANIM_DURATION_EXTRA_LONG) 281 log.info('SKIN PREVIEW - SwapOutOldShip: finished') 282 283 def _fit_model_in_view(self, model): 284 if model is None or not self.camera: 285 return 286 rad = model.GetBoundingSphereRadius() 287 maxRenderDist = self.camera.farClip or 400000.0 288 min_zoom = ZOOM_RANGE[0] * rad 289 max_zoom = min(ZOOM_RANGE[1] * rad, maxRenderDist - 2 * rad) 290 self.SetMinMaxZoom(min_zoom, max_zoom) 291 self.SetZoom(TRANSITION_ZOOM_DEFAULT) 292 self.camera.SetInnerBoundRadius(self.model.shapeEllipsoidRadius) 293 self.camera.SetModelCenter(self.model.shapeEllipsoidCenter)