renderer_apparel.py (35805B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\iconrendering2\renderers\renderer_apparel.py 2 from __future__ import print_function 3 import os 4 import wx 5 import dogma.data as dogma_data 6 import trinity 7 import blue 8 import imageutils 9 import PIL.Image as PILImage 10 import charactercreator.client.animparams as animparams 11 import charactercreator.const as ccConst 12 import eve.client.script.ui.login.charcreation.ccUtil as ccUtil 13 import eve.common.script.paperDoll.paperDollDataManagement as pdDm 14 from eve.client.script.paperDoll.paperDollImpl import Doll 15 from eve.client.script.paperDoll.paperDollSpawnWrappers import PaperDollCharacter 16 from eve.common.script.paperDoll.paperDollDefinitions import LOD_SKIN 17 from eve.common.script.util.paperDollBloodLineAssets import bloodlineAssets 18 import evegraphics.settings as settings 19 import types 20 import log 21 from charactercreator.client.characterDollUtilities import CharacterDollUtilities 22 from eve.client.script.ui.camera.charCreationCamera import CharCreationCamera 23 from eve.client.script.ui.login.charcreation.assetRendererConst import DRESSCODE, SETUP, TUCKINDEX, EXAGGERATE, SCARGROUPS, SCARCAMERASETINGS, MALE_MANNEQUIN, FEMALE_MANNEQUIN, LIGHTLOCATION, PIERCINGRIGHTGROUPS, PIERCINGLEFTGROUPS, PIERCINGPAIRGROUPS, NORMAL_LIGHT_SETTINGS, DRESSCODE_CUSTOM_BY_CATEGORY, DRESSCODE_FEMALE_DEFAULT, DRESSCODE_MALE_DEFAULT, DRESSCODE_CATEGORIES, DOLL_MODIFIERS 24 25 def GetNESDirectory(): 26 try: 27 up = os.path.join(os.environ['USERPROFILE']) 28 return os.path.join(up, 'Desktop', 'CharacterIconOutput') 29 except: 30 return '' 31 32 33 def GetNESIconPath(path, genderID): 34 directory = GetNESDirectory() 35 if not os.path.exists(directory): 36 os.mkdir(directory) 37 directory += '\\Male' if genderID == ccConst.GENDERID_MALE else '\\Female' 38 if not os.path.exists(directory): 39 os.mkdir(directory) 40 return directory + '\\' + os.path.basename(path) 41 42 43 CLIENT_OUTPUT_ROOT = 'res:\\UI\\Asset\\' 44 CLEAR_COLOR = (0.9, 45 0.9, 46 0.9, 47 0.0) 48 BACKGROUND_PATH = 'res:/UI/Texture/CharacterCreation/assetBackground.png' 49 RENDER_SIZE = 2048 50 NES_ICON_SIZE = 512 51 CLIENT_ICON_SIZE = 128 52 53 class ApparelRenderer(object): 54 55 def __init__(self, outputSuffix = ''): 56 self.scene = None 57 self.lightScene = None 58 self.camera = None 59 self.characterSvc = sm.GetService('character') 60 self.paperDollClient = sm.GetService('paperDollClient') 61 self.sceneMgr = sm.GetService('sceneManager') 62 self.factory = self.characterSvc.factory 63 self.resolution = ccConst.TEXTURE_RESOLUTIONS[0] 64 self.genClientIcon = True 65 self.genNESIcon = True 66 self.charID = 0 67 self.renderJob = None 68 self.doll = None 69 self.avatar = None 70 self.cdu = CharacterDollUtilities() 71 self.mannequin = None 72 self.backBuffer = None 73 self.floor = None 74 self.rt = None 75 self.clear_step = None 76 self.outputSuffix = outputSuffix 77 78 def SetupScene(self, gender = False, bloodlineID = None): 79 settings.Set(settings.GFX_ANTI_ALIASING, settings.AA_QUALITY_DISABLED) 80 self.scene = trinity.Load(ccConst.SCENE_PATH_CUSTOMIZATION) 81 self.lightScene = trinity.Load(NORMAL_LIGHT_SETTINGS) 82 ccUtil.SetupLighting(self.scene, self.lightScene, self.lightScene) 83 self.camera = CharCreationCamera(None) 84 self.camera.fieldOfView = 0.5 85 self.camera.distance = 7.0 86 self.camera.frontClip = 0.1 87 self.camera.backclip = 100.0 88 if bloodlineID is not None: 89 gender_name = 'female' 90 if gender: 91 gender_name = 'male' 92 self.mannequin = self.PrepareBloodlineDoll(bloodlineID, gender_name, self.scene) 93 self.avatar = self.mannequin.avatar 94 else: 95 self.avatar, self.mannequin = self.CreateAndLoadMannequin(gender, self.scene) 96 self.renderJob = self.CreateCharacterRenderJob('testing') 97 self.SetShadow(self.avatar, self.scene) 98 self.scene.UpdateScene(blue.os.GetSimTime()) 99 blue.resMan.Wait() 100 101 def CreateCharacterRenderJob(self, name): 102 size = RENDER_SIZE 103 rt = trinity.Tr2RenderTarget(size, size, 1, trinity.PIXEL_FORMAT.B8G8R8A8_UNORM) 104 rt.name = 'MyRT' 105 ds = trinity.Tr2DepthStencil(size, size, trinity.DEPTH_STENCIL_FORMAT.AUTO) 106 ds.name = 'MyDS' 107 self.rt = rt 108 rj = trinity.CreateRenderJob('TakeSnapShot') 109 rj.PushRenderTarget(rt) 110 rj.PushDepthStencil(ds) 111 self.clear_step = rj.Clear((0.0, 0.0, 0.0, 0.0), 1.0) 112 rj.SetView(self.camera.viewMatrix) 113 rj.SetProjection(self.camera.projectionMatrix) 114 rj.RenderScene(self.scene) 115 trinity.WaitForResourceLoads() 116 rj.PopDepthStencil() 117 rj.PopRenderTarget() 118 return rj 119 120 def CreateAndLoadMannequin(self, genderID, scene): 121 mannequin = PaperDollCharacter(self.factory) 122 mannequin.doll = Doll('mannequin', gender=ccUtil.GenderIDToPaperDollGender(genderID)) 123 doll = mannequin.doll 124 mannequin.avatar = trinity.Tr2IntSkinnedObject() 125 self.doll = doll 126 if genderID == ccConst.GENDERID_MALE: 127 doll.Load(MALE_MANNEQUIN, self.factory) 128 else: 129 doll.Load(FEMALE_MANNEQUIN, self.factory) 130 self.WaitForDoll(doll) 131 doll.overrideLod = LOD_SKIN 132 doll.textureResolution = self.resolution 133 grannyPath = 'res:/Animation/PortraitCreator/Male/CharacterCreation/Mannequin.gr2' 134 if doll.gender == 'female': 135 grannyPath = 'res:/Animation/PortraitCreator/Female/CharacterCreation/Mannequin.gr2' 136 self.factory.CreateGrannyAnimation(mannequin.avatar, grannyPath) 137 mannequin.Spawn(scene, updateDoll=True) 138 mannequin.WaitForUpdate() 139 return (mannequin.avatar, mannequin) 140 141 def WaitForDoll(self, doll): 142 while doll.busyUpdating: 143 blue.synchro.Yield() 144 145 def WaitForDollAndScene(self, doll, scene): 146 while len(scene.dynamics) < 1: 147 blue.synchro.Yield() 148 149 blue.synchro.Yield() 150 self.WaitForDoll(doll) 151 152 def FreezeCharacter(self, avatar): 153 network = animparams.GetParamsPerAvatar(avatar) 154 network.SetControlParameter('ControlParameters|isAlive', 0) 155 network.update = False 156 blue.synchro.Yield() 157 158 def SetCameraAndLightPiercings(self, category, typeInfo, character, camera, scene): 159 typeName, a, b = typeInfo 160 if typeName.endswith('left', 0, -1): 161 dictToUse = PIERCINGLEFTGROUPS 162 elif typeName.endswith('right', 0, -1): 163 dictToUse = PIERCINGRIGHTGROUPS 164 else: 165 dictToUse = PIERCINGPAIRGROUPS 166 self.SetUpCamera(camera, category, character, dictToUse, scene) 167 168 def SetCameraForScar(self, typeInfo, character, camera, scene): 169 group = SCARGROUPS.get(typeInfo, None) 170 if group is None: 171 print('couldnt find the group, return') 172 return 173 self.SetUpCamera(camera, group, character, SCARCAMERASETINGS, scene) 174 175 def SetCamera(self, camera, poi, distance, yaw, pitch): 176 camera.SetPointOfInterest(poi) 177 camera.distance = distance 178 camera.SetFieldOfView(0.3) 179 camera.SetYaw(yaw) 180 camera.SetPitch(pitch) 181 camera.Update() 182 183 def SetUpCamera(self, camera, category, character, categoryList = SETUP, scene = None, genderID = None): 184 if (category, genderID) in categoryList: 185 options = categoryList[category, genderID] 186 else: 187 options = categoryList.get(category, None) 188 if options: 189 log.LogNotice('+ category = %s' % category) 190 boneName, offset, lightSetting = options 191 if lightSetting: 192 path = '%s%s.red' % (LIGHTLOCATION, lightSetting) 193 lightScene = trinity.Load(path) 194 ccUtil.SetupLighting(scene, lightScene, lightScene) 195 log.LogNotice('before joint') 196 joint = 4294967295L 197 while joint == 4294967295L: 198 log.LogNotice('joint = %s' % joint) 199 log.LogNotice('boneName = %s' % boneName) 200 joint = character.avatar.GetBoneIndex(boneName) 201 log.LogNotice('j = %s' % joint) 202 blue.synchro.Yield() 203 log.LogNotice('done waiting') 204 205 log.LogNotice('-- joint = %s' % joint) 206 poi = character.avatar.GetBonePosition(joint) 207 distance, yOffset, xOffset, yaw, pitch = offset 208 x, y, z = poi 209 if yOffset: 210 y += yOffset 211 if xOffset: 212 x += xOffset 213 poi = (x, y, z) 214 log.LogNotice('before poi') 215 if category in (ccConst.bottomouter, ccConst.feet): 216 poi = (0.0, y, z) 217 log.LogNotice('before setting camera') 218 self.SetCamera(camera, poi, distance, yaw, pitch) 219 log.LogNotice('after setting camera') 220 return (distance, 221 yaw, 222 pitch, 223 poi) 224 else: 225 return 226 227 def GetCategoriesFromPath(self, typeID, genderID): 228 asset = GetPaperDollResource(typeID, genderID) 229 path = '/' + asset.resPath 230 rv = [] 231 categs = SETUP.keys() 232 categs.sort() 233 categs.reverse() 234 for each in categs: 235 if isinstance(each, types.StringTypes): 236 pathstr = '/%s/' % each 237 if pathstr in path.lower(): 238 rv.append(each) 239 240 return rv 241 242 def PrepareBloodlineDoll(self, bloodlineID, paperdollGender, scene): 243 self.characterSvc.RemoveCharacter(self.charID) 244 self.SetupCharacter(bloodlineID, scene, paperdollGender) 245 character = self.characterSvc.GetSingleCharacter(self.charID) 246 character.avatar.translation = (0.0, 0.0, 0.0) 247 grannyPath = 'res:/Animation/PortraitCreator/Male/CharacterCreation/Mannequin.gr2' 248 if character.doll.gender == 'female': 249 grannyPath = 'res:/Animation/PortraitCreator/Female/CharacterCreation/Mannequin.gr2' 250 self.factory.CreateGrannyAnimation(character.avatar, grannyPath) 251 self.WaitForDollAndScene(character.doll, scene) 252 trinity.WaitForResourceLoads() 253 return character 254 255 def SetupCharacter(self, bloodlineID, scene, paperdollGender): 256 self.characterSvc.AddCharacterToScene(self.charID, scene, paperdollGender, bloodlineID=bloodlineID, raceID=None, noRandomize=True) 257 doll = self.characterSvc.GetSingleCharactersDoll(self.charID) 258 self.WaitForDoll(doll) 259 doll.overrideLod = LOD_SKIN 260 doll.textureResolution = self.resolution 261 self.characterSvc.SetDollBloodline(self.charID, bloodlineID) 262 self.characterSvc.ApplyItemToDoll(self.charID, 'head', bloodlineAssets[bloodlineID], doUpdate=False) 263 if paperdollGender == 'female': 264 modifier = doll.AddResource('hair/hair_shortcut_03', 1.0, self.factory) 265 modifier.SetColorVariation('20_a') 266 doll.AddResource('makeup/eyebrows/eyebrows_01', 1.0, self.factory) 267 else: 268 modifier = doll.AddResource('hair/hair_stubble_01', 1.0, self.factory) 269 modifier.SetColorVariation('20_a') 270 doll.AddResource('makeup/eyebrows/eyebrows_01', 1.0, self.factory) 271 self.characterSvc.UpdateDoll(self.charID, fromWhere='RenderLoop') 272 273 def DoRenderNormalAssetType(self, typeID, genderID, bloodlineID = 7, genClientIcon = False, genNESIcon = False): 274 camera = self.camera 275 character = self.mannequin 276 scene = self.scene 277 doll = character.doll 278 for category in self.GetCategoriesFromPath(typeID, genderID): 279 typeData = [typeID] 280 log.LogNotice('before dresscode') 281 if category in DRESSCODE: 282 removeDcModifers = self.EnforceDresscode(bloodlineID, category, doll, genderID, character) 283 log.LogNotice('go render type') 284 for itemType in typeData: 285 wasRendered = self.RenderNormalType(bloodlineID, camera, category, character, genderID, itemType, scene, genClientIcon=genClientIcon, genNESIcon=genNESIcon) 286 287 def DoRenderMannequinAssetType(self, typeID, genderID, category, avatar = None, mannequin = None, scene = None, genNESIcon = False, genClientIcon = False): 288 if avatar is None: 289 avatar = self.avatar 290 if mannequin is None: 291 mannequin = self.mannequin 292 if scene is None: 293 scene = self.scene 294 self.SetUpCamera(self.camera, category, mannequin, scene=scene) 295 mannequin.doll.buildDataManager.SetAllAsDirty() 296 if category == ccConst.bottommiddle: 297 pantsModifiers = mannequin.doll.buildDataManager.GetModifiersByCategory(ccConst.bottomouter) 298 for pm in pantsModifiers: 299 mannequin.doll.RemoveResource(pm.GetResPath(), self.factory) 300 301 modifierList = [] 302 asset = GetPaperDollResource(typeID, genderID) 303 doll = mannequin.doll 304 path = asset.resPath 305 modifier = doll.SetItemType(self.factory, path, weight=1.0) 306 if modifier: 307 modifierList.append(modifier) 308 mannequin.Update() 309 blue.pyos.synchro.SleepWallclock(500) 310 mannequin.WaitForUpdate() 311 if not modifierList: 312 return False 313 self.SetShadow(avatar, scene) 314 outputPath = self.GetOutputPath(assetPath=path, genderID=genderID, useMannequin=True, category=category, typeID=typeID) 315 scene.UpdateScene(blue.os.GetSimTime()) 316 blue.resMan.Wait() 317 if genClientIcon: 318 self.CheckoutFile(outputPath) 319 self.SaveScreenShot(outputPath, CLIENT_ICON_SIZE, True) 320 if genNESIcon: 321 outputPath = GetNESIconPath(outputPath, genderID) 322 self.SaveScreenShot(outputPath, NES_ICON_SIZE, False) 323 for modifier in modifierList: 324 doll.RemoveResource(modifier.GetResPath(), self.factory) 325 326 mannequin.Update() 327 mannequin.WaitForUpdate() 328 return True 329 330 def RenderNormalType(self, bloodlineID, camera, category, character, genderID, itemType, scene, genClientIcon = False, genNESIcon = False): 331 type_res_path = None 332 for resource in cfg.paperdollResources: 333 if resource.typeID == itemType and (resource.resGender == genderID or resource.resGender is None): 334 type_res_path = resource.resPath 335 336 if type_res_path is None: 337 raise ValueError('Type ID not found! %d' % itemType) 338 doll = character.doll 339 doll.buildDataManager.SetAllAsDirty() 340 modifier = doll.SetItemType(self.factory, type_res_path, weight=1.0) 341 if 'tattoo/head' in type_res_path.lower() and modifier: 342 modifier.SetColorVariation('default_a') 343 if not modifier: 344 return False 345 typeInfo = self.GetCategoriesFromPath(itemType, genderID) 346 self.ApplyTuckingIfNeeded(category) 347 self.TrySetColor(bloodlineID, category, genderID, typeInfo) 348 if (category, genderID) in EXAGGERATE: 349 if getattr(modifier, 'weight', None) is not None: 350 modifier.weight = 1.5 * modifier.weight 351 character.Update() 352 blue.pyos.synchro.SleepWallclock(500) 353 character.WaitForUpdate() 354 blue.resMan.Wait() 355 trinity.WaitForResourceLoads() 356 self.SetShadow(character.avatar, scene) 357 outputPath = self.GetOutputPath(assetPath=type_res_path, genderID=genderID, category=category, bloodlineID=bloodlineID, typeID=itemType) 358 if genderID == ccConst.GENDERID_FEMALE: 359 character.avatar.animationUpdater.boneOffset.ClearTransforms() 360 scene.UpdateScene(blue.os.GetSimTime()) 361 blue.resMan.Wait() 362 if genClientIcon: 363 self.CheckoutFile(outputPath) 364 self.SaveScreenShot(outputPath, CLIENT_ICON_SIZE, True) 365 if genNESIcon: 366 outputPath = GetNESIconPath(outputPath, genderID) 367 self.SaveScreenShot(outputPath, NES_ICON_SIZE, False) 368 return True 369 370 def EnforceDresscode(self, bloodlineID, category, doll, genderID, character): 371 if category in DRESSCODE_CUSTOM_BY_CATEGORY: 372 dressCode = DRESSCODE_CUSTOM_BY_CATEGORY[category][genderID] 373 elif genderID == ccConst.GENDERID_FEMALE: 374 dressCode = DRESSCODE_FEMALE_DEFAULT 375 else: 376 dressCode = DRESSCODE_MALE_DEFAULT 377 removeDcModifers = [] 378 for dcCategory in DRESSCODE_CATEGORIES: 379 if dcCategory == category: 380 continue 381 dcTypeData = self.characterSvc.GetAvailableTypesByCategory(dcCategory, genderID, bloodlineID, None, forceAllTypes=True) 382 if not dcTypeData: 383 continue 384 for itemType in dcTypeData: 385 assetID = itemType[0] 386 if assetID in dressCode: 387 if dcCategory == ccConst.hair: 388 var = self.GetHairColor(genderID, bloodlineID) 389 else: 390 var = None 391 asset = GetPaperDollResource(itemType, genderID) 392 type_res_path = asset.resPath 393 dcModifier = doll.SetItemType(self.factory, type_res_path, weight=1.0) 394 character.Update() 395 character.WaitForUpdate() 396 if dcModifier: 397 removeDcModifers.append(dcModifier.GetResPath()) 398 self.WaitForDoll(doll) 399 blue.resMan.Wait() 400 break 401 402 return removeDcModifers 403 404 def ApplyTuckingIfNeeded(self, category): 405 if category not in TUCKINDEX: 406 return 407 tuckPath, requiredModifier, subKey = ccConst.TUCKMAPPING[category] 408 tuckModifier = sm.GetService('character').GetModifierByCategory(self.charID, tuckPath) 409 if tuckModifier: 410 tuckVariations = tuckModifier.GetVariations() 411 tuckStyle = tuckModifier.GetResPath().split('/')[-1] 412 self.characterSvc.ApplyItemToDoll(self.charID, category, tuckStyle, variation=tuckVariations[TUCKINDEX[category]]) 413 414 def TrySetColor(self, bloodlineID, category, genderID, typeInfo): 415 if category in (ccConst.beard, ccConst.hair, ccConst.eyebrows): 416 category = ccConst.hair 417 try: 418 if typeInfo[1] or typeInfo[2]: 419 return 420 categoryColors = self.characterSvc.GetAvailableColorsForCategory(category, genderID, None) 421 if not categoryColors: 422 return 423 primary, secondary = categoryColors 424 primaryVal = (primary[1][0], primary[1][2]) 425 if primary and secondary: 426 secondaryVal = (secondary[1][0], secondary[1][2]) 427 self.characterSvc.SetColorValueByCategory(self.charID, category, primaryVal, secondaryVal) 428 else: 429 self.characterSvc.SetColorValueByCategory(self.charID, category, primaryVal, None) 430 except: 431 pass 432 finally: 433 if category == ccConst.hair: 434 sm.GetService('character').SetHairDarkness(0, 0.5) 435 436 def SetShadow(self, avatar, scene): 437 scene.shadowSize = 2048 438 439 def GetHairColor(self, genderID, bloodlineID): 440 colorsA, colorsB = sm.GetService('character').GetAvailableColorsForCategory(ccConst.hair, genderID, None) 441 colorA = [] 442 colorB = [] 443 var = None 444 color1Value, color1Name, color2Name, variation = (None, None, None, None) 445 if len(colorsA) > 0: 446 indexA = int(len(colorsA) * 0.3) 447 colorA = colorsA[indexA] 448 colorB = None 449 if len(colorsB) > 0: 450 colorB = colorsB[0] 451 color1Value, color1Name, color2Name, variation = sm.GetService('character').GetColorsToUse(colorA, colorB) 452 if color1Value: 453 return var 454 if colorB: 455 var = variation 456 elif len(colorA) > 0: 457 var = colorA[1] 458 return var 459 460 @staticmethod 461 def CheckoutFile(path): 462 import ccpp4 463 p4 = ccpp4.P4Init() 464 try: 465 if p4.EditOrAdd(path, False): 466 return True 467 except: 468 pass 469 470 return False 471 472 def GetScreenshotRenderTarget(self, rt): 473 readable = trinity.Tr2RenderTarget(rt.width, rt.height, 1, rt.format) 474 if not readable.isValid: 475 raise RuntimeError('out of video memory') 476 rt.Resolve(readable) 477 return readable 478 479 def Tr2HostBitmapToPILImage(self, hostBitmap): 480 import tempfile 481 if not hostBitmap: 482 return 483 fd, path = tempfile.mkstemp(suffix='.png') 484 hostBitmap.Save(path) 485 bitmap = PILImage.open(path) 486 bitmap.load() 487 os.close(fd) 488 os.remove(path) 489 return bitmap 490 491 def SaveScreenShot(self, outputPath, targetRes = 512, applyBackground = False): 492 import imageutils 493 from PIL import Image as PILImage 494 print('SaveScreenShot', outputPath) 495 blue.resMan.Wait() 496 self.render_frame(self.renderJob) 497 backbuffer = self.rt 498 image = self.CreateAlphaPreservingScreenShot(backbuffer, self.renderJob, clearStep=self.clear_step) 499 if applyBackground: 500 background = PILImage.open(blue.paths.ResolvePath(BACKGROUND_PATH)) 501 background.load() 502 if background.size[0] != RENDER_SIZE: 503 background = background.resize((RENDER_SIZE, RENDER_SIZE), PILImage.ANTIALIAS) 504 image = PILImage.composite(image, background, image) 505 if targetRes != RENDER_SIZE: 506 image = image.resize((targetRes, targetRes), PILImage.ANTIALIAS) 507 imageutils.from_pil(image).save(outputPath) 508 509 def GetOutputPath(self, assetPath, genderID, useMannequin = False, category = None, bloodlineID = -1, typeID = None): 510 assetResPath = self.ReformatAssetPath(assetPath) 511 categoryPath = self.ReformatAssetPath(category) 512 subFolder = 'mannequin/' + categoryPath + '/' 513 ccUtil.CreateCategoryFolderIfNeeded(blue.paths.ResolvePath(CLIENT_OUTPUT_ROOT), subFolder) 514 outputPath = blue.paths.ResolvePath(CLIENT_OUTPUT_ROOT) + subFolder 515 suffix = 'png' 516 if self.outputSuffix != '': 517 suffix = '%s.' % self.outputSuffix + suffix 518 if typeID: 519 if genderID == ccConst.GENDERID_MALE: 520 gender = 'male' 521 else: 522 gender = 'female' 523 outputPath = outputPath + '%s_%s_%s.%s' % (typeID, 524 gender, 525 assetResPath, 526 suffix) 527 elif bloodlineID < 0: 528 outputPath = outputPath + '%s_g%s.%s' % (assetResPath, genderID, suffix) 529 else: 530 outputPath = outputPath + '%s_g%s_b%s.%s' % (assetResPath, 531 genderID, 532 bloodlineID, 533 suffix) 534 return outputPath 535 536 @staticmethod 537 def ReformatAssetPath(path): 538 assetResPath = path.replace('/', '_').replace('.type', '') 539 return assetResPath 540 541 def GetClearColor(self): 542 return self.clear_step.color 543 544 def SetClearColor(self, newColor): 545 self.clear_step.color = newColor 546 547 def FreezeRenderJob(self, rj): 548 try: 549 rj.scene.object.update = False 550 rj.scene.object.backgroundRenderingEnabled = False 551 except: 552 pass 553 554 trinity.device.animationTimeScale = 0 555 556 def ThawRenderJob(self, rj): 557 try: 558 rj.scene.object.update = True 559 rj.scene.object.backgroundRenderingEnabled = True 560 except: 561 pass 562 563 def CreateRGPCompositeEffect(self, shotA, shotAColor, shotB, shotBColor, finalImage): 564 effect = trinity.Tr2Effect() 565 effect.effectFilePath = 'res:/graphics/Effect/Managed/Space/System/BlueScreenMatting.fx' 566 param = trinity.TriTextureParameter() 567 param.name = 'ShotA' 568 res = trinity.TriTextureRes() 569 res.SetFromRenderTarget(shotA) 570 param.SetResource(res) 571 effect.resources.append(param) 572 param = trinity.Tr2Vector4Parameter() 573 param.name = 'shotABackgroundColor' 574 param.value = shotAColor 575 effect.parameters.append(param) 576 param = trinity.TriTextureParameter() 577 param.name = 'ShotB' 578 res = trinity.TriTextureRes() 579 res.SetFromRenderTarget(shotB) 580 param.SetResource(res) 581 effect.resources.append(param) 582 param = trinity.Tr2Vector4Parameter() 583 param.name = 'shotBBackgroundColor' 584 param.value = shotBColor 585 effect.parameters.append(param) 586 param = trinity.TriTextureParameter() 587 param.name = 'FinalImage' 588 res = trinity.TriTextureRes() 589 res.SetFromRenderTarget(finalImage) 590 param.SetResource(res) 591 effect.resources.append(param) 592 return effect 593 594 def RunRGBCompositeEffect(self, effect, width, height): 595 rt = trinity.Tr2RenderTarget(width, height, 1, trinity.PIXEL_FORMAT.B8G8R8A8_UNORM) 596 rj = trinity.CreateRenderJob('rj') 597 rj.steps.append(trinity.TriStepPushRenderTarget(rt)) 598 rj.steps.append(trinity.TriStepClear((0, 0, 0, 0))) 599 rj.steps.append(trinity.TriStepSetStdRndStates(trinity.RM_FULLSCREEN)) 600 rj.steps.append(trinity.TriStepPushDepthStencil(None)) 601 rj.steps.append(trinity.TriStepRenderEffect(effect)) 602 rj.steps.append(trinity.TriStepPopRenderTarget()) 603 rj.steps.append(trinity.TriStepPopDepthStencil()) 604 trinity.WaitForResourceLoads() 605 rj.ScheduleOnce() 606 rj.WaitForFinish() 607 return trinity.Tr2HostBitmap(rt) 608 609 def CreateAlphaPreservingScreenShot(self, backBuffer, rj, clearStep = None): 610 originalClearColor = self.GetClearColor() 611 try: 612 bloom = True 613 try: 614 bloom = rj.postProcess.Bloom 615 rj.postProcess.Bloom = False 616 except: 617 pass 618 619 self.FreezeRenderJob(rj) 620 colorA = (1.0, 0.0, 1.0, 1.0) 621 self.SetClearColor(colorA) 622 self.render_frame(rj) 623 shotA = self.GetScreenshotRenderTarget(backBuffer) 624 imA = trinity.Tr2HostBitmap(shotA) 625 colorB = (0.0, 1.0, 0.0, 0.0) 626 self.SetClearColor(colorB) 627 self.render_frame(rj) 628 shotB = self.GetScreenshotRenderTarget(backBuffer) 629 imB = trinity.Tr2HostBitmap(shotB) 630 try: 631 rj.postProcess.Bloom = bloom 632 except: 633 pass 634 635 self.SetClearColor((0, 0, 0, 0)) 636 self.render_frame(rj) 637 final = self.GetScreenshotRenderTarget(backBuffer) 638 imFinal = trinity.Tr2HostBitmap(final) 639 effect = self.CreateRGPCompositeEffect(shotA, colorA, shotB, colorB, final) 640 bmp = self.RunRGBCompositeEffect(effect, backBuffer.width, backBuffer.height) 641 return self.Tr2HostBitmapToPILImage(bmp) 642 except: 643 import traceback 644 traceback.print_exc() 645 return 646 finally: 647 self.SetClearColor(originalClearColor) 648 self.ThawRenderJob(rj) 649 trinity.device.animationTimeScale = 1.0 650 651 def render_frame(self, rj): 652 rj.ScheduleOnce() 653 rj.WaitForFinish() 654 655 656 def GetValidPaperDollGenders(typeID): 657 genders = [] 658 for each in cfg.paperdollResources: 659 if each.typeID == typeID: 660 if each.resGender is not None: 661 genders.append(each.resGender) 662 else: 663 genders.append(0) 664 genders.append(1) 665 666 return genders 667 668 669 def GetPaperDollCategory(typeID, genderID): 670 for each in cfg.paperdollResources: 671 if each.typeID == typeID: 672 asset = GetPaperDollResource(typeID, genderID) 673 path = '/' + asset.resPath 674 rv = [] 675 categs = SETUP.keys() 676 categs.sort() 677 categs.reverse() 678 for each in categs: 679 if isinstance(each, types.StringTypes): 680 pathstr = '/%s/' % each 681 if pathstr in path.lower(): 682 rv.append(each) 683 684 return rv 685 686 687 def GetPaperDollResource(typeID, genderID): 688 assets = [] 689 for each in cfg.paperdollResources: 690 if type(typeID) is int and each.typeID == typeID: 691 assets.append(each) 692 elif type(typeID) is tuple and typeID[1][0] in each.resPath.lower(): 693 assets.append(each) 694 695 if len(assets) == 1: 696 return assets[0] 697 if len(assets) > 1: 698 for asset in assets: 699 if genderID == asset.resGender: 700 return asset 701 702 log.LogError('PreviewWnd::PreviewType - No asset matched the typeID: %d' % typeID) 703 704 705 def IsValidType(typeID): 706 for each in cfg.paperdollResources: 707 if each.typeID == typeID: 708 return True 709 710 return False 711 712 713 def OpenTrinityWindow(): 714 mainFrame = wx.GetApp().GetTopWindow() 715 tp = mainFrame.windowManager.GetWindow('Trinity Panel') 716 717 718 class RenderCharacter(object): 719 720 def __init__(self, doll, avatar): 721 self.doll = doll 722 self.avatar = avatar 723 724 725 def setup_cfg(): 726 import fsdBuiltData.common.character as fsdchar 727 charSvc = sm.GetService('character') 728 charSvc.assetsToIDs = {'male': None, 729 'female': None} 730 paperdollModifierLocations = fsdchar.GetModifierLocationRows() 731 paperdollResources = fsdchar.GetResourceRows() 732 paperdollSculptingLocations = fsdchar.GetSculptingLocationRows() 733 paperdollColors = fsdchar.GetColorLocationRows() 734 paperdollColorNames = fsdchar.GetColorNameRows() 735 paperdollPortraitResources = fsdchar.GetPortraitResourceRows() 736 cfg.paperdollModifierLocations = paperdollModifierLocations 737 cfg.paperdollResources = paperdollResources 738 cfg.paperdollSculptingLocations = paperdollSculptingLocations 739 cfg.paperdollColors = paperdollColors 740 cfg.paperdollColorNames = paperdollColorNames 741 cfg.paperdollPortraitResources = paperdollPortraitResources 742 dogma_data.get_all_attributes = lambda : [] 743 dogma_data.get_all_effects = lambda : [] 744 charSvc.PopulateModifierLocationDicts(True) 745 746 747 def RenderClientIcon(typenum, gender, outputSuffix = ''): 748 if outputSuffix == '' or outputSuffix == 'EN': 749 blue.os.languageID = 'EN' 750 elif outputSuffix == 'ZH': 751 blue.os.languageID = 'ZH' 752 if not IsValidType(typenum): 753 print('***** Type %d does not match a paperdoll resource. *****' % typenum) 754 return False 755 pdDm.ClearAllCachedMaps() 756 aprenderer = ApparelRenderer(outputSuffix) 757 OpenTrinityWindow() 758 if GetPaperDollCategory(typenum, gender)[0] in DOLL_MODIFIERS: 759 curr_bloodline = 1 760 aprenderer.SetupScene(gender, bloodlineID=curr_bloodline) 761 aprenderer.mannequin.doll.buildDataManager.SetAllAsDirty() 762 aprenderer.SetUpCamera(aprenderer.camera, GetPaperDollCategory(typenum, gender)[0], aprenderer.mannequin, scene=aprenderer.scene) 763 aprenderer.DoRenderNormalAssetType(typenum, gender, bloodlineID=curr_bloodline, genClientIcon=True) 764 else: 765 aprenderer.SetupScene(gender) 766 aprenderer.SetUpCamera(aprenderer.camera, GetPaperDollCategory(typenum, gender)[0], aprenderer.mannequin, scene=aprenderer.scene) 767 aprenderer.DoRenderMannequinAssetType(typenum, gender, GetPaperDollCategory(typenum, gender)[0], genClientIcon=True) 768 769 770 def RenderNESIcon(typenum, gender, outputSuffix = ''): 771 if outputSuffix == '' or outputSuffix == 'EN': 772 blue.os.languageID = 'EN' 773 elif outputSuffix == 'ZH': 774 blue.os.languageID = 'ZH' 775 if not IsValidType(typenum): 776 print('***** Type %d does not match a paperdoll resource. *****' % typenum) 777 return False 778 pdDm.ClearAllCachedMaps() 779 aprenderer = ApparelRenderer(outputSuffix) 780 OpenTrinityWindow() 781 if GetPaperDollCategory(typenum, gender)[0] in DOLL_MODIFIERS: 782 curr_bloodline = 1 783 aprenderer.SetupScene(gender, bloodlineID=curr_bloodline) 784 aprenderer.SetUpCamera(aprenderer.camera, GetPaperDollCategory(typenum, gender)[0], aprenderer.mannequin, scene=aprenderer.scene) 785 aprenderer.DoRenderNormalAssetType(typenum, gender, bloodlineID=curr_bloodline, genNESIcon=True) 786 else: 787 aprenderer.SetupScene(gender) 788 aprenderer.SetUpCamera(aprenderer.camera, GetPaperDollCategory(typenum, gender)[0], aprenderer.mannequin, scene=aprenderer.scene) 789 aprenderer.DoRenderMannequinAssetType(typenum, gender, GetPaperDollCategory(typenum, gender)[0], genNESIcon=True) 790 791 792 def ProcessTypes(typeslist, genClientIconCB, genNESIconCB, outputSuffix = ''): 793 print('************** STARTING APPAREL RENDER *************************') 794 types_string = str(typeslist) 795 types = [ int(t) for t in types_string.split(',') ] 796 for typenum in types: 797 genders = GetValidPaperDollGenders(typenum) 798 for gender in genders: 799 if genClientIconCB: 800 print('Rendering %s Client Icon for type %d gender %d' % (outputSuffix, typenum, gender)) 801 RenderClientIcon(typenum, gender, outputSuffix) 802 if genNESIconCB: 803 print('Rendering %s NES Icon for type %d gender %d' % (outputSuffix, typenum, gender)) 804 RenderNESIcon(typenum, gender, outputSuffix) 805 806 807 TYPES_TEXT_CONTROL = None 808 GEN_CLIENT_ICON_CB = None 809 GEN_NES_ICON_CB = None 810 RESOURCE_LANGUAGE_DROPDOWN = False 811 812 class RenderIconDialog(wx.Dialog): 813 814 def __init__(self, *args, **kw): 815 super(RenderIconDialog, self).__init__(*args, **kw) 816 self.InitUI() 817 self.SetSize((400, 300)) 818 self.SetTitle('Apparel Icon Render') 819 820 def InitUI(self): 821 global TYPES_TEXT_CONTROL 822 global GEN_NES_ICON_CB 823 global RESOURCE_LANGUAGE_DROPDOWN 824 global GEN_CLIENT_ICON_CB 825 pnl = wx.Panel(self) 826 vbox = wx.BoxSizer(wx.VERTICAL) 827 sb = wx.StaticBox(pnl, label='Render Parameters') 828 sbs = wx.StaticBoxSizer(sb, orient=wx.VERTICAL) 829 GEN_CLIENT_ICON_CB = wx.CheckBox(pnl, label='Generate Client Icon') 830 sbs.Add(GEN_CLIENT_ICON_CB) 831 GEN_NES_ICON_CB = wx.CheckBox(pnl, label='Generate NES Icon') 832 sbs.Add(GEN_NES_ICON_CB) 833 sbs.Add(wx.StaticText(pnl, -1, 'Resource Language')) 834 RESOURCE_LANGUAGE_DROPDOWN = wx.ComboBox(pnl, value='EN', choices=['EN', 'ZH'], style=wx.CB_READONLY) 835 sbs.Add(RESOURCE_LANGUAGE_DROPDOWN) 836 sbs.Add(wx.StaticText(pnl, -1, 'Types')) 837 TYPES_TEXT_CONTROL = wx.TextCtrl(pnl, size=(300, -1)) 838 sbs.Add(TYPES_TEXT_CONTROL, flag=wx.LEFT, border=5) 839 pnl.SetSizer(sbs) 840 hbox2 = wx.BoxSizer(wx.HORIZONTAL) 841 okButton = wx.Button(self, label='Ok') 842 closeButton = wx.Button(self, label='Close') 843 hbox2.Add(okButton) 844 hbox2.Add(closeButton, flag=wx.LEFT, border=5) 845 vbox.Add(pnl, flag=wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, border=10) 846 vbox.Add(hbox2, flag=wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, border=10) 847 self.SetSizer(vbox) 848 okButton.Bind(wx.EVT_BUTTON, self.OnOk) 849 closeButton.Bind(wx.EVT_BUTTON, self.OnClose) 850 851 def OnClose(self, e): 852 self.Destroy() 853 854 def OnOk(self, e): 855 typeslist = TYPES_TEXT_CONTROL.GetValue() 856 genClientIconCB = GEN_CLIENT_ICON_CB.GetValue() 857 genNESIconCB = GEN_NES_ICON_CB.GetValue() 858 self.Destroy() 859 ProcessTypes(typeslist, genClientIconCB, genNESIconCB, outputSuffix=RESOURCE_LANGUAGE_DROPDOWN.GetValue().replace('EN', '')) 860 861 862 def start(): 863 setup_cfg() 864 cdDialog = RenderIconDialog(None, title='Apparel Icon Render') 865 cdDialog.ShowModal()