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

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