cameraUtil.py (12986B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\camera\cameraUtil.py 2 import logging 3 import math 4 import traceback 5 import blue 6 import geo2 7 import destiny 8 import evespacescene 9 import trinity 10 import uthread 11 from carbonui.primitives.base import ScaleDpiF 12 from carbonui.uicore import uicore 13 from carbon.common.lib.const import SEC 14 from evecamera import LOOKATRANGE_MAX_NEW 15 from evecamera.utils import GetARZoomMultiplier 16 from evegraphics import settings as gfxsettings 17 from eveservices.menu import GetMenuService 18 FOV_MIN = 0.55 19 FOV_MAX = 1.1 20 log = logging.getLogger(__name__) 21 22 def IsBobbingEnabled(): 23 return gfxsettings.Get(gfxsettings.UI_CAMERA_BOBBING_ENABLED) 24 25 26 def GetCameraMaxLookAtRange(): 27 return LOOKATRANGE_MAX_NEW 28 29 30 def GetPanVectorForZoomToCursor(viewport, fov): 31 th = math.radians(90 * fov / 2.0) 32 dist = viewport.width / (2.0 * math.tan(th)) 33 u = ScaleDpiF(uicore.uilib.x) 34 x = -u + viewport.x + viewport.width / 2 35 v = ScaleDpiF(uicore.uilib.y) 36 y = v - viewport.y - viewport.height / 2 37 return geo2.Vec3Normalize((x, y, dist)) 38 39 40 def SetShipDirection(camera): 41 scene = sm.GetService('sceneManager').GetRegisteredScene('default') 42 proj = camera.projectionMatrix.transform 43 view = camera.viewMatrix.transform 44 pickDir = scene.PickInfinity(uicore.ScaleDpi(uicore.uilib.x), uicore.ScaleDpi(uicore.uilib.y), proj, view) 45 if pickDir: 46 bp = sm.GetService('michelle').GetRemotePark() 47 if bp is not None: 48 try: 49 x, y, z = pickDir[0], pickDir[1], pickDir[2] 50 bp.CmdGotoDirection(x, y, z) 51 sm.GetService('tacticalNavigation').NotifyOfMoveTowardsPointCommand(pickDir) 52 GetMenuService().ClearAlignTargets() 53 sm.GetService('flightPredictionSvc').GotoDirection(pickDir) 54 except RuntimeError as e: 55 if e.args[0] != 'MonikerSessionCheckFailure': 56 raise e 57 58 59 def GetZoomDz(): 60 dz = CheckInvertZoom(uicore.uilib.dz) 61 return GetPowerOfWithSign(dz) 62 63 64 def CheckInvertZoom(dz): 65 if gfxsettings.Get(gfxsettings.UI_INVERT_CAMERA_ZOOM): 66 return -dz 67 return dz 68 69 70 def GetPowerOfWithSign(value, power = 1.1): 71 return math.copysign(math.fabs(value) ** power, value) 72 73 74 def GetCameraInertiaMultiplier(): 75 multiplier = gfxsettings.Get(gfxsettings.UI_CAMERA_INERTIA) 76 if multiplier < 0: 77 return 1.0 / (1.0 - multiplier) 78 else: 79 return 1.0 + multiplier 80 81 82 def GetCameraSensitivityMultiplier(): 83 multiplier = gfxsettings.Get(gfxsettings.UI_CAMERA_SENSITIVITY) 84 if multiplier < 0: 85 return 1.0 / (1.0 - multiplier) 86 else: 87 return 1.0 + multiplier 88 89 90 def GetDurationByDistance(pos0, pos1, minTime = 0.3, maxTime = 1.0, k = 100000.0): 91 dist = geo2.Vec3Distance(pos0, pos1) 92 duration = max(minTime, min(minTime + (maxTime - minTime) * dist / k, maxTime)) 93 return duration 94 95 96 def GetBallRadius(ball): 97 model = GetBallModel(ball) 98 if model and model.__bluetype__ in evespacescene.EVESPACE_TRINITY_CLASSES: 99 rad = model.GetBoundingSphereRadius() 100 elif model and len(getattr(model, 'children', [])) > 0: 101 rad = model.children[0].GetBoundingSphereRadius() 102 else: 103 rad = None 104 if rad is None or rad <= 0.0: 105 rad = ball.radius * 1.1 106 return rad 107 108 109 def GetBallModel(ball): 110 try: 111 return ball.GetModel() 112 except AttributeError: 113 return None 114 115 116 def GetBallPosition(ball): 117 ballID = ball.id 118 if not ball.ballpark: 119 log.warning('Attempting to use position of a released ball, returning (0, 0, 0) ballID=%s\n%s', ballID, traceback.format_stack()) 120 return (0, 0, 0) 121 else: 122 return _GetBallPosition(ball) 123 124 125 def _GetModelLookAtOffset(model): 126 elpc = trinity.EveLocalPositionCurve() 127 elpc.parent = model 128 elpc.behavior = trinity.EveLocalPositionBehavior.centerBounds 129 locatorSets = getattr(model, 'locatorSets', None) 130 if locatorSets: 131 lookAtLocator = locatorSets.FindByName('camera_look_at') 132 if lookAtLocator is not None and len(lookAtLocator.locators) > 0: 133 elpc.behavior = trinity.EveLocalPositionBehavior.offsetPosition 134 elpc.positionOffset = lookAtLocator.locators[0][0] 135 return elpc 136 137 138 def GetModelLookAtOffset(model): 139 offset = _GetModelLookAtOffset(model) 140 v = offset.GetVectorAt(blue.os.GetSimTime()) 141 return (v.x, v.y, v.z) 142 143 144 def _GetBallPosition(ball): 145 if getattr(ball, 'model', None) and not isinstance(ball.model, trinity.EvePlanet): 146 elpc = _GetModelLookAtOffset(ball.model) 147 elpc.parentPositionCurve = ball 148 elpc.parentRotationCurve = ball 149 vec = elpc.GetVectorAt(blue.os.GetSimTime()) 150 else: 151 vec = ball.GetVectorAt(blue.os.GetSimTime()) 152 return (vec.x, vec.y, vec.z) 153 154 155 def GetSpeedDirection(ball): 156 if getattr(ball, 'model', None) and hasattr(ball.model.rotationCurve, 'value'): 157 quat = ball.model.rotationCurve.value 158 else: 159 quat = ball.GetQuaternionAt(blue.os.GetSimTime()) 160 quat = (quat.x, 161 quat.y, 162 quat.z, 163 quat.w) 164 return geo2.QuaternionTransformVector(quat, (0, 0, 1)) 165 166 167 def GetBall(itemID): 168 bp = sm.GetService('michelle').GetBallpark() 169 if not bp: 170 return None 171 return bp.GetBall(itemID) 172 173 174 def GetBallWaitForModel(ballID): 175 ball = None 176 while ball is None: 177 ball = GetBall(ballID) 178 blue.synchro.Yield() 179 180 while not getattr(ball, 'model', None): 181 blue.synchro.Yield() 182 183 blue.synchro.Yield() 184 return ball 185 186 187 def GetBallMaxZoom(ball, nearClip): 188 rad = GetBallRadius(ball) 189 zoomMultiplier = 1.5 * GetARZoomMultiplier(trinity.GetAspectRatio()) 190 return (rad + nearClip) * zoomMultiplier + 2 191 192 193 def IsBallWarping(itemID): 194 ball = GetBall(itemID) 195 if not ball: 196 return False 197 return ball.mode == destiny.DSTBALL_WARP 198 199 200 def IsAutoTrackingEnabled(): 201 return settings.char.ui.Get('orbitCameraAutoTracking', False) 202 203 204 def IsDynamicCameraMovementEnabled(): 205 return gfxsettings.Get(gfxsettings.UI_CAMERA_DYNAMIC_CAMERA_MOVEMENT) 206 207 208 def CheckShowModelTurrets(ball): 209 if hasattr(ball, 'LookAtMe'): 210 uthread.new(ball.LookAtMe) 211 212 213 def IsNanVector3(values): 214 for value in values: 215 if math.isnan(value): 216 return True 217 218 return False 219 220 221 def IsInfVector3(values): 222 for value in values: 223 if math.fabs(value) > 1e+38: 224 return True 225 226 return False 227 228 229 MAX_SPACE_CAMERA_COORDINATE = 1000000000000.0 230 231 def IsValidSpaceCameraPosition(values): 232 return all((math.fabs(value) <= MAX_SPACE_CAMERA_COORDINATE for value in values)) 233 234 235 def SolveQuadratic(a, b, c): 236 d = math.sqrt(b ** 2 - 4 * a * c) 237 x1 = -2 * c / (b + d) 238 x2 = -2 * c / (b - d) 239 return max(x1, x2) 240 241 242 def GetFullscreenProjectionViewAndViewport(): 243 viewport = trinity.device.viewport 244 camera = sm.GetService('sceneManager').GetActiveCamera() 245 return (camera.projectionMatrix, camera.viewMatrix, viewport) 246 247 248 def GetInitialLookAtDistance(maxZoom, minZoom, objRadius = None): 249 kPower = 0.95 250 a = 1.0 / minZoom ** kPower 251 b = FOV_MIN / 2.0 252 r = objRadius or maxZoom 253 r = max(objRadius, maxZoom) 254 c = -r 255 radius = SolveQuadratic(a, b, c) 256 return radius 257 258 259 def GetPixelSizeAcrossEst(position, radius, camPos, projectionMatrix): 260 viewPort = trinity.device.viewport 261 dist = max(geo2.Vec3Distance(position, camPos), 1e-05) 262 ratio = radius / dist 263 return ratio * projectionMatrix[0][0] * viewPort.width 264 265 266 class Vector3Chaser(object): 267 268 def __init__(self, speed = 1.0): 269 self._value = (0, 0, 0) 270 self._targetValue = None 271 self._speed = speed 272 self._updateTime = None 273 274 def GetValue(self): 275 if self._updateTime != blue.os.GetTime(): 276 self.Update() 277 return self._value 278 279 def SetTargetValue(self, value, speed = None): 280 if IsNanVector3(value): 281 log.warning('Camera: Attempting to set an invalid value: %s\n%s', repr(value), traceback.format_stack()) 282 return 283 self._targetValue = value 284 if speed is not None: 285 self._speed = speed 286 287 def Update(self): 288 self._updateTime = blue.os.GetTime() 289 if not self._targetValue or self._targetValue == self._value: 290 return 291 if self._speed == 0.0: 292 return 293 dt = 1.0 / blue.os.fps 294 diff = geo2.Vec3Subtract(self._targetValue, self._value) 295 prop = dt * (1.0 * self._speed) 296 prop = min(1.0, prop) 297 dV = geo2.Vec3Scale(diff, prop) 298 self._value = geo2.Vec3Add(self._value, dV) 299 if prop == 1.0: 300 self._targetValue = None 301 302 def ResetValue(self, speed = None): 303 if speed is None: 304 self._value = (0, 0, 0) 305 self._targetValue = None 306 else: 307 self.SetTargetValue((0, 0, 0), speed) 308 309 310 class VectorLerper(object): 311 __notifyevents__ = ['DoSimClockRebase'] 312 313 def __init__(self, duration = 1.0): 314 sm.RegisterNotify(self) 315 self.duration = duration 316 self.Reset() 317 318 def Reset(self, duration = None): 319 if duration: 320 self.duration = duration 321 self._v0 = (0, 0, 0) 322 self._v1 = (0, 0, 0) 323 self.startTime = blue.os.GetSimTime() 324 325 def SetStartValue(self, value): 326 self._v0 = value 327 328 def GetValue(self, v0 = None, v1 = None): 329 if v0 is None: 330 v0 = self._v0 331 t = self.GetTime() 332 if self._IsTimePastDuration(t): 333 self._v1 = v1 334 elif hasattr(v0, '__iter__'): 335 self._v1 = geo2.Lerp(v0, v1, t / self.duration) 336 else: 337 self._v1 = v0 + (v1 - v0) * t 338 return self._v1 339 340 def GetLastValue(self): 341 return self._v1 342 343 def IsDone(self): 344 t = self.GetTime() 345 return self._IsTimePastDuration(t) 346 347 def _IsTimePastDuration(self, t): 348 return t >= self.duration 349 350 def GetTime(self): 351 return (blue.os.GetSimTime() - self.startTime) / float(SEC) 352 353 def DoSimClockRebase(self, rebaseTimes): 354 oldSimTime, newSimTime = rebaseTimes 355 delta = newSimTime - oldSimTime 356 self.startTime += delta 357 358 359 class PositionAnimatorDetached(object): 360 361 def __init__(self, camera): 362 self.camera = camera 363 self.ball = None 364 self.positionDiff = (0, 0, 0) 365 self.ballPosLast = None 366 self.SetAbstractBall() 367 368 def GetAtPosition(self): 369 return geo2.Vec3Add(self.camera._atPosition, self.positionDiff) 370 371 def Update(self): 372 if not self.ball: 373 return 374 ballPos = GetBallPosition(self.ball) 375 if self.ballPosLast: 376 self.positionDiff = geo2.Vec3SubtractD(ballPos, self.ballPosLast) 377 self.ballPosLast = ballPos 378 379 def GetEyePosition(self): 380 return geo2.Vec3Add(self.camera._eyePosition, self.positionDiff) 381 382 def _SetBall(self, ball, animate, duration): 383 self.positionDiff = (0, 0, 0) 384 self.ballPosLast = None 385 self.ball = ball 386 self.Update() 387 388 def SetAbstractBall(self, animate = True, duration = 0.6): 389 bp = self._GetBallpark() 390 if not bp: 391 return 392 pos = bp.GetCurrentEgoPos() 393 if self.ball: 394 pos = geo2.Vec3AddD(pos, GetBallPosition(self.ball)) 395 ball = bp.AddClientSideBall(pos) 396 self._SetBall(ball, animate, 0.0) 397 398 def _GetBallpark(self): 399 michelle = sm.GetServiceIfRunning('michelle') 400 if not michelle: 401 return None 402 return michelle.GetBallpark() 403 404 def IsAttached(self): 405 return False 406 407 def GetItemID(self): 408 if self.ball: 409 return self.ball.id 410 411 def Reset(self): 412 self._SetBall(None, False, 0) 413 414 415 class PositionAnimatorAttached(object): 416 417 def __init__(self, camera, ball, duration): 418 self.camera = camera 419 self.ball = ball 420 self.atPosition = camera._atPosition 421 self.atPositionDiff = (0, 0, 0) 422 self.SetBall(ball, duration) 423 424 def GetAtPosition(self): 425 return self.atPosition 426 427 def Update(self): 428 if not self.ball: 429 return (0, 0, 0) 430 atPosLast = self.atPosition 431 if self.GetItemID() == self.camera.ego: 432 self.atPosition = (0, 0, 0) 433 else: 434 self.atPosition = GetBallPosition(self.ball) 435 self.atPositionDiff = geo2.Vec3SubtractD(self.atPosition, atPosLast) 436 437 def GetEyePosition(self): 438 ret = self.camera._eyePosition 439 if self.GetItemID() != session.shipid: 440 ret = geo2.Vec3AddD(ret, self.atPositionDiff) 441 return ret 442 443 def SetBall(self, ball, duration = 0.6): 444 self._SetBall(ball, duration) 445 446 def _SetBall(self, ball, duration): 447 self.ball = ball 448 449 def GetItemID(self): 450 if self.ball: 451 return self.ball.id 452 453 def IsAttached(self): 454 return True 455 456 def Reset(self): 457 self._SetBall(None, 0)