paperDollSculpting.py (49807B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\paperDoll\paperDollSculpting.py 2 from __future__ import print_function 3 import trinity 4 import blue 5 import uthread 6 import struct 7 import math 8 import geo2 9 from carbon.client.script.animation.animationController import AnimationController 10 import telemetry 11 import legacy_r_drive 12 from eve.common.script.paperDoll.paperDollCommonFunctions import Yield 13 from .commonClientFunctions import MoveAreas 14 from eve.common.script.paperDoll.paperDollDefinitions import BLENDSHAPE_CATEGORIES, BODY_BLENDSHAPE_ZONES, DOLL_EXTRA_PARTS, HEAD_BLENDSHAPE_ZONES, HEAD_CATEGORIES 15 from eve.common.script.paperDoll.yamlPreloader import LoadYamlFileNicely 16 17 class PaperDollSculpting: 18 19 def GetProjectionAndViewMatrix(self): 20 return (self.camera.projectionMatrix, self.camera.viewMatrix) 21 22 def OnInvalidate(self, dev): 23 self.Stop() 24 25 def OnCreate(self, dev): 26 self.PreloadZoneMaps(self.doll) 27 self.Reset(self.doll, self.avatar, mode=self.mode, camera=self.camera, callback=self.callback, pickCallback=self.pickCallback, inactiveZones=self.inactiveZones) 28 self.ready = True 29 30 @telemetry.ZONE_METHOD 31 def GetMaskAtPixel(self, x, y): 32 self.zoneSize = (self.zoneMap.width, self.zoneMap.height) 33 self.bodyZoneSize = (self.bodyZoneMap.width, self.bodyZoneMap.height) 34 if self.zoneSize[0] == 0 or self.bodyZoneSize[0] == 0: 35 return (0, 36 0, 37 [0, 0], 38 0, 39 True) 40 mask = 0 41 dev = trinity.device 42 cameraProj, cameraView = self.GetProjectionAndViewMatrixFunc() 43 if self.pickScene: 44 self.pickAvatar.rotation = self.avatar.rotation 45 backbuffer = self.backbuffer or trinity.device.GetRenderContext().GetDefaultBackBuffer() 46 viewport = trinity.TriViewport(0, 0, backbuffer.width, backbuffer.height) 47 pick = None 48 if hasattr(self.pickScene, 'PickObject'): 49 pick = self.pickScene.PickPointAndObject(x, y, cameraProj, cameraView, viewport) 50 if not pick: 51 return (0, 52 0, 53 [0, 0], 54 0, 55 True) 56 if not hasattr(self.pickScene, 'PickObjectUV') or pick[0].__typename__ != 'Tr2IntSkinnedObject': 57 return (0, 58 pick[0], 59 [0, 0], 60 pick[1], 61 True) 62 pickedPixelUV = self.pickScene.PickObjectUV(x, y, cameraProj, cameraView, viewport) 63 isHead = True 64 self.pickedSide = 'right' 65 midpoint = 0.5 66 if pickedPixelUV[0] > 0.5: 67 self.pickedMesh = 'head' 68 pickedPixelUV = [(pickedPixelUV[0] - 0.5) * 2.0, pickedPixelUV[1] * 2.0] 69 if pickedPixelUV[0] < 0.0 or pickedPixelUV[0] > 1.0 or pickedPixelUV[1] < 0.0 or pickedPixelUV[1] > 1.0: 70 return (0, 71 pick[0], 72 pickedPixelUV, 73 pick[1], 74 isHead) 75 pixel = [int(pickedPixelUV[0] * self.zoneSize[0]), int(pickedPixelUV[1] * self.zoneSize[1])] 76 buffer = self.zoneMap.GetRawData() 77 color = struct.unpack_from('=BBBB', buffer[0], pixel[0] * 4 + pixel[1] * buffer[3]) 78 mask = color[0] 79 else: 80 isHead = False 81 self.pickedMesh = 'body' 82 pickedPixelUV = [pickedPixelUV[0] * 2.0, pickedPixelUV[1]] 83 pixel = [int(pickedPixelUV[0] * self.bodyZoneSize[0]), int(pickedPixelUV[1] * self.bodyZoneSize[1])] 84 buffer = self.bodyZoneMap.GetRawData() 85 color = struct.unpack_from('=BBBB', buffer[0], pixel[0] * 4 + pixel[1] * buffer[3]) 86 mask = color[0] 87 zone = self.ConvertMaskToZone(mask) 88 if zone in (0, 2, 5) or zone == 1 and pickedPixelUV[0] < 0.37: 89 midpoint = 0.2 90 if pickedPixelUV[0] > midpoint: 91 self.pickedSide = 'left' 92 return (mask, 93 pick[0], 94 pickedPixelUV, 95 pick[1], 96 isHead) 97 98 def ConvertMaskToZone(self, mask): 99 return int(mask / 10.0 - 1) 100 101 def RightDown(self, x, y): 102 self.rightClick = True 103 self.PickWrapper(x, y) 104 105 def RightUp(self, x, y): 106 self.EndMotion(x, y) 107 108 @telemetry.ZONE_METHOD 109 def PickWrapper(self, x, y): 110 xy = (x, y) 111 dev = trinity.device 112 self.markerCorrection = [0.0, 0.0] 113 mask, pick, uv, xyz, isHead = self.GetMaskAtPixel(x, y) 114 if mask > 0: 115 if self.mode == 'sculpt': 116 self.avatar.animationUpdater.TogglePauseAnimations(True) 117 self.startXY = [x, y] 118 camera = self.camera 119 cPos = camera.GetPosition() 120 cInt = camera.GetPointOfInterest() 121 avatarRotation = self.avatar.rotation 122 vector = [cPos[0] - cInt[0], cPos[1] - cInt[1], cPos[2] - cInt[2]] 123 invRotation = geo2.QuaternionInverse(avatarRotation) 124 vector = geo2.QuaternionTransformVector(invRotation, vector) 125 if abs(vector[0]) > abs(vector[2]): 126 if vector[0] > 0.0: 127 self.direction = 'right' 128 else: 129 self.direction = 'left' 130 else: 131 self.direction = 'front' 132 self.zone = self.ConvertMaskToZone(mask) 133 if self.zone not in self.inactiveZones: 134 if self.pickCallback: 135 self.pickCallback(self.zone) 136 if self.useHighlighting: 137 if self.highlightGhost.IsActive(): 138 self.highlightGhost.Stop() 139 if self.bodyHighlightGhost.IsActive(): 140 self.bodyHighlightGhost.Stop() 141 else: 142 self.zone = -1 143 self.direction = None 144 self.startXY = None 145 self.rightClick = False 146 return self.zone 147 148 @telemetry.ZONE_METHOD 149 def MotionWrapper(self, x, y): 150 if self.handlingMotion: 151 return 152 if self.stopInteraction: 153 return 154 currentFrameCounter = trinity.GetCurrentFrameCounter() 155 if self.lastFrameSculpted == currentFrameCounter: 156 return 157 self.lastFrameSculpted = currentFrameCounter 158 self.handlingMotion = True 159 if self.startXY: 160 delta = [self.startXY[0] - x, self.startXY[1] - y] 161 if sum(delta) == 0: 162 self.handlingMotion = False 163 return 164 if self.mode == 'sculpt': 165 result = self.UpdateField(delta) 166 self.UpdateBlendShapes(result) 167 elif self.mode == 'animation': 168 result = self.UpdateFieldAnimation(delta) 169 if result: 170 self.UpdateAnimation(result) 171 else: 172 mask, pick, uv, xyz, isHead = self.GetMaskAtPixel(x, y) 173 zone = self.ConvertMaskToZone(mask) 174 isFront = True 175 camera = self.camera 176 cPos = camera.GetPosition() 177 cInt = camera.GetPointOfInterest() 178 vector = [cPos[0] - cInt[0], cPos[1] - cInt[1], cPos[2] - cInt[2]] 179 if abs(vector[0]) > abs(vector[2]): 180 isFront = False 181 if zone not in self.inactiveZones: 182 if self.callback: 183 self.callback(zone, isFront, isHead) 184 if self.useHighlighting: 185 if self.highlightGhost.IsActive() and not isHead: 186 self.highlightGhost.Stop() 187 if self.bodyHighlightGhost.IsActive() and isHead: 188 self.bodyHighlightGhost.Stop() 189 if mask == 0: 190 if self.highlightGhost.IsActive() and not self.previewingHighlight: 191 self.highlightGhost.Stop() 192 if self.bodyHighlightGhost.IsActive() and not self.previewingHighlight: 193 self.bodyHighlightGhost.Stop() 194 self.handlingMotion = False 195 return 196 if not self.highlightGhost.IsActive() and isHead and not self.mode == 'bodyselect': 197 uthread.new(self.highlightGhost.Start, pick) 198 if not self.bodyHighlightGhost.IsActive() and not isHead and (self.mode == 'sculpt' or self.mode == 'bodyselect'): 199 uthread.new(self.bodyHighlightGhost.Start, pick) 200 if isHead: 201 if self.highlightGhost.IsActive(): 202 if not self.overrideMousePos: 203 self.highlightGhost.SetMousePos(xyz, 0.05) 204 else: 205 self.highlightGhost.SetMousePos(self.overrideMousePosXYZ, 0.05) 206 if zone not in self.inactiveZones: 207 self.KillHighlightPreview() 208 self.highlightGhost.SetActiveZoneColor((1.0, 209 1.0, 210 1.0, 211 mask / 255.0)) 212 elif self.bodyHighlightGhost.IsActive(): 213 if not self.overrideMousePos: 214 self.highlightGhost.SetMousePos(xyz, 0.15) 215 else: 216 self.highlightGhost.SetMousePos(self.overrideMousePosXYZ, 0.15) 217 if zone not in self.inactiveZones: 218 self.KillHighlightPreview() 219 self.bodyHighlightGhost.SetActiveZoneColor((1.0, 220 1.0, 221 1.0, 222 mask / 255.0)) 223 self.handlingMotion = False 224 225 @telemetry.ZONE_METHOD 226 def OverrideMousePosWithJoint(self, joint_name): 227 bpos = (0.0, 0.0, 0.0) 228 if self.avatar is not None and self.avatar.animationUpdater is not None: 229 joint = self.avatar.GetBoneIndex(joint_name) 230 if joint == 4294967295L: 231 bpos = (0.0, 0.0, 0.0) 232 else: 233 bpos = self.avatar.GetBonePosition(joint) 234 self.OverrideMousePos(bpos[0], bpos[1], bpos[2]) 235 236 @telemetry.ZONE_METHOD 237 def OverrideMousePos(self, x, y, z): 238 self.overrideMousePos = True 239 self.overrideMousePosXYZ = (x, y, z) 240 241 @telemetry.ZONE_METHOD 242 def ReleaseOverrideMousePos(self): 243 self.overrideMousePos = False 244 self.overrideMousePosXYZ = (0.0, 0.0, 0.0) 245 246 @telemetry.ZONE_METHOD 247 def HighlightPreview(self, isMale = True): 248 import time 249 self.previewingHighlight = True 250 start = time.time() 251 self.highlightGhost.Start(self.avatar) 252 self.bodyHighlightGhost.Start(self.avatar) 253 if self.mode == 'sculpt': 254 sequence = [10.1, 255 11.1, 256 17, 257 13, 258 1, 259 15, 260 2, 261 3, 262 4, 263 12, 264 18, 265 5, 266 14.1, 267 7, 268 9.1, 269 8, 270 6] 271 for i, each in enumerate(sequence): 272 self.highlightGhost.SetActiveZoneColor((2.0, 273 2.0, 274 2.0, 275 each * 10 / 255.0)) 276 while time.time() < start + (i + 1) / 3.0: 277 Yield(frameNice=False) 278 279 else: 280 numZones = 0 281 if self.mode == 'hair': 282 numZones = 2 283 if isMale: 284 numZones = 3 285 elif self.mode == 'bodyselect': 286 numZones = 5 287 elif self.mode == 'makeup': 288 numZones = 3 289 for i in range(numZones + 1): 290 if self.mode == 'bodyselect': 291 self.bodyHighlightGhost.SetActiveZoneColor((1.0, 292 1.0, 293 1.0, 294 i * 10 / 255.0)) 295 else: 296 self.highlightGhost.SetActiveZoneColor((2.0, 297 2.0, 298 2.0, 299 i * 10 / 255.0)) 300 while time.time() < start + i / 3.0: 301 Yield(frameNice=False) 302 303 self.highlightGhost.Stop() 304 self.bodyHighlightGhost.Stop() 305 self.previewingHighlight = False 306 307 def KillHighlightPreview(self): 308 self.previewingHighlight = False 309 if self.highlightThread is not None: 310 self.highlightThread.kill() 311 312 def RunHighlightPreview(self, isMale = True): 313 self.KillHighlightPreview() 314 if self.useHighlighting: 315 self.highlightThread = uthread.new(self.HighlightPreview, isMale) 316 317 @telemetry.ZONE_METHOD 318 def EndMotion(self, x, y): 319 self.stopInteraction = False 320 if self.mode == 'sculpt': 321 self.avatar.animationUpdater.TogglePauseAnimations(False) 322 for f in self.fieldResetData: 323 pos = self.fieldResetData[f] 324 field = None 325 if self.mode == 'sculpt': 326 if f in self.fieldData['Fields']: 327 field = self.fieldData['Fields'][f] 328 elif self.mode == 'animation': 329 if f in self.fieldDataAnimation['Fields']: 330 field = self.fieldDataAnimation['Fields'][f] 331 if field: 332 field['MarkerPosition'] = pos 333 334 self.fieldResetData = {} 335 self.startXY = None 336 337 @telemetry.ZONE_METHOD 338 def UpdateAnimation(self, values): 339 doll = self.doll 340 av = self.avatar 341 if self.animationController is None or self.animationController.animationNetwork.avatar != av: 342 self.animationController = AnimationController(av) 343 for v in values: 344 if v.endswith('_X') or v.endswith('_Y') or v.endswith('_Z'): 345 baseName = v[:-2] 346 self.animationController.SetControlParameter(baseName, (values[baseName + '_X'], values[baseName + '_Y'], values[baseName + '_Z'])) 347 break 348 rightVersion = v.replace('Left', 'Right') 349 if rightVersion != v: 350 if self.poseSymmetric: 351 self.animationController.SetControlParameter(v, values[v]) 352 self.animationController.SetControlParameter(rightVersion, values[v]) 353 elif self.pickedSide == 'left': 354 self.animationController.SetControlParameter(v, values[v]) 355 else: 356 self.animationController.SetControlParameter(rightVersion, values[v]) 357 else: 358 self.animationController.SetControlParameter(v, values[v]) 359 360 @telemetry.ZONE_METHOD 361 def UpdateBlendShapes(self, values, doUpdate = True): 362 doll = self.doll 363 mods = [] 364 for blendshapeCategory in BLENDSHAPE_CATEGORIES: 365 modifiersByCategory = doll.buildDataManager.GetModifiersByCategory(blendshapeCategory) 366 mods.extend(modifiersByCategory) 367 368 cleanValues = {} 369 valueThreshold = 0.0001 370 if doll: 371 av = self.avatar 372 for v in iter(values): 373 mod = (v + 'shape').lower() 374 cleanValues[mod] = values[v] 375 limit = doll.buildDataManager.modifierLimits.get(mod) 376 if limit: 377 if cleanValues[mod] > limit[1]: 378 cleanValues[mod] = limit[1] 379 elif cleanValues[mod] < limit[0]: 380 cleanValues[mod] = limit[0] 381 foundMod = False 382 for m in iter(mods): 383 if mod == m.name: 384 m.weight = values[v] 385 foundMod = True 386 if values[v] < valueThreshold: 387 resPath = '{0}/{1}'.format(m.categorie, m.name) 388 doll.RemoveResource(resPath, self.factory) 389 break 390 391 if not foundMod: 392 for zone in BODY_BLENDSHAPE_ZONES: 393 if zone.lower() in mod and cleanValues[mod] > valueThreshold: 394 resPath = '{0}/{1}'.format(DOLL_EXTRA_PARTS.BODYSHAPES, mod) 395 doll.AddResource(resPath, cleanValues[mod], self.factory) 396 foundMod = True 397 break 398 399 if not foundMod: 400 for zone in HEAD_BLENDSHAPE_ZONES: 401 if zone.lower() in mod and cleanValues[mod] > valueThreshold: 402 resPath = '{0}/{1}'.format(HEAD_CATEGORIES.FACEMODIFIERS, mod) 403 doll.AddResource(resPath, cleanValues[mod], self.factory) 404 break 405 406 if doUpdate: 407 doll.Update(self.factory, avatar=av) 408 for m in mods: 409 if m.weight > 0 and m not in cleanValues: 410 limit = doll.buildDataManager.modifierLimits.get(m.name) 411 cleanValues[m.name] = m.weight 412 if limit: 413 if cleanValues[m.name] > limit[1]: 414 cleanValues[m.name] = limit[1] 415 elif cleanValues[m.name] < limit[0]: 416 cleanValues[m.name] = limit[0] 417 418 pickAvatar = self.pickAvatar 419 if pickAvatar: 420 self.UpdatePickBlendshapes(pickAvatar, cleanValues) 421 422 @telemetry.ZONE_METHOD 423 def UpdatePickBlendshapes(self, avatar, values): 424 meshGeometryResPaths = {} 425 modifierList = self.doll.buildDataManager.GetSortedModifiers() 426 for m in self.pickExtraMods: 427 modifierList.append(m) 428 429 for modifier in iter(modifierList): 430 meshGeometryResPaths.update(modifier.meshGeometryResPaths) 431 432 meshGeometryResPaths.update(self.pickAvatarPaths) 433 meshes = avatar.Find('Trinity.Tr2Mesh') 434 uthread.new(self.factory.ApplyMorphTargetsToMeshes, meshes, values, self.pickAvatarCache, meshGeometryResPaths) 435 436 @telemetry.ZONE_METHOD 437 def LoadMapping(self): 438 self.mapping = {} 439 self.mapping[0] = 'Nose' 440 self.mapping[1] = 'NoseTip' 441 self.mapping[2] = 'Nostrils' 442 self.mapping[3] = 'CheeksUpper' 443 self.mapping[4] = 'Jaw' 444 self.mapping[5] = 'Chin' 445 self.mapping[6] = 'MouthCorner' 446 self.mapping[7] = 'LowerLip' 447 self.mapping[8] = 'UpperLip' 448 self.mapping[9] = 'InnerBrow' 449 self.mapping[10] = 'OuterBrow' 450 self.mapping[11] = 'Ears' 451 self.mapping[12] = 'Eyes' 452 self.mapping[13] = 'CheeksMiddle' 453 self.mapping[14] = 'Nosebone' 454 self.mapping[15] = 'EyesInner' 455 self.mapping[16] = 'EyesOuter' 456 self.mapping[17] = 'JawCheek' 457 self.bodyMapping = {} 458 self.bodyMapping[0] = 'Legs' 459 self.bodyMapping[1] = 'Abs' 460 self.bodyMapping[2] = 'Pelvis' 461 self.bodyMapping[3] = 'Shoulders' 462 self.bodyMapping[4] = 'Chest' 463 self.bodyMapping[5] = 'Feet' 464 self.bodyMapping[6] = 'Neck' 465 466 def OnSculptFace(self, evt): 467 self.mode = 'sculpt' 468 469 def OnPoseFace(self, evt): 470 self.mode = 'animation' 471 self.poseSymmetric = True 472 473 def OnPoseAsymFace(self, evt): 474 self.mode = 'animation' 475 self.poseSymmetric = False 476 477 @telemetry.ZONE_METHOD 478 def __init__(self, avatar = None, doll = None, scene = None, camera = None, factory = None, callback = None, viewProjCallback = None, mode = 'sculpt', pickCallback = None, inactiveZones = [], backbuffer = None): 479 self.avatar = avatar 480 self.doll = doll 481 self.scene = scene 482 self.head = '' 483 self.gender = '' 484 self.pickScene = None 485 self.pickAvatar = None 486 self.pickExtraMods = [] 487 self.pickAvatarCache = {} 488 self.pickAvatarPaths = {} 489 self.updateRenderjob = None 490 self.backbuffer = backbuffer 491 self.ready = False 492 if camera: 493 self.camera = camera 494 self.GetProjectionAndViewMatrixFunc = self.GetProjectionAndViewMatrix 495 if viewProjCallback: 496 self.GetProjectionAndViewMatrixFunc = viewProjCallback 497 self.factory = factory 498 self.callback = callback 499 self.pickCallback = pickCallback 500 self.inactiveZones = inactiveZones 501 self.keysDown = set() 502 self.handlingMotion = False 503 self.lastFrameSculpted = 0 504 self.rightClick = False 505 self.mode = None 506 self.startXY = None 507 self.direction = None 508 self.pickedSide = None 509 self.pickedMesh = 'head' 510 self.zone = -1 511 self.mapping = {} 512 self.fieldData = None 513 self.fieldDataAnimation = None 514 self.stopInteraction = False 515 self.finalAttrs = {} 516 self.fieldResetData = {} 517 self.fieldLKG = {} 518 self.fieldLKGPos = {} 519 self.markerCorrection = [0.0, 0.0] 520 self.dirDict = {} 521 self.LoadMapping() 522 self.LoadFieldData() 523 self.FillInFieldData() 524 self.lightSettings = [] 525 self.poseSymmetric = False 526 self.useHighlighting = True 527 self.previewingHighlight = False 528 self.highlightGhost = None 529 self.highlightThread = None 530 self.overrideMousePos = False 531 self.overrideMousePosXYZ = (0.0, 0.0, 0.0) 532 self.animationController = None 533 self.PreloadZoneMaps(doll) 534 self.Reset(doll, avatar, mode=mode, camera=camera, callback=callback, pickCallback=pickCallback, inactiveZones=inactiveZones) 535 self.ready = True 536 trinity.device.RegisterResource(self) 537 538 @telemetry.ZONE_METHOD 539 def PreloadZoneMaps(self, doll): 540 textureRoot = 'R:/' 541 textureSuffix = '.tga' 542 if not legacy_r_drive.loadFromContent: 543 textureRoot = 'res:/' 544 textureSuffix = '.png' 545 self.zoneMaps = {} 546 self.highlightMaps = {} 547 for each in ('hair', 'makeup', 'bodyselect', 'animation', 'default'): 548 zonePath = textureRoot + 'Graphics/Character/Global/FaceSetup/SculptZones' + textureSuffix 549 headGridPath = textureRoot + 'Graphics/Character/Global/FaceSetup/male_head_fx' + textureSuffix 550 bodyGridPath = textureRoot + 'Graphics/Character/Global/FaceSetup/male_body_fx' + textureSuffix 551 if doll.gender == 'female': 552 headGridPath = headGridPath.replace('male_', 'female_') 553 bodyGridPath = bodyGridPath.replace('male_', 'female_') 554 if headGridPath not in self.highlightMaps: 555 self.highlightMaps[headGridPath] = blue.resMan.GetResource(headGridPath) 556 if bodyGridPath not in self.highlightMaps: 557 self.highlightMaps[bodyGridPath] = blue.resMan.GetResource(bodyGridPath) 558 bodyZonePath = textureRoot + 'Graphics/Character/Global/FaceSetup/BodySculptZones' + textureSuffix 559 headTiling = 1 560 bodyTiling = 1 561 if each == 'hair': 562 zonePath = textureRoot + 'Graphics/Character/Global/FaceSetup/HairZones' + textureSuffix 563 bodyZonePath = textureRoot + 'Graphics/Character/Global/FaceSetup/EmptyZone' + textureSuffix 564 headGridPath = textureRoot + 'Graphics/Character/Global/FaceSetup/SelectGrid' + textureSuffix 565 bodyGridPath = textureRoot + 'Graphics/Character/Global/FaceSetup/SelectGrid' + textureSuffix 566 headTiling = 40 567 bodyTiling = 40 568 elif each == 'makeup': 569 zonePath = textureRoot + 'Graphics/Character/Global/FaceSetup/MakeupZones' + textureSuffix 570 bodyZonePath = textureRoot + 'Graphics/Character/Global/FaceSetup/EmptyZone' + textureSuffix 571 headGridPath = textureRoot + 'Graphics/Character/Global/FaceSetup/SelectGrid' + textureSuffix 572 bodyGridPath = textureRoot + 'Graphics/Character/Global/FaceSetup/SelectGrid' + textureSuffix 573 headTiling = 40 574 bodyTiling = 40 575 elif each == 'bodyselect': 576 zonePath = textureRoot + 'Graphics/Character/Global/FaceSetup/EmptyZone' + textureSuffix 577 bodyZonePath = textureRoot + 'Graphics/Character/Global/FaceSetup/BodySelectZones' + textureSuffix 578 headGridPath = textureRoot + 'Graphics/Character/Global/FaceSetup/SelectGrid' + textureSuffix 579 bodyGridPath = textureRoot + 'Graphics/Character/Global/FaceSetup/SelectGrid' + textureSuffix 580 headTiling = 40 581 bodyTiling = 40 582 elif each == 'animation': 583 zonePath = textureRoot + 'Graphics/Character/Global/FaceSetup/AnimZones' + textureSuffix 584 headGridPath = textureRoot + 'Graphics/Character/Global/FaceSetup/male_head_Profile_fx' + textureSuffix 585 if doll.gender == 'female': 586 headGridPath = headGridPath.replace('male_', 'female_') 587 headTiling = 1 588 zoneMap = trinity.Tr2HostBitmap() 589 zoneMap.CreateFromFile(zonePath) 590 bodyZoneMap = trinity.Tr2HostBitmap() 591 bodyZoneMap.CreateFromFile(bodyZonePath) 592 zoneSize = (0, 0) 593 bodyZoneSize = (0, 0) 594 self.zoneMaps[each] = (zonePath, 595 headGridPath, 596 bodyGridPath, 597 headTiling, 598 bodyTiling, 599 bodyZonePath, 600 zoneMap, 601 zoneSize, 602 bodyZoneMap, 603 bodyZoneSize) 604 605 def IsReady(self): 606 return self.ready 607 608 def IsDollDifferent(self, doll, avatar): 609 retVal = False 610 if avatar != self.avatar: 611 self.avatar = avatar 612 retVal = True 613 head = doll.buildDataManager.GetModifiersByCategory('head') 614 if not head == self.head: 615 self.head = head 616 retVal = True 617 if not self.gender == doll.gender: 618 self.gender = doll.gender 619 retVal = True 620 return retVal 621 622 @telemetry.ZONE_METHOD 623 def Reset(self, doll, avatar, camera = None, mode = 'sculpt', callback = None, pickCallback = None, inactiveZones = [], skipPickSceneReset = False): 624 dollUpdated = self.IsDollDifferent(doll, avatar) 625 self.doll = doll 626 if self.pickAvatar: 627 self.pickAvatar.animationUpdater = avatar.animationUpdater 628 if self.mode == mode and not dollUpdated: 629 return 630 if camera is not None: 631 self.camera = camera 632 if (dollUpdated or not self.pickScene or mode != self.mode) and not skipPickSceneReset: 633 self.SetupPickScene() 634 self.avatar = avatar 635 self.mode = mode 636 self.inactiveZones = inactiveZones 637 if pickCallback: 638 self.pickCallback = pickCallback 639 if callback: 640 self.callback = callback 641 if mode in self.zoneMaps: 642 zonePath, headGridPath, bodyGridPath, headTiling, bodyTiling, bodyZonePath, self.zoneMap, self.zoneSize, self.bodyZoneMap, self.bodyZoneSize = self.zoneMaps[mode] 643 else: 644 zonePath, headGridPath, bodyGridPath, headTiling, bodyTiling, bodyZonePath, self.zoneMap, self.zoneSize, self.bodyZoneMap, self.bodyZoneSize = self.zoneMaps['default'] 645 self.zoneSize = (self.zoneMap.width, self.zoneMap.height) 646 self.bodyZoneSize = (self.bodyZoneMap.width, self.bodyZoneMap.height) 647 if self.useHighlighting: 648 from eve.client.script.paperDoll.PaperdollSculptingGhost import PaperdollSculptingGhost 649 self.highlightGhost = PaperdollSculptingGhost(zonePath=zonePath, texturePath=headGridPath, noisePath='res:/Texture/Global/noise.png', meshFilter=['head'], tiling=headTiling) 650 self.bodyHighlightGhost = PaperdollSculptingGhost(zonePath=bodyZonePath, texturePath=bodyGridPath, noisePath='res:/Texture/Global/noise.png', meshFilter=['topinner', 651 'bottominner', 652 'hands', 653 'feet', 654 'dependantsnude'], ignoreZ=True, tiling=bodyTiling) 655 656 @telemetry.ZONE_METHOD 657 def Stop(self): 658 self.mode = None 659 if self.updateRenderjob: 660 self.updateRenderjob.UnscheduleRecurring() 661 self.updateRenderjob = None 662 self.pickScene = None 663 self.pickAvatar = None 664 self.pickExtraMods = [] 665 self.pickAvatarCache = {} 666 667 @telemetry.ZONE_METHOD 668 def SetupPickScene(self, doUpdate = True): 669 self.pickScene = trinity.Tr2InteriorScene() 670 if hasattr(self.pickScene, 'updateShadowCubeMap'): 671 self.pickScene.updateShadowCubeMap = False 672 self.pickAvatarCache = {} 673 self.pickAvatar = self.avatar.CopyTo() 674 foundUpperNude = False 675 foundLowerNude = False 676 foundHead = False 677 torsoClickable = False 678 for meshIx in range(len(self.avatar.visualModel.meshes)): 679 mesh = self.avatar.visualModel.meshes[meshIx] 680 self.pickAvatar.visualModel.meshes[meshIx].SetGeometryRes(mesh.geometry) 681 if mesh.name.startswith('topinner'): 682 foundUpperNude = True 683 if len(mesh.opaqueAreas): 684 torsoClickable |= True 685 if mesh.name.startswith('bottominner'): 686 foundLowerNude = True 687 if mesh.name.startswith('head'): 688 foundHead = True 689 690 deleteList = [] 691 for mesh in self.pickAvatar.visualModel.meshes: 692 if mesh.name.startswith('feet') or mesh.name.startswith('hands'): 693 deleteList.append(mesh) 694 695 for d in deleteList: 696 self.pickAvatar.visualModel.meshes.remove(d) 697 698 self.pickExtraMods = [] 699 if not foundUpperNude or not torsoClickable: 700 deleteList = [] 701 for mesh in self.pickAvatar.visualModel.meshes: 702 if mesh.name.startswith('topinner'): 703 deleteList.append(mesh) 704 705 for d in deleteList: 706 self.pickAvatar.visualModel.meshes.remove(d) 707 708 torsoMod = self.factory.CollectBuildData(self.doll.gender, 'topinner/torso_nude') 709 self.pickExtraMods.append(torsoMod) 710 item = blue.resMan.LoadObject(torsoMod.redfile) 711 if item: 712 index = 1 713 for m in item.meshes: 714 m.name = 'topinner' + str(index) 715 self.pickAvatar.visualModel.meshes.append(m) 716 torsoMod.meshGeometryResPaths[m.name] = m.geometryResPath 717 self.pickAvatarPaths[m.name] = m.geometryResPath 718 index += 1 719 720 index = 1 721 for armPart in ['dependants/sleeveslower/standard', 'dependants/sleevesupper/standard']: 722 armMod = self.factory.CollectBuildData(self.doll.gender, armPart) 723 self.pickExtraMods.append(armMod) 724 item = blue.resMan.LoadObject(armMod.redfile) 725 if item: 726 for m in item.meshes: 727 m.name = 'dependantsnude' + str(index) 728 self.pickAvatar.visualModel.meshes.append(m) 729 armMod.meshGeometryResPaths[m.name] = m.geometryResPath 730 self.pickAvatarPaths[m.name] = m.geometryResPath 731 index += 1 732 733 if not foundLowerNude: 734 legMod = self.factory.CollectBuildData(self.doll.gender, 'bottominner/legs_nude') 735 self.pickExtraMods.append(legMod) 736 item = blue.resMan.LoadObject(legMod.redfile) 737 if item: 738 index = 1 739 for m in item.meshes: 740 m.name = 'bottominner' + str(index) 741 self.pickAvatar.visualModel.meshes.append(m) 742 legMod.meshGeometryResPaths[m.name] = m.geometryResPath 743 self.pickAvatarPaths[m.name] = m.geometryResPath 744 index += 1 745 746 if not foundHead: 747 headMod = self.factory.CollectBuildData(self.doll.gender, 'head/head_generic') 748 self.pickExtraMods.append(headMod) 749 item = blue.resMan.LoadObject(headMod.redfile) 750 if item: 751 index = 1 752 for m in item.meshes: 753 m.name = 'head' + str(index) 754 self.pickAvatar.visualModel.meshes.append(m) 755 headMod.meshGeometryResPaths[m.name] = m.geometryResPath 756 self.pickAvatarPaths[m.name] = m.geometryResPath 757 index += 1 758 759 handMod = self.factory.CollectBuildData(self.doll.gender, 'hands/hands_nude') 760 self.pickExtraMods.append(handMod) 761 item = blue.resMan.LoadObject(handMod.redfile) 762 if item: 763 index = 1 764 for m in item.meshes: 765 m.name = 'hands' + str(index) 766 self.pickAvatar.visualModel.meshes.append(m) 767 handMod.meshGeometryResPaths[m.name] = m.geometryResPath 768 self.pickAvatarPaths[m.name] = m.geometryResPath 769 index += 1 770 771 feetMod = self.factory.CollectBuildData(self.doll.gender, 'feet/feet_nude') 772 self.pickExtraMods.append(feetMod) 773 item = blue.resMan.LoadObject(feetMod.redfile) 774 if item: 775 index = 1 776 for m in item.meshes: 777 m.name = 'feet' + str(index) 778 self.pickAvatar.visualModel.meshes.append(m) 779 feetMod.meshGeometryResPaths[m.name] = m.geometryResPath 780 self.pickAvatarPaths[m.name] = m.geometryResPath 781 index += 1 782 783 for mesh in self.pickAvatar.visualModel.meshes: 784 MoveAreas(mesh.decalAreas, mesh.opaqueAreas) 785 786 self.pickAvatar.animationUpdater = self.avatar.animationUpdater 787 self.pickAvatar.worldTransformUpdater = self.avatar.worldTransformUpdater 788 789 def Filter(mesh): 790 for f in ['head', 791 'topinner', 792 'bottominner', 793 'hands', 794 'feet', 795 'dependantsnude']: 796 if mesh.name.lower().startswith(f): 797 return True 798 799 return False 800 801 index = 0 802 remList = [] 803 for mesh in self.pickAvatar.visualModel.meshes: 804 if not Filter(mesh): 805 remList.append(mesh) 806 807 for m in remList: 808 self.pickAvatar.visualModel.meshes.remove(m) 809 810 self.pickScene.AddDynamic(self.pickAvatar) 811 self.pickScene.RebuildSceneData() 812 cameraProj, cameraView = self.GetProjectionAndViewMatrixFunc() 813 rj = trinity.CreateRenderJob('ProdPickScene') 814 RT = trinity.Tr2RenderTarget(32, 32, 1, trinity.PIXEL_FORMAT.B8G8R8A8_UNORM) 815 depth = trinity.Tr2DepthStencil(32, 32, trinity.DEPTH_STENCIL_FORMAT.D24S8) 816 rj.PushRenderTarget(RT) 817 rj.PushDepthStencil(depth) 818 rj.SetStdRndStates(trinity.RM_PICKING) 819 rj.SetView(cameraView) 820 rj.SetProjection(cameraProj) 821 rj.Update(self.pickScene) 822 rj.RenderScene(self.pickScene) 823 rj.PopDepthStencil() 824 rj.PopRenderTarget() 825 rj.ScheduleOnce() 826 trinity.renderJobs.UnscheduleByName('PickSceneUpdate') 827 self.updateRenderjob = trinity.CreateRenderJob('PickSceneUpdate') 828 self.updateRenderjob.SetView(cameraView) 829 self.updateRenderjob.SetProjection(cameraProj) 830 self.updateRenderjob.Update(self.pickScene) 831 self.updateRenderjob.ScheduleRecurring() 832 self.UpdateBlendShapes([], doUpdate=doUpdate) 833 834 def KeyUpWrapper(self, key): 835 self.keysDown.discard(key) 836 837 def KeyDownWrapper(self, key): 838 self.keysDown.add(key) 839 840 @telemetry.ZONE_METHOD 841 def LoadFieldData(self): 842 self.fieldData = LoadYamlFileNicely('res:/Graphics/Character/Global/FaceSetup/TriangleFields.trif') 843 self.fieldDataAnimation = LoadYamlFileNicely('res:/Graphics/Character/Global/FaceSetup/TriangleFieldsAnimation.trif') 844 845 @telemetry.ZONE_METHOD 846 def FillInFieldData(self): 847 defaultFields = LoadYamlFileNicely('res:/Graphics/Character/Global/FaceSetup/DefaultFields.trif') 848 import copy 849 850 def FillInFields(mapping): 851 for m in mapping: 852 for var in ['Front', 'Side']: 853 fieldName = mapping[m] + '_' + var 854 if fieldName not in self.fieldData['Fields']: 855 defaultField = copy.deepcopy(defaultFields['Fields']['Default_' + var]) 856 newAttr = [] 857 for a in defaultField['Attributes']: 858 newAttr.append(a.replace('XXX', mapping[m])) 859 860 defaultField['Attributes'] = newAttr 861 for v in defaultField['VertData']: 862 for pair in defaultField['VertData'][v]: 863 pair[0] = pair[0].replace('XXX', mapping[m]) 864 865 if False: 866 print('New Field:') 867 print(defaultField) 868 print('-----------------------------------') 869 self.fieldData['Fields'][fieldName] = defaultField 870 871 FillInFields(self.mapping) 872 FillInFields(self.bodyMapping) 873 874 @telemetry.ZONE_METHOD 875 def CalcBaryCentric2DTriangle(self, corners, position): 876 x = [position[0], 877 corners[0][0], 878 corners[1][0], 879 corners[2][0]] 880 y = [position[1], 881 corners[0][1], 882 corners[1][1], 883 corners[2][1]] 884 b0 = (x[2] - x[1]) * (y[3] - y[1]) - (x[3] - x[1]) * (y[2] - y[1]) 885 b1 = ((x[2] - x[0]) * (y[3] - y[0]) - (x[3] - x[0]) * (y[2] - y[0])) / b0 886 b2 = ((x[3] - x[0]) * (y[1] - y[0]) - (x[1] - x[0]) * (y[3] - y[0])) / b0 887 b3 = ((x[1] - x[0]) * (y[2] - y[0]) - (x[2] - x[0]) * (y[1] - y[0])) / b0 888 return (b1, b2, b3) 889 890 @telemetry.ZONE_METHOD 891 def ProjectToTriangle(self, p, a, b, c): 892 import geo2 893 ab = geo2.Vec3Subtract(b, a) 894 ac = geo2.Vec3Subtract(c, a) 895 ap = geo2.Vec3Subtract(p, a) 896 d1 = geo2.Vec3Dot(ab, ap) 897 d2 = geo2.Vec3Dot(ac, ap) 898 if d1 <= 0 and d2 <= 0: 899 return (a, (1, 0, 0)) 900 bp = geo2.Vec3Subtract(p, b) 901 d3 = geo2.Vec3Dot(ab, bp) 902 d4 = geo2.Vec3Dot(ac, bp) 903 if d3 >= 0 and d4 <= d3: 904 return (b, (0, 1, 0)) 905 vc = d1 * d4 - d3 * d2 906 if vc <= 0 and d1 >= 0 and d3 <= 0: 907 v = d1 / (d1 - d3) 908 vab = geo2.Vec3Scale(ab, v) 909 return (geo2.Vec3Add(a, vab), (1.0 - v, v, 0)) 910 cp = geo2.Vec3Subtract(p, c) 911 d5 = geo2.Vec3Dot(ab, cp) 912 d6 = geo2.Vec3Dot(ac, cp) 913 if d6 >= 0 and d5 <= d6: 914 return (c, (0, 0, 1)) 915 vb = d5 * d2 - d1 * d6 916 if vb <= 0 and d2 >= 0 and d6 <= 0: 917 w = d2 / (d2 - d6) 918 wac = geo2.Vec3Scale(ac, w) 919 return (geo2.Vec3Add(a, wac), (1.0 - w, 0, w)) 920 va = d3 * d6 - d5 * d4 921 if va <= 0 and d4 - d3 >= 0 and d5 - d6 >= 0: 922 w = (d4 - d3) / (d4 - d3 + (d5 - d6)) 923 bc = geo2.Vec3Subtract(c, b) 924 wcb = geo2.Vec3Scale(bc, w) 925 return (geo2.Vec3Add(b, wcb), (0, 1.0 - w, w)) 926 denom = 1.0 / (va + vb + vc) 927 v = vb * denom 928 w = vc * denom 929 abv = geo2.Vec3Scale(ab, v) 930 acw = geo2.Vec3Scale(ac, w) 931 r = geo2.Vec3Add(a, abv) 932 r = geo2.Vec3Add(r, acw) 933 return (r, (1.0 - v - w, v, w)) 934 935 @telemetry.ZONE_METHOD 936 def CalculateClosestPosInField(self, position, field): 937 938 def CalcDistance(v1, v2): 939 val = math.sqrt(pow(v1[0] - v2[0], 2) + pow(v1[1] - v2[1], 2)) 940 return val 941 942 pos = [position[0], position[2]] 943 ret = None 944 shortestDistance = 1000000.0 945 for t in field['Tris']: 946 internalPos = self.ProjectToTriangle(pos, t[0][1], t[1][1], t[2][1])[0] 947 dist = CalcDistance(pos, internalPos) 948 if dist < shortestDistance: 949 shortestDistance = dist 950 ret = internalPos 951 952 return ret 953 954 @telemetry.ZONE_METHOD 955 def UpdateFields(self, fieldName, field, secondaryFieldName, secField, delta): 956 threshold = 0.0001 957 markerPos = field['MarkerPosition'] 958 if not len(markerPos) == 3: 959 print('Warning: Field ' + fieldName + ' passing in a 2D coordinate, not a 3D one: ' + str(markerPos)) 960 return {} 961 moveScale = 0.03 962 actualMarkerPos = [markerPos[0], markerPos[1], markerPos[2]] 963 actualMarkerPos[0] += delta[0] * moveScale 964 actualMarkerPos[2] += delta[1] * moveScale 965 newMarkerPos = [actualMarkerPos[0], actualMarkerPos[1], actualMarkerPos[2]] 966 newMarkerPos[0] += self.markerCorrection[0] 967 newMarkerPos[2] += self.markerCorrection[1] 968 tris = field['Tris'] 969 result = [] 970 for t in tris: 971 points2D = [t[0][1], t[1][1], t[2][1]] 972 a, b, c = self.CalcBaryCentric2DTriangle(points2D, (newMarkerPos[0], newMarkerPos[2])) 973 if a >= 0 - threshold and b >= 0 - threshold and c >= 0 - threshold: 974 result = [[t[0][0], a], [t[1][0], b], [t[2][0], c]] 975 self.fieldLKG[fieldName] = result 976 self.fieldLKGPos[fieldName] = newMarkerPos 977 break 978 979 if result != []: 980 self.fieldResetData[fieldName] = newMarkerPos 981 else: 982 closestPos = self.CalculateClosestPosInField(newMarkerPos, field) 983 for t in tris: 984 points2D = [t[0][1], t[1][1], t[2][1]] 985 a, b, c = self.CalcBaryCentric2DTriangle(points2D, closestPos) 986 if a >= 0 - threshold and b >= 0 - threshold and c >= 0 - threshold: 987 result = [[t[0][0], a], [t[1][0], b], [t[2][0], c]] 988 self.fieldLKG[fieldName] = result 989 self.fieldLKGPos[fieldName] = closestPos 990 break 991 992 self.fieldResetData[fieldName] = [closestPos[0], 0.0, closestPos[1]] 993 self.markerCorrection = [closestPos[0] - actualMarkerPos[0], closestPos[1] - actualMarkerPos[2]] 994 finalAttrs = {} 995 newAttrs = {} 996 for r in result: 997 if r[0] in field['VertData']: 998 attrs = field['VertData'][r[0]] 999 weight = r[1] 1000 for a in attrs: 1001 if a[0] in field['Attributes']: 1002 if a[0] not in newAttrs: 1003 newAttrs[a[0]] = weight * a[1] 1004 else: 1005 newAttrs[a[0]] += weight * a[1] 1006 1007 for newAttr in newAttrs: 1008 finalAttrs[newAttr] = newAttrs[newAttr] 1009 1010 if secField: 1011 secMarkerPos = list(secField['MarkerPosition']) 1012 if len(secMarkerPos) == 3: 1013 secMarkerPos[2] = newMarkerPos[2] 1014 tris = secField['Tris'] 1015 result = [] 1016 for t in tris: 1017 points2D = [t[0][1], t[1][1], t[2][1]] 1018 a, b, c = self.CalcBaryCentric2DTriangle(points2D, (secMarkerPos[0], secMarkerPos[2])) 1019 if a >= 0 - threshold and b >= 0 - threshold and c >= 0 - threshold: 1020 result = [[t[0][0], a], [t[1][0], b], [t[2][0], c]] 1021 self.fieldLKG[secondaryFieldName] = result 1022 self.fieldLKGPos[secondaryFieldName] = secMarkerPos 1023 1024 if result != []: 1025 self.fieldResetData[secondaryFieldName] = secMarkerPos 1026 elif secondaryFieldName in self.fieldLKG: 1027 result = self.fieldLKG[secondaryFieldName] 1028 self.fieldResetData[secondaryFieldName] = self.fieldLKGPos[secondaryFieldName] 1029 else: 1030 print("Warning: Can't find secondary field in LKG!") 1031 secFinalAttrs = {} 1032 for r in result: 1033 if r[0] in secField['VertData']: 1034 attrs = secField['VertData'][r[0]] 1035 weight = r[1] 1036 for a in attrs: 1037 if a[0] in secField['Attributes']: 1038 if a[0] not in secFinalAttrs: 1039 secFinalAttrs[a[0]] = weight * a[1] 1040 else: 1041 secFinalAttrs[a[0]] += weight * a[1] 1042 1043 if secFinalAttrs != {}: 1044 for a in secFinalAttrs: 1045 if a in finalAttrs: 1046 finalAttrs[a] = (finalAttrs[a] + secFinalAttrs[a]) / 2.0 1047 else: 1048 finalAttrs[a] = secFinalAttrs[a] 1049 1050 else: 1051 print('Secondary out of range') 1052 else: 1053 print('Warning: Secondary marker coordinate not 3 values.') 1054 return finalAttrs 1055 1056 @telemetry.ZONE_METHOD 1057 def UpdateFieldAnimation(self, delta): 1058 mirror = True 1059 delta[0] = -delta[0] 1060 if self.pickedMesh == 'head': 1061 fieldName = self.mapping[self.zone] 1062 else: 1063 fieldName = 'Body' 1064 animFieldName = '' 1065 if fieldName == 'OuterBrow': 1066 animFieldName = 'EyebrowOuter' 1067 elif fieldName == 'InnerBrow': 1068 animFieldName = 'EyebrowInner' 1069 elif fieldName == 'Chin': 1070 animFieldName = 'Jaw' 1071 mirror = False 1072 elif fieldName == 'MouthCorner': 1073 animFieldName = 'MouthCorner' 1074 elif fieldName in ('EyesInner', 'EyesOuter'): 1075 animFieldName = 'EyeClose' 1076 elif fieldName == 'Eyes': 1077 animFieldName = 'EyeRotation' 1078 mirror = False 1079 elif fieldName == 'CheeksUpper': 1080 animFieldName = 'CheeksUpper' 1081 elif fieldName == 'UpperLip': 1082 animFieldName = 'UpperLip' 1083 elif fieldName == 'Jaw' or fieldName == 'JawCheek' or fieldName == 'Ears': 1084 animFieldName = 'Forehead' 1085 mirror = False 1086 elif fieldName == 'Body': 1087 animFieldName = 'Torso' 1088 mirror = False 1089 else: 1090 animFieldName = 'HeadLookAt' 1091 mirror = False 1092 if mirror and self.pickedSide == 'right': 1093 delta[0] = -delta[0] 1094 if animFieldName in self.fieldDataAnimation['Fields']: 1095 field = self.fieldDataAnimation['Fields'][animFieldName] 1096 secField = None 1097 attrs = self.UpdateFields(animFieldName, field, None, secField, delta) 1098 return attrs 1099 else: 1100 return 1101 1102 @telemetry.ZONE_METHOD 1103 def UpdateField(self, delta): 1104 if self.zone not in self.mapping: 1105 return {} 1106 if self.pickedMesh == 'head': 1107 fieldName = self.mapping[self.zone] 1108 else: 1109 fieldName = 'Body' 1110 if self.zone in self.bodyMapping: 1111 fieldName = self.bodyMapping[self.zone] 1112 secondaryFieldName = '' 1113 if self.direction == 'left' or self.direction == 'right': 1114 secondaryFieldName = fieldName + '_Front' 1115 fieldName = fieldName + '_Side' 1116 if self.direction == 'left': 1117 delta[0] = -delta[0] 1118 else: 1119 secondaryFieldName = fieldName + '_Side' 1120 fieldName += '_Front' 1121 if self.pickedSide == 'left': 1122 delta[0] = -delta[0] 1123 if fieldName in self.fieldData['Fields']: 1124 field = self.fieldData['Fields'][fieldName] 1125 secField = None 1126 if secondaryFieldName in self.fieldData['Fields']: 1127 secField = self.fieldData['Fields'][secondaryFieldName] 1128 attrs = self.UpdateFields(fieldName, field, secondaryFieldName, secField, delta) 1129 return attrs 1130 return {} 1131 1132 @telemetry.ZONE_METHOD 1133 def UpdateFieldsBasedOnExistingValues(self, doll): 1134 if not doll: 1135 return 1136 mods = doll.buildDataManager.GetModifiersAsList() 1137 fieldGroups = {} 1138 for m in mods: 1139 if len(m.name.split('_')) > 1: 1140 if m.categorie == 'facemodifiers' or m.categorie == 'bodyshapes': 1141 group = m.name.split('_')[0] 1142 if group not in fieldGroups: 1143 fieldGroups[group] = {} 1144 axisName = m.name.split('_')[1][:-5] 1145 fieldGroups[group][axisName] = m.weight 1146 1147 for f in self.fieldData['Fields']: 1148 type = f.split('_')[0].lower() 1149 direction = f.split('_')[1].lower() 1150 field = self.fieldData['Fields'][f] 1151 if type in fieldGroups: 1152 attrs = fieldGroups[type] 1153 x = 0.0 1154 y = 0.0 1155 for a in attrs: 1156 if a == 'up': 1157 y = attrs[a] * 2 1158 elif a == 'down': 1159 y = -attrs[a] * 2 1160 elif a == 'left' and direction == 'front': 1161 x = -attrs[a] * 2 1162 elif a == 'right' and direction == 'front': 1163 x = attrs[a] * 2 1164 elif a == 'forward' and direction == 'side': 1165 x = attrs[a] * 2 1166 elif a == 'back' and direction == 'side': 1167 x = -attrs[a] * 2 1168 1169 newPos = [x, 0.0, y] 1170 field['MarkerPosition'] = newPos 1171 self.fieldResetData[f] = newPos 1172 else: 1173 newPos = [0, 0, 0] 1174 field['MarkerPosition'] = newPos 1175 self.fieldResetData[f] = newPos 1176 1177 for meshPicked in ['head', 'body']: 1178 self.pickedMesh = meshPicked 1179 for z in range(20): 1180 self.zone = z 1181 self.UpdateField([0, 0]) 1182 1183 self.zone = 0 1184 result = self.UpdateField([0, 0])