dungeonEditorTools.py (37575B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\parklife\dungeonEditorTools.py 2 import math 3 from ballparkCommon.ballRadius import ComputeQuantityFromRadius 4 import trinity 5 from eve.client.script.parklife import dungeonEditorToolGeometry 6 import geo2 7 from eve.client.script.ui.util import uix 8 import carbonui.const as uiconst 9 from carbonui.uicore import uicore 10 X_AXIS = geo2.Vector(1.0, 0.0, 0.0) 11 Y_AXIS = geo2.Vector(0.0, 1.0, 0.0) 12 Z_AXIS = geo2.Vector(0.0, 0.0, 1.0) 13 CHANGE_NONE = 0 14 CHANGE_TRANSLATION = 1 15 CHANGE_ROTATION = 2 16 CHANGE_SCALE = 4 17 18 def GetRayAndPointFromScreen(x, y): 19 proj, view, vp = uix.GetFullscreenProjectionViewAndViewport() 20 ray, start = trinity.device.GetPickRayFromViewport(x, y, vp, view.transform, proj.transform) 21 ray = geo2.Vector(*ray) 22 start = geo2.Vector(*start) 23 return (ray, start) 24 25 26 def RayToPlaneIntersection(P, d, Q, n): 27 denom = geo2.Vec3Dot(n, d) 28 if abs(denom) < 1e-05: 29 return P 30 else: 31 distance = -geo2.Vec3Dot(Q, n) 32 t = -(geo2.Vec3Dot(n, P) + distance) / denom 33 scaledRay = geo2.Scale(d, t) 34 ret = geo2.Add(scaledRay, P) 35 return geo2.Vector(*ret) 36 37 38 def ProjectPointTowardsFrontPlane(point, dist = 7.0): 39 ppos = point 40 viewMat = trinity.GetViewTransform() 41 cpos = geo2.Vector(*trinity.GetViewPosition()) 42 dir = geo2.Vec3Normalize(geo2.Subtract(cpos, ppos)) 43 lookat = geo2.Vector(viewMat[0][2], viewMat[1][2], viewMat[2][2]) 44 point = cpos + lookat * dist 45 return RayToPlaneIntersection(ppos, dir, point, lookat) 46 47 48 def CameraFacingMatrix(objtransform): 49 viewMat = trinity.GetViewTransform() 50 objInv = geo2.MatrixInverse(objtransform) 51 viewInv = geo2.MatrixInverse(viewMat) 52 viewInv = geo2.MatrixMultiply(viewInv, objInv) 53 rmat = geo2.MatrixRotationX(math.pi * 0.5) 54 rmat = geo2.MatrixMultiply(rmat, viewInv) 55 rmat = (rmat[0], 56 rmat[1], 57 rmat[2], 58 (0.0, 59 0.0, 60 0.0, 61 rmat[3][3])) 62 return rmat 63 64 65 class BaseTool(): 66 67 def __init__(self, geometry, view, projection): 68 self.geometry = geometry 69 self.view = view 70 self.projection = projection 71 self.display = True 72 self.worldTranslation = geo2.MatrixIdentity() 73 self.frontPlaneTranslation = geo2.MatrixIdentity() 74 75 def ApplyTransform(self): 76 pass 77 78 def onActivated(self): 79 pass 80 81 def Cull(self, areas): 82 return areas 83 84 def GetTargetPlaneProjectionMatrix(self): 85 trans = self.GetTranslation() 86 adjusted_translation = ProjectPointTowardsFrontPlane(trans) 87 rmat = geo2.MatrixRotationQuaternion(self.GetRotation()) 88 rmat = geo2.MatrixTranspose(rmat) 89 mat = geo2.MatrixTranslation(adjusted_translation.x, adjusted_translation.y, adjusted_translation.z) 90 self.frontPlaneTranslation = geo2.MatrixMultiply(rmat, mat) 91 return self.frontPlaneTranslation 92 93 def Show(self): 94 self.transformed = False 95 areas = self.geometry.areas 96 for each in areas: 97 each.display = True 98 99 self.display = True 100 101 def Hide(self): 102 self.display = False 103 areas = self.geometry.areas 104 for each in areas: 105 each.display = False 106 107 def IsShown(self): 108 return self.display 109 110 def UpdatePrimitives(self): 111 self.geometry.Update(self.worldTranslation) 112 self._InternalUpdate() 113 114 def Translate(self, amount): 115 self.worldTranslation = list(self.worldTranslation) 116 self.worldTranslation[3] = (amount[0], 117 amount[1], 118 amount[2], 119 self.worldTranslation[3][3]) 120 121 def GetTranslation(self): 122 return geo2.Vector(self.worldTranslation[3][0], self.worldTranslation[3][1], self.worldTranslation[3][2]) 123 124 def Rotate(self, rot): 125 self.worldTranslation = geo2.MatrixRotationQuaternion(rot) 126 127 def GetRotation(self): 128 scale, rotation, translation = geo2.MatrixDecompose(self.worldTranslation) 129 rotation = geo2.QuaternionInverse(rotation) 130 return rotation 131 132 def Scale(self, scale): 133 pass 134 135 def GetScale(self): 136 scale, rotation, translation = geo2.MatrixDecompose(self.worldTranslation) 137 return scale 138 139 def GetUpVec(self): 140 transForm = self.worldTranslation 141 return geo2.Vector(transForm[1][0], transForm[1][1], transForm[1][2]) 142 143 def GetFrontVec(self): 144 transForm = self.worldTranslation 145 v = geo2.Vector(transForm[2][0], transForm[2][1], transForm[2][2]) 146 return v 147 148 def GetRightVec(self): 149 transForm = self.worldTranslation 150 v = geo2.Vector(transForm[0][0], transForm[0][1], transForm[0][2]) 151 return v 152 153 def _InternalUpdate(self): 154 pass 155 156 157 class TransformationTool(BaseTool): 158 159 def __init__(self, view, projection, primitiveScene): 160 self.primitiveScene = primitiveScene 161 BaseTool.__init__(self, self.GenGeometry(), view, projection) 162 self.originalLocation = {'x': geo2.Vector(0.0, 0.0, 0.0), 163 'y': geo2.Vector(0.0, 0.0, 0.0), 164 'z': geo2.Vector(0.0, 0.0, 0.0), 165 'w': geo2.Vector(0.0, 0.0, 0.0)} 166 self.activeManipAxis = None 167 self.targetPlaneNormal = None 168 self.captured = False 169 self.SetDefaultColors() 170 self.preX = 0 171 self.preY = 0 172 self.curX = 0 173 self.curY = 0 174 self.invalidAxes = [] 175 176 def InvalidateAxes(self, axisList): 177 for axis in axisList: 178 if axis not in self.invalidAxes: 179 self.invalidAxes.append(axis) 180 self.HideAxis(axis) 181 182 def ValidateAxes(self, axisList): 183 for axis in axisList: 184 if axis in self.invalidAxes: 185 self.invalidAxes.remove(axis) 186 self.ShowAxis(axis) 187 188 def ValidateAllAxes(self): 189 self.ValidateAxes(['x', 190 'y', 191 'z', 192 'w', 193 'ww']) 194 195 def PickPrimitiveScene(self, x, y): 196 camera = sm.GetService('sceneManager').GetActiveCamera() 197 view = trinity.TriView() 198 view.transform = camera.viewMatrix.transform 199 proj = trinity.TriProjection() 200 p = camera.projectionMatrix.transform 201 proj.CustomProjection(p) 202 res = self.primitiveScene.PickObject(x, y, proj, view, trinity.device.viewport) 203 if res and res.name in self.PickableAxis(): 204 return res.name 205 else: 206 return None 207 208 def PickableAxis(self): 209 return ['x', 210 'y', 211 'z', 212 'w', 213 'ww'] 214 215 def PickAxis(self, x, y): 216 ray, start = GetRayAndPointFromScreen(x, y) 217 axis = self.PickPrimitiveScene(x, y) 218 self.SetDefaultColors() 219 if axis: 220 self.activeManipAxis = axis 221 self.ColorActiveAxis() 222 self.targetPlaneNormal = self.GetDesiredPlaneNormal(ray) 223 if self.targetPlaneNormal: 224 self.startPlanePos = RayToPlaneIntersection(start, ray, self.GetTranslation(), self.targetPlaneNormal) 225 self.CaptureAxis() 226 return axis 227 228 def SetDefaultColors(self): 229 for each in self.geometry.areas: 230 if each.name == 'x': 231 each.SetColor(dungeonEditorToolGeometry.RED) 232 elif each.name == 'y': 233 each.SetColor(dungeonEditorToolGeometry.GREEN) 234 elif each.name == 'z': 235 each.SetColor(dungeonEditorToolGeometry.BLUE) 236 elif each.name == 'w': 237 each.SetColor(dungeonEditorToolGeometry.CYAN) 238 239 def ColorComponent(self, name, color): 240 for each in self.geometry.areas: 241 if each.name == name: 242 each.SetColor(color) 243 244 def ColorActiveAxis(self): 245 self.ColorComponent(self.activeManipAxis, dungeonEditorToolGeometry.YELLOW) 246 247 def CaptureAxis(self): 248 for each in self.geometry.areas: 249 if each.name == self.activeManipAxis: 250 each.display = True 251 252 self.captured = True 253 254 def ReleaseAxis(self): 255 self.ShowAllAxis() 256 for axis in self.invalidAxes: 257 self.HideAxis(axis) 258 259 self.SetDefaultColors() 260 self.activeManipAxis = None 261 self.targetPlaneNormal = None 262 self.captured = False 263 264 def ShowAllAxis(self): 265 for each in self.geometry.areas: 266 each.display = True 267 268 def HideAllAxis(self): 269 for each in self.geometry.areas: 270 each.display = False 271 272 def HideAxis(self, name): 273 for each in self.geometry.areas: 274 if each.name == name: 275 each.display = False 276 277 def ShowAxis(self, name): 278 for each in self.geometry.areas: 279 if each.name == name: 280 each.display = True 281 282 def Transform(self, x, y): 283 self.curX = x 284 self.curY = y 285 if self.activeManipAxis: 286 dev = trinity.device 287 ray, start = GetRayAndPointFromScreen(x, y) 288 if self.targetPlaneNormal: 289 diff = self._DiffProjectedPoint(ray, start) 290 self._TransformContext(self._TransformAxis(diff)) 291 self.preX = x 292 self.preY = y 293 294 def GetDesiredPlaneNormal(self, ray): 295 x_axis = X_AXIS 296 y_axis = Y_AXIS 297 z_axis = Z_AXIS 298 if self.activeManipAxis: 299 if self.activeManipAxis == 'x': 300 ydot = abs(geo2.Vec3Dot(ray, y_axis)) 301 zdot = abs(geo2.Vec3Dot(ray, z_axis)) 302 if zdot > ydot: 303 return z_axis 304 if ydot > zdot: 305 return y_axis 306 elif self.activeManipAxis == 'y': 307 zdot = abs(geo2.Vec3Dot(ray, z_axis)) 308 xdot = abs(geo2.Vec3Dot(ray, x_axis)) 309 if zdot > xdot: 310 return z_axis 311 if xdot > zdot: 312 return x_axis 313 elif self.activeManipAxis == 'z': 314 xdot = abs(geo2.Vec3Dot(ray, x_axis)) 315 ydot = abs(geo2.Vec3Dot(ray, y_axis)) 316 if xdot > ydot: 317 return x_axis 318 if ydot > xdot: 319 return y_axis 320 else: 321 viewMat = trinity.GetViewTransform() 322 return geo2.Vector(viewMat[0][2], viewMat[1][2], viewMat[2][2]) 323 else: 324 return None 325 326 def _DiffProjectedPoint(self, ray, start): 327 self.endPlanePos = RayToPlaneIntersection(start, ray, self.GetTranslation(), self.targetPlaneNormal) 328 displacement = self.endPlanePos - self.startPlanePos 329 self.startPlanePos = self.endPlanePos 330 if self.activeManipAxis == 'w': 331 finalDisplacement = displacement 332 else: 333 if self.activeManipAxis == 'x': 334 dir = self.GetRightVec() 335 elif self.activeManipAxis == 'y': 336 dir = self.GetUpVec() 337 elif self.activeManipAxis == 'z': 338 dir = self.GetFrontVec() 339 dir = geo2.Vec3Normalize(dir) 340 scaledDir = geo2.Vec3Scale(dir, geo2.Vec3Dot(displacement, dir)) 341 finalDisplacement = scaledDir 342 return finalDisplacement 343 344 def _TransformContext(self, v): 345 pass 346 347 def _TransformAxis(self, v): 348 if self.activeManipAxis != 'w': 349 ret = geo2.Vector(*v) 350 worldTransInv = geo2.MatrixInverse(self.worldTranslation) 351 v = geo2.Vec3TransformNormal(v, worldTransInv) 352 t = self.GetTranslation() 353 self.Translate(t + v) 354 return ret 355 return v 356 357 358 class TranslationTool(TransformationTool): 359 360 def __init__(self, view, projection, primitiveScene): 361 self.cones = [] 362 self.axes = [] 363 TransformationTool.__init__(self, view, projection, primitiveScene) 364 self.action = None 365 366 def GenGeometry(self): 367 rotateMat = geo2.MatrixRotationZ(-math.pi / 2.0) 368 transform = geo2.MatrixTranslation(0.0, 1.0, 0.0) 369 transform = geo2.MatrixMultiply(transform, rotateMat) 370 c_tris = geo2.Vec3TransformCoordArray(dungeonEditorToolGeometry.CONE_TRIS, transform) 371 xTransAreaCone = dungeonEditorToolGeometry.area('x', dungeonEditorToolGeometry.RED) 372 xTransAreaCone.AddToSolidSet(c_tris) 373 xTransAreaAxis = dungeonEditorToolGeometry.area('x', dungeonEditorToolGeometry.RED) 374 xTransAreaAxis.AddToLineSet([(0.0, 0.0, 0.0), (1.0, 0.0, 0.0)]) 375 t = dungeonEditorToolGeometry.GetSolidAroundLine([(0.3, 0.0, 0.0), (1.0, 0.0, 0.0)], 0.08) 376 xTransAreaAxis.AddToPickingSet(t) 377 transform = geo2.MatrixTranslation(0.0, 1.0, 0.0) 378 c_tris = geo2.Vec3TransformCoordArray(dungeonEditorToolGeometry.CONE_TRIS, transform) 379 yTransAreaCone = dungeonEditorToolGeometry.area('y', dungeonEditorToolGeometry.GREEN) 380 yTransAreaCone.AddToSolidSet(c_tris) 381 yTransAreaAxis = dungeonEditorToolGeometry.area('y', dungeonEditorToolGeometry.GREEN) 382 yTransAreaAxis.AddToLineSet([(0.0, 0.0, 0.0), (0.0, 1.0, 0.0)]) 383 t = dungeonEditorToolGeometry.GetSolidAroundLine([(0.0, 0.3, 0.0), (0.0, 1.0, 0.0)], 0.08) 384 yTransAreaAxis.AddToPickingSet(t) 385 transform = geo2.MatrixTranslation(0.0, 1.0, 0.0) 386 rotateMat = geo2.MatrixRotationX(math.pi / 2.0) 387 transform = geo2.MatrixMultiply(transform, rotateMat) 388 c_tris = geo2.Vec3TransformCoordArray(dungeonEditorToolGeometry.CONE_TRIS, transform) 389 zTransAreaCone = dungeonEditorToolGeometry.area('z', dungeonEditorToolGeometry.BLUE) 390 zTransAreaCone.AddToSolidSet(c_tris) 391 zTransAreaAxis = dungeonEditorToolGeometry.area('z', dungeonEditorToolGeometry.BLUE) 392 zTransAreaAxis.AddToLineSet([(0.0, 0.0, 0.0), (0.0, 0.0, 1.0)]) 393 t = dungeonEditorToolGeometry.GetSolidAroundLine([(0.0, 0.0, 0.3), (0.0, 0.0, 1.0)], 0.08) 394 zTransAreaAxis.AddToPickingSet(t) 395 wTransAreaPlane = dungeonEditorToolGeometry.area('w', dungeonEditorToolGeometry.CYAN) 396 wTransAreaPlane.AddToLineSet(dungeonEditorToolGeometry.CIRCLE_POINTS_QUART) 397 wTransAreaPlane._lineset.viewOriented = True 398 picking_tris = dungeonEditorToolGeometry.GenCircleTriangles(0.25) 399 if not trinity.IsRightHanded(): 400 picking_tris.reverse() 401 wTransAreaPlane.AddToPickingSet(picking_tris) 402 translationGeo = dungeonEditorToolGeometry.geometry(self.primitiveScene) 403 translationGeo.AppendArea(wTransAreaPlane) 404 translationGeo.AppendArea(xTransAreaCone) 405 translationGeo.AppendArea(xTransAreaAxis) 406 translationGeo.AppendArea(yTransAreaCone) 407 translationGeo.AppendArea(yTransAreaAxis) 408 translationGeo.AppendArea(zTransAreaCone) 409 translationGeo.AppendArea(zTransAreaAxis) 410 self.cones.append(xTransAreaCone) 411 self.cones.append(yTransAreaCone) 412 self.cones.append(zTransAreaCone) 413 self.axes.append(xTransAreaAxis) 414 self.axes.append(yTransAreaAxis) 415 self.axes.append(zTransAreaAxis) 416 return translationGeo 417 418 def _TransformContext(self, v): 419 scenarioSvc = sm.StartService('scenario') 420 michelleSvc = sm.StartService('michelle') 421 for slimItem in scenarioSvc.GetSelObjects(): 422 if slimItem.dunObjectID in scenarioSvc.GetLockedObjects(): 423 if uicore.uilib.Key(uiconst.VK_CONTROL): 424 scenarioSvc.UnlockObject(slimItem.itemID, slimItem.dunObjectID, force=True) 425 else: 426 continue 427 targetBall = michelleSvc.GetBall(slimItem.itemID) 428 targetModel = getattr(targetBall, 'model', None) 429 if targetModel: 430 targetModel.translationCurve.x += v.x 431 targetModel.translationCurve.y += v.y 432 targetModel.translationCurve.z += v.z 433 else: 434 try: 435 targetTransform = scenarioSvc.fakeTransforms[slimItem.itemID] 436 targetTransform.translationCurve.x += v.x 437 targetTransform.translationCurve.y += v.y 438 targetTransform.translationCurve.z += v.z 439 except KeyError: 440 scenarioSvc.LogError('Unable to translate any ball for dungeon object:', slimItem.dunObjectID) 441 442 slimItem.dunX += v.x 443 slimItem.dunY += v.y 444 slimItem.dunZ += v.z 445 scenarioSvc.UpdateUnsavedObjectChanges(slimItem.itemID, CHANGE_TRANSLATION) 446 447 def _InternalUpdate(self): 448 mat = CameraFacingMatrix(self.worldTranslation) 449 area = self.geometry.GetArea('w') 450 area.localTransform = mat 451 452 453 class ScalingTool(TransformationTool): 454 455 def __init__(self, view, projection, primitiveScene): 456 TransformationTool.__init__(self, view, projection, primitiveScene) 457 self.preLength = 1.0 458 self.action = None 459 self.state = None 460 self.initial_scaling = {} 461 self.initial_position = {} 462 self.targetPos = None 463 self.scale = geo2.Vector(1.0, 1.0, 1.0) 464 self.startPos = None 465 self.startScreenX = 0 466 self.toolPosition = None 467 468 def GenGeometry(self): 469 scalingGeo = dungeonEditorToolGeometry.geometry(self.primitiveScene) 470 wBox = dungeonEditorToolGeometry.area('w', dungeonEditorToolGeometry.CYAN) 471 wBox.AddToSolidSet(dungeonEditorToolGeometry.CUBE_TRIS) 472 xBox = dungeonEditorToolGeometry.area('x', dungeonEditorToolGeometry.RED) 473 transform = geo2.MatrixTranslation(1.0, 0.0, 0.0) 474 x_tris = geo2.Vec3TransformCoordArray(dungeonEditorToolGeometry.CUBE_TRIS, transform) 475 xBox.AddToSolidSet(x_tris) 476 xBox.AddToLineSet(((0.0, 0.0, 0.0), (1.0, 0.0, 0.0))) 477 transform = geo2.MatrixTranslation(0.0, 1.0, 0.0) 478 y_tris = geo2.Vec3TransformCoordArray(dungeonEditorToolGeometry.CUBE_TRIS, transform) 479 yBox = dungeonEditorToolGeometry.area('y', dungeonEditorToolGeometry.GREEN) 480 yBox.AddToSolidSet(y_tris) 481 yBox.AddToLineSet(((0.0, 0.0, 0.0), (0.0, 1.0, 0.0))) 482 transform = geo2.MatrixTranslation(0.0, 0.0, 1.0) 483 z_tris = geo2.Vec3TransformCoordArray(dungeonEditorToolGeometry.CUBE_TRIS, transform) 484 zBox = dungeonEditorToolGeometry.area('z', dungeonEditorToolGeometry.BLUE) 485 zBox.AddToSolidSet(z_tris) 486 zBox.AddToLineSet(((0.0, 0.0, 0.0), (0.0, 0.0, 1.0))) 487 scalingGeo.AppendArea(xBox) 488 scalingGeo.AppendArea(yBox) 489 scalingGeo.AppendArea(zBox) 490 scalingGeo.AppendArea(wBox) 491 return scalingGeo 492 493 def GetInitialScaling(self): 494 self.axis = {'x': self.GetRightVec(), 495 'y': self.GetUpVec(), 496 'z': self.GetFrontVec()} 497 maxScale = 0.0 498 for slimItem in sm.GetService('scenario').GetSelObjects(): 499 targetBall = sm.GetService('michelle').GetBall(slimItem.itemID) 500 targetModel = getattr(targetBall, 'model', None) 501 if not targetModel: 502 return 503 if hasattr(targetModel, 'scaling'): 504 maxScale = max(maxScale, targetModel.scaling.x) 505 506 geo2.Vector(maxScale, maxScale, maxScale) 507 508 def CaptureAxis(self): 509 self.scale = geo2.Vector(1.0, 1.0, 1.0) 510 self.startScreenX = self.curX 511 self.toolPosition = sm.GetService('scenario').GetSelectionCenter() 512 513 def ReleaseAxis(self): 514 TransformationTool.ReleaseAxis(self) 515 self.state = None 516 self.targetPos = None 517 self.startPos = None 518 self.initial_scaling = {} 519 self.initial_position = {} 520 self.toolPosition = None 521 for slimItem in sm.GetService('scenario').GetSelObjects(): 522 slimItem.initialRadius = None 523 524 def _TransformContext(self, v): 525 scenarioMgr = sm.StartService('scenario') 526 michelleSvc = sm.StartService('michelle') 527 dungeonOrigin = scenarioMgr.GetDungeonOrigin() 528 toolPositionX, toolPositionY, toolPositionZ = sm.GetService('scenario').GetSelectionCenter() 529 toolOffset = (self.toolPosition[0] - dungeonOrigin.x, self.toolPosition[1] - dungeonOrigin.y, self.toolPosition[2] - dungeonOrigin.z) 530 godma = sm.GetService('godma') 531 slimItems = scenarioMgr.GetSelObjects() 532 for slimItem in slimItems: 533 if slimItem.dunObjectID in sm.GetService('scenario').GetLockedObjects(): 534 if uicore.uilib.Key(uiconst.VK_CONTROL): 535 scenarioMgr.UnlockObject(slimItem.itemID, slimItem.dunObjectID, force=True) 536 else: 537 continue 538 targetBall = michelleSvc.GetBall(slimItem.itemID) 539 targetModel = getattr(targetBall, 'model', None) 540 if not targetModel: 541 continue 542 if slimItem.groupID in (const.groupHarvestableCloud, const.groupCloud) and hasattr(targetModel, 'scaling'): 543 if slimItem.itemID not in self.initial_scaling: 544 self.initial_scaling[slimItem.itemID] = trinity.TriVector(targetModel.scaling.x, targetModel.scaling.y, targetModel.scaling.z) 545 initialScaling = self.initial_scaling[slimItem.itemID] 546 scaleVector = trinity.TriVector(initialScaling.x * self.scale.x, initialScaling.y * self.scale.y, initialScaling.z * self.scale.z) 547 targetModel.scaling = scaleVector 548 slimItem.dunRadius = ComputeQuantityFromRadius(slimItem.categoryID, slimItem.groupID, slimItem.typeID, targetModel.scaling.x / 2.0, godma) 549 scenarioMgr.UpdateUnsavedObjectChanges(slimItem.itemID, CHANGE_SCALE) 550 elif slimItem.categoryID == const.categoryAsteroid and hasattr(targetModel, 'modelScale'): 551 if slimItem.itemID not in self.initial_scaling: 552 self.initial_scaling[slimItem.itemID] = targetModel.modelScale 553 targetModel.modelScale = self.initial_scaling[slimItem.itemID] * self.scale.x 554 slimItem.dunRadius = ComputeQuantityFromRadius(slimItem.categoryID, slimItem.groupID, slimItem.typeID, targetModel.modelScale, godma) 555 scenarioMgr.UpdateUnsavedObjectChanges(slimItem.itemID, CHANGE_SCALE) 556 if len(slimItems) > 1 and not uicore.uilib.Key(uiconst.VK_SHIFT): 557 if slimItem.itemID not in self.initial_position: 558 self.initial_position[slimItem.itemID] = ((targetModel.translationCurve.x, targetModel.translationCurve.y, targetModel.translationCurve.z), (slimItem.dunX, slimItem.dunY, slimItem.dunZ)) 559 initialWorldPosition, initialDungeonPosition = self.initial_position[slimItem.itemID] 560 relativeObjectPosition = trinity.TriVector(initialDungeonPosition[0] - toolOffset[0], initialDungeonPosition[1] - toolOffset[1], initialDungeonPosition[2] - toolOffset[2]) 561 scaledPosition = trinity.TriVector(relativeObjectPosition.x * self.scale.x, relativeObjectPosition.y * self.scale.y, relativeObjectPosition.z * self.scale.z) 562 targetModel.translationCurve.x = scaledPosition.x + self.toolPosition[0] 563 targetModel.translationCurve.y = scaledPosition.y + self.toolPosition[1] 564 targetModel.translationCurve.z = scaledPosition.z + self.toolPosition[2] 565 slimItem.dunX = scaledPosition.x + toolOffset[0] 566 slimItem.dunY = scaledPosition.y + toolOffset[1] 567 slimItem.dunZ = scaledPosition.z + toolOffset[2] 568 scenarioMgr.UpdateUnsavedObjectChanges(slimItem.itemID, CHANGE_TRANSLATION) 569 570 def _TransformAxis(self, v): 571 dev = trinity.device 572 pos = self.GetTranslation() 573 if self.activeManipAxis == 'w': 574 self.targetPos = pos - self.endPlanePos 575 scale = abs(1.0 + float(self.curX - self.startScreenX) / dev.width * 4.0) 576 self.scale = geo2.Vector(scale, scale, scale) 577 else: 578 dir = self.axis[self.activeManipAxis] 579 self.targetPos = geo2.Vec3Scale(dir, geo2.Vec3Dot(pos - self.endPlanePos, dir)) 580 if not self.startPos: 581 self.startPos = self.targetPos 582 start_len = geo2.Vec3Length(self.startPos) 583 current_len = geo2.Vec3Length(self.targetPos) 584 scale = current_len / start_len 585 if geo2.Vec3Dot(self.startPos, self.targetPos) < 0: 586 scale = -scale 587 scale = abs(scale) 588 self.scale = geo2.Vector(scale, scale, scale) 589 return v 590 591 def _InternalUpdate(self): 592 if not self.state: 593 self.GetInitialScaling() 594 self.state = 'start' 595 if self.activeManipAxis: 596 if self.activeManipAxis == 'w': 597 scale = self.scale.x 598 else: 599 scale = getattr(self.scale, self.activeManipAxis) 600 else: 601 scale = 1.0 602 603 604 class RotationTool(TransformationTool): 605 606 def __init__(self, view, projection, primitiveScene): 607 TransformationTool.__init__(self, view, projection, primitiveScene) 608 self.action = None 609 self.axis = {'x': X_AXIS, 610 'y': Y_AXIS, 611 'z': Z_AXIS} 612 self.axisCulling = True 613 self.lastRotation = geo2.QuaternionIdentity() 614 615 def SetAxisCulling(self, state): 616 self.axisCulling = state 617 618 def GenGeometry(self): 619 xCircleAreas = [] 620 yCircleAreas = [] 621 zCircleAreas = [] 622 if not trinity.IsRightHanded(): 623 effectPath = 'res:/Graphics/Effect/Managed/Utility/LinesRotationToolLH.fx' 624 else: 625 effectPath = 'res:/Graphics/Effect/Managed/Utility/LinesRotationTool.fx' 626 unit_circle = dungeonEditorToolGeometry.GenCirclePoints(1.0, 60) 627 mat = geo2.MatrixRotationY(math.pi / 2) 628 x_circle = geo2.Vec3TransformCoordArray(unit_circle, mat) 629 xRotationHandleCircle = dungeonEditorToolGeometry.area('x', dungeonEditorToolGeometry.RED) 630 xRotationHandleCircle.AddToLineSet(x_circle, True) 631 xRotationHandleCircle._lineset.effect.effectFilePath = effectPath 632 mat = geo2.MatrixRotationX(math.pi / 2) 633 y_circle = geo2.Vec3TransformCoordArray(unit_circle, mat) 634 yRotationHandleCircle = dungeonEditorToolGeometry.area('y', dungeonEditorToolGeometry.GREEN) 635 yRotationHandleCircle.AddToLineSet(y_circle, True) 636 yRotationHandleCircle._lineset.effect.effectFilePath = effectPath 637 zRotationHandleCircle = dungeonEditorToolGeometry.area('z', dungeonEditorToolGeometry.BLUE) 638 zRotationHandleCircle.AddToLineSet(unit_circle, True) 639 zRotationHandleCircle._lineset.effect.effectFilePath = effectPath 640 w_circle = dungeonEditorToolGeometry.GenCirclePoints(1.2, 60) 641 wArea = dungeonEditorToolGeometry.area('w', dungeonEditorToolGeometry.CYAN) 642 wArea.AddToLineSet(w_circle, True) 643 wArea._lineset.viewOriented = True 644 wwArea = dungeonEditorToolGeometry.area('ww', dungeonEditorToolGeometry.LIGHT_GRAY) 645 wwArea.AddToLineSet(dungeonEditorToolGeometry.GenCirclePoints(1.0, 60)) 646 wwArea._lineset.viewOriented = True 647 picking_tris = dungeonEditorToolGeometry.GenCircleTriangles(1.0, 60) 648 if not trinity.IsRightHanded(): 649 picking_tris.reverse() 650 wwArea.AddToPickingSet(picking_tris) 651 rotationGeo = dungeonEditorToolGeometry.geometry(self.primitiveScene) 652 rotationGeo.AppendArea(xRotationHandleCircle) 653 rotationGeo.AppendArea(yRotationHandleCircle) 654 rotationGeo.AppendArea(zRotationHandleCircle) 655 rotationGeo.AppendArea(wArea) 656 rotationGeo.AppendArea(wwArea) 657 return rotationGeo 658 659 def ColorActiveAxis(self): 660 if self.activeManipAxis != 'ww': 661 TransformationTool.ColorActiveAxis(self) 662 663 def Cull(self, areas): 664 pos = geo2.Vector(self.frontPlaneTranslation[3][0], self.frontPlaneTranslation[3][1], self.frontPlaneTranslation[3][2]) 665 viewMat = trinity.GetViewTransform() 666 lookat = geo2.Vector(-viewMat[0][2], -viewMat[1][2], -viewMat[2][2]) 667 x_area = dungeonEditorToolGeometry.area('x', 4294771202L) 668 y_area = dungeonEditorToolGeometry.area('y', 4278385922L) 669 z_area = dungeonEditorToolGeometry.area('z', 4278321917L) 670 x_lines = [] 671 y_lines = [] 672 z_lines = [] 673 for each in iter(areas): 674 name = each.name 675 if name not in ('x', 'y', 'z'): 676 continue 677 b = pos - (each.bounds.updated_center - lookat * each.bounds.radius) 678 if geo2.Vec3Dot(geo2.Vec3Normalize(b), lookat) < 0.0 or not self.axisCulling: 679 if name == 'x': 680 x_area.SetColor(each.GetColor()) 681 x_area.lineset.transform = each.lineset.transform 682 x_lines.extend(each.lines) 683 elif name == 'y': 684 y_area.SetColor(each.GetColor()) 685 y_area.lineset.transform = each.lineset.transform 686 y_lines.extend(each.lines) 687 elif name == 'z': 688 z_area.SetColor(each.GetColor()) 689 z_area.lineset.transform = each.lineset.transform 690 z_lines.extend(each.lines) 691 self.geometry.visible_areas.append(each) 692 693 x_area.AddToLineSet(x_lines) 694 x_area.lineset.zEnable = False 695 y_area.AddToLineSet(y_lines) 696 y_area.lineset.zEnable = False 697 z_area.AddToLineSet(z_lines) 698 z_area.lineset.zEnable = False 699 return [x_area, 700 y_area, 701 z_area, 702 self.geometry.GetArea('w'), 703 self.geometry.GetArea('ww')] 704 705 def _Hemisphere(self, x, y): 706 dev = trinity.device 707 center = geo2.Vector(self.frontPlaneTranslation[3][0], self.frontPlaneTranslation[3][1], self.frontPlaneTranslation[3][2]) 708 view = trinity.GetViewTransform() 709 proj = trinity.GetProjectionTransform() 710 side = center - geo2.Vector(view[0][0], view[1][0], view[2][0]) 711 center = geo2.Vec3TransformCoord(center, view) 712 center = geo2.Vec3TransformCoord(center, proj) 713 center = geo2.Vector(*center) 714 side = geo2.Vec3TransformCoord(side, view) 715 side = geo2.Vec3TransformCoord(side, proj) 716 side = geo2.Vector(*side) 717 side.x += 1.0 718 side.y += 1.0 719 center.x += 1.0 720 center.y += 1.0 721 dim = abs(dev.width * (side.x - center.x)) * 0.5 722 screenx = int((dev.width - 1) * 0.5 * center.x) 723 screeny = dev.height - int((dev.height - 1) * 0.5 * center.y) 724 px = float(x - screenx) / float(dim) 725 py = float(screeny - y) / float(dim) 726 d = math.sqrt(px * px + py * py) 727 if d > 1.0: 728 a = 1.0 / d 729 vec = geo2.Vector(px * a, py * a, 0.0) 730 else: 731 vec = geo2.Vector(px, py, -(1.0 - d)) 732 return geo2.Vec3Normalize(vec) 733 734 def _TransformAxis(self, v): 735 viewMat = trinity.GetViewTransform() 736 viewVec = geo2.Vector(viewMat[0][2], viewMat[1][2], viewMat[2][2]) 737 pos = self.GetTranslation() 738 start = self.startPlanePos - pos 739 start = geo2.Vec3Normalize(start) 740 end = self.endPlanePos - pos 741 end = geo2.Vec3Normalize(end) 742 q = geo2.QuaternionIdentity() 743 dot = geo2.Vec3Dot(start, end) 744 if 1.0 - dot < 1e-05: 745 return q 746 dnormal = geo2.Vec3Cross(start, end) 747 if self.activeManipAxis == 'w': 748 worldInv = geo2.MatrixInverse(self.worldTranslation) 749 axis = geo2.Vec3TransformNormal(viewVec, worldInv) 750 axis = geo2.Vector(*axis) 751 rdot = geo2.Vec3Dot(axis, viewVec) 752 ddot = geo2.Vec3Dot(dnormal, axis) 753 if ddot < 0.0 and rdot > 0.0: 754 axis = -axis 755 elif ddot > 0.0 and rdot < 0.0: 756 axis = -axis 757 elif self.activeManipAxis == 'ww': 758 curP = self._Hemisphere(self.curX, self.curY) 759 preP = self._Hemisphere(self.preX, self.preY) 760 viewInverse = geo2.MatrixInverse(viewMat) 761 norm = geo2.Vec3Cross(preP, curP) 762 worldInv = geo2.MatrixInverse(self.worldTranslation) 763 axis = geo2.Vec3TransformNormal(norm, worldInv) 764 axis = geo2.Vec3TransformNormal(axis, viewInverse) 765 dot = geo2.Vec3Dot(curP, preP) 766 else: 767 axis = self.axis[self.activeManipAxis] 768 if geo2.Vec3Dot(dnormal, axis) < 0.0: 769 axis = -axis 770 if self.activeManipAxis == 'x' and self.worldTranslation[0][0] < 0.0 or self.activeManipAxis == 'y' and self.worldTranslation[1][1] < 0.0 or self.activeManipAxis == 'z' and self.worldTranslation[2][2] < 0.0: 771 axis = -axis 772 self.startPlanePos = self.endPlanePos 773 if dot < -1: 774 dot = -1 775 elif dot > 1: 776 dot = 1 777 q = geo2.QuaternionRotationAxis(axis, math.acos(dot)) 778 q = geo2.QuaternionNormalize(q) 779 return q 780 781 def _TransformContext(self, q): 782 scenarioSvc = sm.StartService('scenario') 783 originalToolRotation = self.GetRotation() 784 orgX, orgY, orgZ = scenarioSvc.GetDungeonOrigin() 785 toolPositionX, toolPositionY, toolPositionZ = sm.GetService('scenario').GetSelectionCenter() 786 toolOffset = geo2.Vector(toolPositionX - orgX, toolPositionY - orgY, toolPositionZ - orgZ) 787 qout = geo2.QuaternionMultiply(originalToolRotation, q) 788 qout = geo2.QuaternionNormalize(qout) 789 inverse = geo2.QuaternionInverse(originalToolRotation) 790 diff = geo2.QuaternionMultiply(qout, inverse) 791 diff = geo2.QuaternionNormalize(diff) 792 slimItems = scenarioSvc.GetSelObjects() 793 for slimItem in slimItems: 794 if slimItem.dunObjectID in scenarioSvc.GetLockedObjects(): 795 if uicore.uilib.Key(uiconst.VK_CONTROL): 796 scenarioSvc.UnlockObject(slimItem.itemID, slimItem.dunObjectID, force=True) 797 else: 798 continue 799 targetBall = sm.StartService('michelle').GetBall(slimItem.itemID) 800 targetModel = getattr(targetBall, 'model', None) 801 if targetModel and slimItem.categoryID != const.categoryAsteroid and slimItem.groupID != const.groupHarvestableCloud: 802 qout = geo2.QuaternionMultiply(targetModel.rotationCurve.value, diff) 803 qout = geo2.QuaternionNormalize(qout) 804 targetModel.rotationCurve.value = qout 805 slimItem.dunDirection = geo2.QuaternionTransformVector(qout, geo2.Vector(0.0, 0.0, 1.0)) 806 scenarioSvc.UpdateUnsavedObjectChanges(slimItem.itemID, CHANGE_ROTATION) 807 if len(slimItems) > 1 and not uicore.uilib.Key(uiconst.VK_SHIFT): 808 relativeObjectPosition = geo2.Vector(slimItem.dunX - toolOffset.x, slimItem.dunY - toolOffset.y, slimItem.dunZ - toolOffset.z) 809 rotatedDirectionVector = geo2.QuaternionTransformVector(diff, relativeObjectPosition) 810 if targetModel: 811 targetModel.translationCurve.x = rotatedDirectionVector[0] + toolPositionX 812 targetModel.translationCurve.y = rotatedDirectionVector[1] + toolPositionY 813 targetModel.translationCurve.z = rotatedDirectionVector[2] + toolPositionZ 814 elif slimItem.groupID in scenarioSvc.groupsWithNoModel: 815 try: 816 targetTransform = scenarioSvc.fakeTransforms[slimItem.itemID] 817 targetTransform.translationCurve.x = rotatedDirectionVector[0] + toolPositionX 818 targetTransform.translationCurve.y = rotatedDirectionVector[1] + toolPositionY 819 targetTransform.translationCurve.z = rotatedDirectionVector[2] + toolPositionZ 820 except KeyError: 821 scenarioSvc.LogError('Unable to rotate any ball for dungeon object:', slimItem.dunObjectID) 822 823 slimItem.dunX = rotatedDirectionVector[0] + toolOffset.x 824 slimItem.dunY = rotatedDirectionVector[1] + toolOffset.y 825 slimItem.dunZ = rotatedDirectionVector[2] + toolOffset.z 826 scenarioSvc.UpdateUnsavedObjectChanges(slimItem.itemID, CHANGE_TRANSLATION) 827 828 qout = geo2.QuaternionMultiply(q, originalToolRotation) 829 qout = geo2.QuaternionNormalize(qout) 830 self.Rotate(qout) 831 832 def AddRotationCurveToObject(self, itemID): 833 ball = sm.GetService('michelle').GetBall(itemID) 834 if ball.model is None: 835 return 836 if ball.model.rotationCurve is not None: 837 return 838 ball.model.rotationCurve = ball.model.translationCurve 839 840 def GetDesiredPlaneNormal(self, ray): 841 viewMat = trinity.GetViewTransform() 842 view = geo2.Vector(viewMat[0][2], viewMat[1][2], viewMat[2][2]) 843 local_axis = {'x': self.GetRightVec(), 844 'y': self.GetUpVec(), 845 'z': self.GetFrontVec()} 846 if self.activeManipAxis in local_axis: 847 axis = local_axis[self.activeManipAxis] 848 if geo2.Vec3Dot(view, axis) > 0.0: 849 norm = -axis 850 else: 851 norm = axis 852 else: 853 norm = view 854 norm = geo2.Vec3Normalize(norm) 855 return norm 856 857 def _DiffProjectedPoint(self, ray, start): 858 self.endPlanePos = RayToPlaneIntersection(start, ray, self.GetTranslation(), self.targetPlaneNormal) 859 860 def _InternalUpdate(self): 861 mat = CameraFacingMatrix(self.worldTranslation) 862 warea = self.geometry.GetArea('w') 863 wwarea = self.geometry.GetArea('ww') 864 warea.localTransform = mat 865 wwarea.localTransform = mat