modularHangarCamera.py (19296B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\camera\modularHangarCamera.py 2 import math 3 from eve.client.script.ui.camera.cameraUtil import GetInitialLookAtDistance 4 import evecamera 5 import uthread 6 import logging 7 import blue 8 from eve.client.script.ui.camera.baseSpaceCamera import BaseSpaceCamera 9 from gametime import GetSecondsSinceSimTime, GetSimTime 10 import carbonui.const as uiconst 11 import geo2 12 from carbonui.uicore import uicore 13 import eve.client.script.ui.view.hangarBehaviours.modularHangarBehavioursConstants as hc 14 from uthread2 import call_after_simtime_delay 15 logger = logging.getLogger(__name__) 16 17 class ModularHangarCamera(BaseSpaceCamera): 18 cameraID = evecamera.CAM_MODULARHANGAR 19 isBobbingCamera = False 20 name = 'ModularHangarCamera' 21 kMaxPitch = math.pi / 2.0 + math.pi / 8.0 22 minFov = 0.3 23 maxFov = 1.0 24 hangarMinZoom = 2050.0 25 hangarMaxZoom = 10.0 26 27 def __init__(self): 28 BaseSpaceCamera.__init__(self) 29 self.log = logger 30 self.model = None 31 self.atPosition = (0.0, 0.0, 0.0) 32 self.typeID = 0 33 self.zoomFactor = 0.5 34 self.fov = 1.0 35 self.fpShipSpawnTime = 0 36 self.hangarEntryTime = 0 37 self.simplifiedDirection = (0.0, 0.0, 0.0) 38 self.camSpeed = (0.0, 0.0, 0.0) 39 self.distanceToFP = 0 40 self.isRotating = 0 41 self.changingShip = False 42 self.flightValueMap = [] 43 self.targetPoint = (0.0, 0.0, 0.0) 44 self.lastShipLocation = None 45 self.transitionAnimationEndedTime = 0 46 self.hallwayTime = 0.4 47 self.currentShipSizeClass = 1 48 self.phase2finished = True 49 self.changingSkinsTime = 0 50 51 def SetCurrentShipSizeClass(self, sizeClass): 52 self.currentShipSizeClass = sizeClass 53 54 def SetRotating(self, isTrue): 55 self.isRotating = isTrue 56 57 def SetFlightValueMap(self, exit1, hallway1, hallway2, exit2, dockPos): 58 hallwayLength = min(0.9, geo2.Vec3Length(geo2.Vec3Subtract(hallway1, hallway2)) / 10000) 59 self.hallwayTime = 0.1 + hallwayLength 60 if self.hallwayTime > 0.4 or not hc.TRANSITION_MODIFY_BY_HALLWAYTIME: 61 self.flightValueMap = [self.GetEyePosition(), 62 exit1, 63 hallway1, 64 hallway2, 65 exit2, 66 dockPos] 67 else: 68 modifiedHallway1 = geo2.Vec3Lerp(exit1, hallway1, self.hallwayTime) 69 modifiedHallway2 = geo2.Vec3Lerp(exit2, hallway2, self.hallwayTime) 70 self.flightValueMap = [self.GetEyePosition(), 71 exit1, 72 modifiedHallway1, 73 modifiedHallway2, 74 exit2, 75 dockPos] 76 77 def SetIsChangingSkin(self): 78 self.changingSkinsTime = GetSimTime() 79 80 def SetShip(self, model, typeID, changingShip = True): 81 uicore.animations.StopAllAnimations(self) 82 self.lastShipLocation = self.atPosition 83 self.model = model 84 self.typeID = typeID 85 if changingShip: 86 self.fov = 1.0 87 self.fpShipSpawnTime = GetSimTime() 88 self.targetPoint = self.GetEyePosition() 89 self.changingShip = changingShip or self.changingShip 90 91 def SkipFlight(self): 92 time = GetSimTime() - (hc.SHIP_SWAP_DURATION + hc.TRANSITION_PADDING) 93 self.fpShipSpawnTime = time 94 self.changingSkinsTime = 0.0 95 self.phase2finished = True 96 self.changingShip = False 97 98 def PlaceShip(self, pos): 99 self.atPosition = pos 100 101 def AnimEnterHangar(self, model, startPos, endPos, duration = 5.0): 102 self.hangarEntryTime = GetSimTime() 103 self.model = model 104 self.atPosition = self._CalculateFocalPoint(model) 105 self.changingShip = False 106 self.SetEyePosition(self.CalculateTargetPoint()) 107 self.yaw = 0 108 self.pitch = 0 109 110 def AllignCamera(): 111 modelRotation = model.rotationCurve.currentValue 112 extraYaw = geo2.QuaternionRotationGetYawPitchRoll(modelRotation)[0] 113 self.yaw = extraYaw + 0.5 - math.pi 114 self.pitch = 1.2 115 self.zoomFactor = 0.9 116 117 call_after_simtime_delay(AllignCamera, 0.3) 118 119 def _AnimEnterHangarFOV(self, duration): 120 pass 121 122 def _AnimEnterHangarZoom(self, duration, model): 123 pass 124 125 def _AnimSwitchShipsZoom(self, duration, model): 126 pass 127 128 def _AnimZoom(self, duration, zoom0, zoom1): 129 pass 130 131 def UpdateMinMaxZoom(self): 132 pass 133 134 def SetZoom(self, proportion): 135 pass 136 137 def ClearRefs(self): 138 self.model = None 139 140 def CalculateTargetPoint(self): 141 biggestEllipsoidAxis = max(self.model.generatedShapeEllipsoidRadius) 142 roundFactor = hc.SHIELD_ELLIPSOID_ROUNDING_FACTOR + (1 - pow(1 - self.zoomFactor, 2.0)) * (1 - hc.SHIELD_ELLIPSOID_ROUNDING_FACTOR) 143 cameraBoundLength, innerPaddingValue, outerPaddingValue = self.GetSizeDependantZoomConstants() 144 platformCameraBounds = (cameraBoundLength, cameraBoundLength, cameraBoundLength) 145 innerPadding = (innerPaddingValue, innerPaddingValue, innerPaddingValue) 146 outerPadding = (outerPaddingValue, outerPaddingValue, outerPaddingValue) 147 fullyRoundedEllipsoid = (biggestEllipsoidAxis, biggestEllipsoidAxis, biggestEllipsoidAxis) 148 innerBoundRadius = geo2.Vec3Lerp(self.model.generatedShapeEllipsoidRadius, fullyRoundedEllipsoid, roundFactor) 149 innerBoundRadius = geo2.Vec3Add(innerBoundRadius, innerPadding) 150 preferredOuterBoundRadius = geo2.Vec3Add(geo2.Vec3Scale(innerBoundRadius, hc.SHIELD_ELLIPSOID_ZOOM_MULTIPLIER), outerPadding) 151 outerBoundRadius = tuple((min(ele1, ele2) for ele1, ele2 in zip(preferredOuterBoundRadius, platformCameraBounds))) 152 direction = self.GetLookAtDirection() 153 invertedDirection = geo2.QuaternionInverse(self.model.rotationCurve.currentValue) 154 self.simplifiedDirection = geo2.QuaternionTransformVector(invertedDirection, direction) 155 invertedSimplifiedDirection = geo2.Vec3Scale(self.simplifiedDirection, -1) 156 innerPoint = tuple((ele1 * ele2 for ele1, ele2 in zip(invertedSimplifiedDirection, innerBoundRadius))) 157 outerPoint = tuple((ele1 * ele2 for ele1, ele2 in zip(invertedSimplifiedDirection, outerBoundRadius))) 158 self.distanceToFP = geo2.Vec3Length(geo2.Vec3Lerp(innerPoint, outerPoint, self.zoomFactor)) 159 zoomVec = geo2.Vec3Scale(direction, self.distanceToFP) 160 targetPos = geo2.Vec3Add(self.GetZoomToPoint(), zoomVec) 161 return targetPos 162 163 def GetSizeDependantZoomConstants(self): 164 biggestEllipsoidAxis = max(self.model.generatedShapeEllipsoidRadius) 165 if self.currentShipSizeClass == 0: 166 cbl = hc.SMALL_PLATFORM_CAMERA_BOUNDS + hc.SMALL_PLATFORM_BOUNDING_PADDING * biggestEllipsoidAxis 167 innerBoundsPadding = hc.SMALL_PLATFORM_INNER_PADDING_BOUNDING_SPHERE_FACTOR * biggestEllipsoidAxis 168 return (cbl, hc.SMALL_PLATFORM_INNER_PADDING, hc.SMALL_PLATFORM_OUTER_PADDING) 169 elif self.currentShipSizeClass == 1: 170 cbl = hc.SMALL_PLATFORM_CAMERA_BOUNDS + hc.SMALL_PLATFORM_BOUNDING_PADDING * biggestEllipsoidAxis 171 innerBoundsPadding = hc.SMALL_PLATFORM_INNER_PADDING_BOUNDING_SPHERE_FACTOR * biggestEllipsoidAxis 172 return (cbl, hc.SMALL_PLATFORM_INNER_PADDING + innerBoundsPadding, hc.SMALL_PLATFORM_OUTER_PADDING) 173 elif self.currentShipSizeClass == 2: 174 cbl = hc.MEDIUM_PLATFORM_CAMERA_BOUNDS + hc.MEDIUM_PLATFORM_BOUNDING_PADDING * biggestEllipsoidAxis 175 return (cbl, hc.MEDIUM_PLATFORM_INNER_PADDING, hc.MEDIUM_PLATFORM_OUTER_PADDING) 176 elif self.currentShipSizeClass == 3: 177 self.log.error('capital ship misplaced in the regular hangar') 178 cbl = hc.SMALL_PLATFORM_CAMERA_BOUNDS + hc.SMALL_PLATFORM_BOUNDING_PADDING * biggestEllipsoidAxis 179 innerBoundsPadding = hc.SMALL_PLATFORM_INNER_PADDING_BOUNDING_SPHERE_FACTOR * biggestEllipsoidAxis 180 return (cbl, hc.SMALL_PLATFORM_INNER_PADDING + innerBoundsPadding, hc.SMALL_PLATFORM_OUTER_PADDING) 181 else: 182 return None 183 184 def EnforceMaxZoom(self): 185 if self.changingShip: 186 cameraSpeed = hc.CAMERA_FOLLOW_SPEED / 100.0 187 lerpedTarget = geo2.Vec3Lerp(self.GetEyePosition(), self.targetPoint, cameraSpeed) 188 self.SetEyePosition(lerpedTarget) 189 return 190 if self.changingSkinsTime != 0: 191 cameraSpeed = hc.CAMERA_FOLLOW_SPEED / 100.0 192 lerpedTarget = geo2.Vec3Lerp(self.GetEyePosition(), self.CalculateTargetPoint(), cameraSpeed) 193 self.SetEyePosition(lerpedTarget) 194 return 195 targetPos = self.CalculateTargetPoint() 196 elapsedDuration = GetSecondsSinceSimTime(self.transitionAnimationEndedTime) 197 timeSinceHangarEntry = GetSecondsSinceSimTime(self.hangarEntryTime) 198 if timeSinceHangarEntry > 5 and not self.phase2finished and elapsedDuration < hc.PHASE_2_DURATION: 199 target = geo2.Vec3Add(self.GetEyePosition(), self.camSpeed) 200 blendRamp = (hc.PHASE_1_TO_2_BLEND_DURATION - elapsedDuration) / hc.PHASE_1_TO_2_BLEND_DURATION 201 self.camSpeed = geo2.Vec3Scale(self.camSpeed, 0.6 + 0.4 * blendRamp) 202 phase2Progress = (hc.PHASE_2_DURATION - elapsedDuration) / hc.PHASE_2_DURATION 203 lerpedTarget = geo2.Vec3Lerp(target, targetPos, 1.0 - phase2Progress) 204 self.SetEyePosition(lerpedTarget) 205 if geo2.Vec3DistanceSqD(lerpedTarget, targetPos) < 5.0: 206 self.phase2finished = True 207 else: 208 self.SetEyePosition(geo2.Vec3Lerp(self.GetEyePosition(), targetPos, min(1.0, elapsedDuration))) 209 210 def ClampPitch(self, pitch): 211 if self.model is None: 212 return pitch 213 if self.model.translationCurve is None: 214 return pitch 215 extraPitch = 0 216 try: 217 if self.currentShipSizeClass < 2: 218 thresholds = [hc.SMALL_PLATFORM_GAP_INNER_EDGE, hc.SMALL_PLATFORM_GAP_OUTER_EDGE, hc.SMALL_PLATFORM_OUTER_EDGE] 219 extraAllowance = math.pi / 3.0 220 else: 221 thresholds = [hc.MEDIUM_PLATFORM_GAP_INNER_EDGE, hc.MEDIUM_PLATFORM_GAP_OUTER_EDGE, hc.MEDIUM_PLATFORM_OUTER_EDGE] 222 extraAllowance = math.pi / 6.0 223 lookingAtTheFront = pow(max(self.simplifiedDirection[2], 0.0), 2) 224 frontOffset = self.model.translationCurve.curves[1].value[2] 225 relativeCamPlacementFront = self.distanceToFP + frontOffset 226 frontBoost = min(max(relativeCamPlacementFront * lookingAtTheFront - thresholds[0], 0.0) / thresholds[1], 1.0) 227 lookingRight = -cmp(self.simplifiedDirection[0], 0) 228 centerOffset = self.model.translationCurve.curves[1].value[0] 229 relativeCamPlacement = (self.distanceToFP + lookingRight * centerOffset) * abs(self.simplifiedDirection[0]) 230 gapCenter = (thresholds[0] + thresholds[1]) / 2 231 gapHalfWidth = abs(thresholds[1] - thresholds[0]) / 2 232 closenessToGapCenter = max(gapHalfWidth - abs(relativeCamPlacement - gapCenter), 0.0) / gapHalfWidth 233 closenessToGapCenter = closenessToGapCenter * min(2.0 * max(self.simplifiedDirection[2] + 0.8, 0.0), 1.0) 234 distanceFromPlatformEdge = min(max((relativeCamPlacement - thresholds[2]) / (gapHalfWidth * 4), 0), 1.0) 235 extraPitch = (closenessToGapCenter + distanceFromPlatformEdge + frontBoost) * extraAllowance 236 except Exception as exc: 237 logger.exception('ModularHangarCamera: Ship translationCurve not configured correctly') 238 239 maxPitch = math.pi / 2.0 + extraPitch 240 return max(self.kMinPitch, min(pitch, maxPitch)) 241 242 def GetShipOffset(self): 243 if self.model is None: 244 return (0.0, 0.0, 0.0) 245 localBB = self.model.GetLocalBoundingBox() 246 height = abs(localBB[0][0]) 247 width = abs(localBB[0][2]) 248 return (0.0, height, width) 249 250 def _AnimEnterHangarYaw(self, duration): 251 pass 252 253 def _AnimEnterHangarPitch(self, duration): 254 pass 255 256 def AnimSwitchShips(self, model, startPos, endPos, duration = 5.0): 257 pass 258 259 def Orbit(self, *args): 260 BaseSpaceCamera.Orbit(self, *args) 261 uicore.animations.StopAnimation(self, 'yaw') 262 uicore.animations.StopAnimation(self, 'pitch') 263 264 def OnDeactivated(self): 265 BaseSpaceCamera.OnDeactivated(self) 266 self.model = None 267 268 def Update(self): 269 BaseSpaceCamera.Update(self) 270 if self.model and self.model.translationCurve: 271 if self.changingShip: 272 self._updateShipChangeLocations() 273 self.EnforceMaxZoom() 274 else: 275 self._UpdateFocalPoint() 276 self.EnforceMaxZoom() 277 278 def GetIsChangingShip(self): 279 if self.changingShip or not self.phase2finished: 280 return True 281 return False 282 283 def _updateShipChangeLocations(self): 284 remappedTimings = hc.TRANSITION_TIME_REMAP 285 swapDuration = hc.SHIP_SWAP_DURATION 286 phase1Padding = hc.TRANSITION_PADDING 287 if hc.TRANSITION_MODIFY_BY_HALLWAYTIME: 288 swapDuration = 0.7 * swapDuration + 0.3 * swapDuration * self.hallwayTime 289 phase1Padding = 0.7 * phase1Padding + 0.3 * phase1Padding * self.hallwayTime 290 elapsedDuration = GetSecondsSinceSimTime(self.fpShipSpawnTime) 291 travelProgress = min(elapsedDuration / swapDuration, 1.0) 292 293 def _EndShipSwapping(): 294 self.changingShip = False 295 self.zoomFactor = hc.PHASE_2_END_ZOOM_LEVEL 296 self.transitionAnimationEndedTime = GetSimTime() 297 cameraSpeed = hc.CAMERA_FOLLOW_SPEED / 100.0 298 lerpedTarget = geo2.Vec3Lerp(self.GetEyePosition(), self.targetPoint, cameraSpeed) 299 self.camSpeed = geo2.Vec3Subtract(lerpedTarget, self.GetEyePosition()) 300 self.phase2finished = False 301 302 def _Relevancy(startRelevancy, endRelevancy, boost = 1.0): 303 if boost is 0.0: 304 return 0.0 305 spikeTime = endRelevancy - startRelevancy 306 frontSpike = min(max(travelProgress - startRelevancy, 0.0) / spikeTime, 0.5) 307 backSpike = min(max(travelProgress - (endRelevancy - spikeTime / 2.0), 0.0) / spikeTime, 0.5) 308 return boost * pow(max(frontSpike - backSpike, 0.0), 1 + hc.PATH_BELL_CURVE_CONST / 100) 309 310 points = [hc.PATH_ORIGINAL_POSITION_RELEVANCY, 311 hc.PATH_FIRST_EXIT_RELEVANCY, 312 hc.PATH_FIRST_HALLWAY_POINT_RELEVANCY, 313 hc.PATH_END_HALLWAY_POINT_RELEVANCY, 314 hc.PATH_END_EXIT_RELEVANCY, 315 hc.PATH_END_DOCK_POINT_RELEVANCY] 316 progressMap = [] 317 for point in points: 318 progressMap.append(_Relevancy(point[0], point[1], point[2])) 319 320 targetPoint = (0.0, 0.0, 0.0) 321 for i, each in enumerate(self.flightValueMap): 322 if progressMap[i] != 0: 323 addition = geo2.Vec3Scale(each, progressMap[i]) 324 targetPoint = geo2.Vec3Add(targetPoint, addition) 325 326 total = sum(progressMap) 327 if total == 0: 328 return 329 self.targetPoint = geo2.Vec3Scale(targetPoint, 1 / total) 330 if elapsedDuration > swapDuration: 331 swapThreshold = pow(hc.PHASE_2_START_THRESHOLD * max(self.model.generatedShapeEllipsoidRadius), 2) 332 if geo2.Vec3DistanceSqD(self.GetEyePosition(), self.targetPoint) < swapThreshold: 333 _EndShipSwapping() 334 elif elapsedDuration > swapDuration + phase1Padding: 335 _EndShipSwapping() 336 targetShipPos = self._CalculateFocalPoint(self.model) 337 remappedTravelProgress = min(max(travelProgress - remappedTimings[0], 0.0) / (remappedTimings[1] - remappedTimings[0]), 1.0) 338 if remappedTravelProgress < hc.FP_SWAP_TIMING: 339 lerpValue = hc.FP_SWAP_VALUE * pow(1 / hc.FP_SWAP_TIMING * remappedTravelProgress, hc.FP_SWAP_SPEED) 340 else: 341 reductionValue = max(2 * hc.FP_SWAP_TIMING - remappedTravelProgress, 0.0) 342 reduction = (1 - hc.FP_SWAP_VALUE) * pow(1 / hc.FP_SWAP_TIMING * reductionValue, hc.FP_SWAP_SPEED) 343 lerpValue = 1 - reduction 344 linearPointRelevancy = 1.0 - 0.2 * (0.5 - abs(0.5 - lerpValue)) 345 if lerpValue < 0.5: 346 lerpValue = 2 * pow(lerpValue, 2.0) 347 else: 348 ajustedLerpValue = lerpValue - 0.5 349 lerpValue = 0.5 + 2 * ajustedLerpValue * (1 - ajustedLerpValue) 350 linearPoint = geo2.Vec3Lerp(self.lastShipLocation, targetShipPos, lerpValue) 351 superFloor = geo2.Vec3Add(geo2.Vec3Lerp(self.lastShipLocation, targetShipPos, 0.5), (0.0, -(500.0 + 500 * self.hallwayTime), 0.0)) 352 FPtarget = geo2.Vec3Lerp(superFloor, linearPoint, linearPointRelevancy) 353 self.atPosition = FPtarget 354 355 def _UpdateFocalPoint(self): 356 if self.changingSkinsTime != 0: 357 totalDuration = 5.0 358 elapsedTime = GetSecondsSinceSimTime(self.changingSkinsTime) 359 lerpValue = 0.05 * (elapsedTime / totalDuration) 360 self.atPosition = geo2.Vec3Lerp(self.atPosition, self._CalculateFocalPoint(self.model), lerpValue) 361 timeSinceHangarEntry = GetSecondsSinceSimTime(self.hangarEntryTime) 362 if elapsedTime > totalDuration or timeSinceHangarEntry < 5.0: 363 self.changingSkinsTime = 0 364 else: 365 self.atPosition = self._CalculateFocalPoint(self.model) 366 367 def _CalculateFocalPoint(self, model): 368 if model is None or model.translationCurve is None: 369 return (0.0, 0.0, 0.0) 370 modelTranslation = model.translationCurve.currentValue 371 centerOffset = model.generatedShapeEllipsoidCenter 372 rotatedCenterOffset = geo2.QuaternionTransformVector(self.model.rotationCurve.currentValue, centerOffset) 373 return geo2.Add(modelTranslation, rotatedCenterOffset) 374 375 def SetMinMaxZoomDefaults(self, minZoom, maxZoom): 376 pass 377 378 def SetHangarAnimationParameters(self, yaw, pitch, zoom, fov): 379 pass 380 381 def Zoom(self, dz): 382 if self.zoomTarget is None: 383 self.zoomTarget = self.zoomFactor 384 self.zoomTarget = max(min(1.0, self.zoomTarget + 0.5 * dz), 0.0) 385 if not self.zoomUpdateThread: 386 self.zoomUpdateThread = uthread.new(self.ZoomUpdateThread) 387 388 def SetZoomTarget(self, proportion): 389 pass 390 391 def ZoomUpdateThread(self): 392 try: 393 while True: 394 if self.zoomTarget is None: 395 break 396 distLeft = self.zoomTarget - self.zoomFactor 397 if not distLeft: 398 break 399 zoomSpeed = self._GetZoomSpeed() 400 moveProp = zoomSpeed / blue.os.fps 401 if math.fabs(distLeft) < self.kZoomStopDist: 402 moveProp *= self.kZoomStopDist / math.fabs(distLeft) 403 moveProp = min(moveProp, 1.0) 404 self.zoomFactor += distLeft * moveProp 405 self.SetZoom(self.zoomFactor) 406 if moveProp == 1.0: 407 break 408 self.SetPitch(self.GetPitch()) 409 blue.synchro.Yield() 410 411 finally: 412 self.zoomUpdateThread = None 413 self.zoomTarget = None