TextureCompositor.py (20826B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\TextureCompositor\TextureCompositor.py 2 from contextlib import contextmanager 3 import trinity 4 import blue 5 import log 6 RUN_RENDER_JOB, RETURN_RENDER_JOB = range(2) 7 DIFFUSE_MAP, SPECULAR_MAP, NORMAL_MAP, MASK_MAP = range(4) 8 MAPS = (DIFFUSE_MAP, 9 SPECULAR_MAP, 10 NORMAL_MAP, 11 MASK_MAP) 12 MAPNAMES = ('DiffuseMap', 'SpecularMap', 'NormalMap', 'CutMaskMap') 13 EFFECT_LOCATION = 'res:/Graphics/Effect/Utility/Compositing' 14 COMPOSITE_SHADER_PATHS = ['AlphaFill.fx', 15 'BlitIntoAlpha1.fx', 16 'BlitIntoAlpha2.fx', 17 'BlitIntoAlphaWithZones.fx', 18 'BlitUVOffset.fx', 19 'ColorCopyblit.fx', 20 'ColorCopyblitToGamma.fx', 21 'ColorFill.fx', 22 'ColorizedBlit.fx', 23 'ColorizedBlit_AlphaTest.fx', 24 'ColorizedCopyBlit.fx', 25 'Copyblit.fx', 26 'ExpandOpaque.fx', 27 'ExpandOpaqueNoMask.fx', 28 'MaskedNormalBlit.fx', 29 'PatternBlit.fx', 30 'SimpleBlit.fx', 31 'SphericalCircleBlit.fx', 32 'TwistNormalBlit.fx'] 33 COMPRESS_DXT1 = trinity.TR2DXT_COMPRESS_SQUISH_DXT1 34 COMPRESS_DXT5 = trinity.TR2DXT_COMPRESS_SQUISH_DXT5 35 COMPRESS_DXT5n = trinity.TR2DXT_COMPRESS_RT_DXT5N 36 37 class TextureLoadingError(Exception): 38 pass 39 40 41 def _GetEffectsToCache(): 42 effects = [] 43 for each in COMPOSITE_SHADER_PATHS: 44 effect = trinity.Tr2Effect() 45 effect.effectFilePath = EFFECT_LOCATION + '/' + each 46 effects.append(effect) 47 48 return effects 49 50 51 def _CreateParameter(paramType, paramName, paramValue): 52 param = paramType 53 param.name = paramName 54 if isinstance(paramValue, list): 55 paramValue = tuple(paramValue) 56 param.value = paramValue 57 return param 58 59 60 def _AppendParameter(effect, paramName, paramValue): 61 try: 62 value = tuple(paramValue) 63 except TypeError: 64 value = (paramValue,) 65 66 value += (0.0,) * (4 - len(value)) 67 effect.constParameters.append((paramName, value)) 68 69 70 @contextmanager 71 def _UpdateEffect(effect): 72 effect.StartUpdate() 73 try: 74 yield 75 finally: 76 effect.EndUpdate() 77 78 79 class TextureCompositor(object): 80 cachedEffects = None 81 82 def __init__(self, renderTarget = None, resData = None, targetWidth = 0): 83 self.renderJob = None 84 self.renderTarget = renderTarget 85 self.targetWidth = targetWidth 86 self.resData = resData 87 self._texturesWithCutouts = [] 88 self._texturesByResourceID = {} 89 self._resourcesToLoad = [] 90 if not TextureCompositor.cachedEffects: 91 TextureCompositor.cachedEffects = _GetEffectsToCache() 92 93 def _CreateResource(self, effect, paramName, resPath, cutoutName = None, mapType = ''): 94 if not resPath: 95 raise Exception('Invalid resource passed to texture compositor!') 96 elif isinstance(resPath, basestring): 97 resPath = str(resPath) 98 if self.targetWidth > 0 and self.resData: 99 resDataEntry = self.resData.GetEntryByFullResPath(resPath) 100 if resDataEntry: 101 resPath = resDataEntry.GetMapResolutonMatch(resPath, self.targetWidth) 102 paramRes = blue.resMan.GetResource(resPath) 103 elif isinstance(resPath, trinity.TriTextureRes): 104 paramRes = resPath 105 elif hasattr(resPath, 'resource'): 106 paramRes = resPath.resource 107 else: 108 raise Exception('Invalid resource passed to texture compositor!') 109 if paramRes is None: 110 raise Exception('Invalid resource passed to texture compositor!') 111 param = trinity.TriTextureParameter() 112 param.name = paramName 113 param.SetResource(paramRes) 114 item = (paramRes, 115 effect, 116 cutoutName, 117 mapType) 118 if cutoutName: 119 self._texturesWithCutouts.append(item) 120 self._texturesByResourceID[id(paramRes)] = item 121 if paramRes not in self._resourcesToLoad: 122 self._resourcesToLoad.append(paramRes) 123 return param 124 125 def _AppendResource(self, effect, paramName, resPath, cutoutName = None, mapType = ''): 126 effect.resources.append(self._CreateResource(effect, paramName, resPath, cutoutName, mapType)) 127 128 def _MakeEffect(self, effectName): 129 effect = trinity.Tr2Effect() 130 effect.effectFilePath = '{0}/{1}.fx'.format(EFFECT_LOCATION, effectName) 131 self._resourcesToLoad.append(effect.effectResource) 132 return effect 133 134 def Start(self, clear = True): 135 self.renderJob = trinity.CreateRenderJob('Texture Compositing') 136 self.renderJob.PushRenderTarget(self.renderTarget) 137 self.renderJob.PushDepthStencil(None) 138 if clear: 139 cl = self.renderJob.Clear((0.0, 1.0, 0.0, 0.0), 1.0) 140 cl.isDepthCleared = False 141 self.renderJob.SetStdRndStates(trinity.RM_FULLSCREEN) 142 143 def _WaitForLoads(self): 144 while any((not x.isPrepared for x in self._resourcesToLoad)): 145 blue.synchro.Yield() 146 147 not_good = [ not x.isGood for x in self._resourcesToLoad ] 148 if any(not_good): 149 for idx, state in enumerate(not_good): 150 if state: 151 x = self._resourcesToLoad[idx] 152 errpath = '(Effect Resource)' 153 if hasattr(x, 'path'): 154 errpath = x.path 155 log.LogError('TextureCompositor:: Texture load failed %s' % errpath) 156 raise TextureLoadingError('TextureCompositor:: Texture load failed %s' % errpath) 157 158 def _AddCutoutParameters(self): 159 lastFx = None 160 for resource, effect, name, _ in self._texturesWithCutouts: 161 cutout = (resource.cutoutX, 162 resource.cutoutY, 163 resource.cutoutWidth, 164 resource.cutoutHeight) 165 if lastFx != effect: 166 if lastFx: 167 lastFx.EndUpdate() 168 lastFx = effect 169 lastFx.StartUpdate() 170 _AppendParameter(lastFx, name, cutout) 171 172 if lastFx: 173 lastFx.EndUpdate() 174 175 def _AddTextureTypeParameters(self): 176 for step in self.renderJob.steps: 177 if isinstance(step, trinity.TriStepRenderEffect): 178 step.effect.StartUpdate() 179 for res in step.effect.resources: 180 mapFormat = res.resource.format 181 if mapFormat == trinity.PIXEL_FORMAT.R8_UNORM: 182 _AppendParameter(step.effect, res.name.lower() + '_L8', 1.0) 183 elif mapFormat == trinity.PIXEL_FORMAT.R8G8_UNORM: 184 _AppendParameter(step.effect, res.name.lower() + '_L8A8', 1.0) 185 r = self._texturesByResourceID.get(id(res.resource)) 186 if r: 187 mapName = r[3] 188 if mapName == 'N' and mapFormat == trinity.PIXEL_FORMAT.R8G8_UNORM: 189 _AppendParameter(step.effect, res.name.lower() + '_blitAsNormal', 1.0) 190 191 step.effect.EndUpdate() 192 193 def Finalize(self, textureToCopyTo = None, compressionSettings = None, mapType = None): 194 self._WaitForLoads() 195 doCompression = compressionSettings and compressionSettings.compressTextures and compressionSettings.AllowCompress(mapType) 196 if doCompression: 197 textureToCopyTo = None 198 self._AddCutoutParameters() 199 self._AddTextureTypeParameters() 200 self.renderJob.PopDepthStencil() 201 self.renderJob.PopRenderTarget() 202 self.renderJob.GenerateMipMaps(self.renderTarget) 203 if textureToCopyTo is not None: 204 self.renderJob.CopyRenderTarget(textureToCopyTo, self.renderTarget) 205 self.renderJob.ScheduleChained() 206 try: 207 self.renderJob.WaitForFinish() 208 except Exception: 209 self.renderJob.CancelChained() 210 raise 211 212 self._texturesWithCutouts = [] 213 self._texturesByResourceID.clear() 214 if self.renderJob.status != trinity.RJ_DONE: 215 return 216 if not doCompression: 217 if textureToCopyTo is not None: 218 while not textureToCopyTo.isPrepared: 219 blue.synchro.Yield() 220 221 if not textureToCopyTo.isGood: 222 log.LogError('TextureCompositor:: Texture %s failed to load properly' % textureToCopyTo.name) 223 raise TextureLoadingError('TextureCompositor:: Texture %s failed to load properly' % textureToCopyTo.name) 224 return textureToCopyTo 225 tex = trinity.TriTextureRes() 226 tex.CreateAndCopyFromRenderTarget(self.renderTarget) 227 while not tex.isPrepared: 228 blue.synchro.Yield() 229 230 if not tex.isGood: 231 log.LogError('TextureCompositor:: Texture %s failed to load properly' % tex.name) 232 raise TextureLoadingError('TextureCompositor:: Texture %s failed to load properly' % tex.name) 233 return tex 234 hostBitmap = trinity.Tr2HostBitmap(self.renderTarget) 235 tex = trinity.TriTextureRes() 236 compressionFormat = COMPRESS_DXT5n if mapType is NORMAL_MAP else COMPRESS_DXT5 237 hostBitmap.Compress(compressionFormat, compressionSettings.qualityLevel, tex) 238 while not tex.isPrepared: 239 blue.synchro.Yield() 240 241 if not tex.isGood: 242 log.LogError('TextureCompositor:: Texture %s failed to load properly' % tex.name) 243 raise TextureLoadingError('TextureCompositor:: Texture %s failed to load properly' % tex.name) 244 return tex 245 246 def _CompositeTexture(self, effect, subrect = None): 247 vp = trinity.TriViewport() 248 if subrect: 249 vp.x = subrect[0] 250 vp.y = subrect[1] 251 vp.width = subrect[2] - subrect[0] 252 vp.height = subrect[3] - subrect[1] 253 else: 254 vp.x = 0 255 vp.y = 0 256 vp.width = self.renderTarget.width 257 vp.height = self.renderTarget.height 258 self.renderJob.SetViewport(vp) 259 self.renderJob.RenderEffect(effect) 260 261 def CopyBlitTexture(self, path, subrect = None, srcRect = None, isNormalMap = False, alphaMultiplier = 1.0): 262 effect = self._MakeEffect('Copyblit') 263 with _UpdateEffect(effect): 264 self._AppendResource(effect, 'Texture', path, 'TextureReverseUV', mapType='N' if isNormalMap else '') 265 if srcRect: 266 _AppendParameter(effect, 'SourceUVs', srcRect) 267 _AppendParameter(effect, 'AlphaMultiplier', alphaMultiplier) 268 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_ADD) 269 self._CompositeTexture(effect, subrect) 270 271 def MaskedNormalBlitTexture(self, path, strength, subrect = None, srcRect = None): 272 effect = self._MakeEffect('MaskedNormalBlit') 273 with _UpdateEffect(effect): 274 self._AppendResource(effect, 'Texture', path, 'TextureReverseUV') 275 _AppendParameter(effect, 'Strength', strength) 276 if srcRect: 277 _AppendParameter(effect, 'SourceUVs', srcRect) 278 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_ADD) 279 self._CompositeTexture(effect, subrect) 280 281 def TwistNormalBlitTexture(self, path, strength, subrect = None, srcRect = None): 282 effect = self._MakeEffect('TwistNormalBlit') 283 with _UpdateEffect(effect): 284 self._AppendResource(effect, 'Texture', path, 'TextureReverseUV') 285 _AppendParameter(effect, 'Strength', strength) 286 if srcRect: 287 _AppendParameter(effect, 'SourceUVs', srcRect) 288 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_ADD) 289 self._CompositeTexture(effect, subrect) 290 291 def SubtractAlphaFromAlpha(self, path, subrect = None, srcRect = None): 292 effect = self._MakeEffect('BlitIntoAlpha1') 293 with _UpdateEffect(effect): 294 self._AppendResource(effect, 'Texture', path, 'TextureReverseUV') 295 if srcRect: 296 _AppendParameter(effect, 'SourceUVs', srcRect) 297 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_REVSUBTRACT) 298 self._CompositeTexture(effect, subrect) 299 300 def BlitTextureIntoAlphaWithMask(self, path, mask, subrect = None, srcRect = None): 301 effect = self._MakeEffect('BlitIntoAlpha1') 302 with _UpdateEffect(effect): 303 self._AppendResource(effect, 'Texture', path, 'TextureReverseUV') 304 if srcRect: 305 _AppendParameter(effect, 'SourceUVs', srcRect) 306 effect2 = self._MakeEffect('BlitIntoAlpha2') 307 with _UpdateEffect(effect2): 308 self._AppendResource(effect2, 'Texture', path, 'TextureReverseUV') 309 self._AppendResource(effect2, 'MaskMap', mask, 'MaskReverseUV') 310 if srcRect: 311 _AppendParameter(effect2, 'SourceUVs', srcRect) 312 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_REVSUBTRACT) 313 self._CompositeTexture(effect, subrect) 314 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_ADD) 315 self._CompositeTexture(effect2, subrect) 316 317 def BlitAlphaIntoAlphaWithMask(self, path, mask, subrect = None, srcRect = None): 318 effect = self._MakeEffect('BlitIntoAlpha1') 319 with _UpdateEffect(effect): 320 self._AppendResource(effect, 'Texture', mask, 'TextureReverseUV') 321 if srcRect: 322 _AppendParameter(effect, 'SourceUVs', srcRect) 323 effect2 = self._MakeEffect('BlitIntoAlpha2') 324 with _UpdateEffect(effect2): 325 self._AppendResource(effect2, 'Texture', path, 'TextureReverseUV') 326 self._AppendResource(effect2, 'MaskMap', mask, 'MaskReverseUV') 327 if srcRect: 328 _AppendParameter(effect2, 'SourceUVs', srcRect) 329 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_REVSUBTRACT) 330 self._CompositeTexture(effect, subrect) 331 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_ADD) 332 self._CompositeTexture(effect2, subrect) 333 334 def BlitAlphaIntoAlphaWithMaskAndZones(self, path, mask, zone, values, subrect = None, srcRect = None): 335 effect = self._MakeEffect('BlitIntoAlpha1') 336 with _UpdateEffect(effect): 337 self._AppendResource(effect, 'Texture', mask, 'TextureReverseUV') 338 if srcRect: 339 _AppendParameter(effect, 'SourceUVs', srcRect) 340 effect2 = self._MakeEffect('BlitIntoAlphaWithZones') 341 with _UpdateEffect(effect2): 342 self._AppendResource(effect2, 'Texture', path, 'TextureReverseUV') 343 self._AppendResource(effect2, 'MaskMap', mask, 'MaskReverseUV') 344 self._AppendResource(effect2, 'ZoneMap', zone, 'ZoneReverseUV') 345 if srcRect: 346 _AppendParameter(effect2, 'SourceUVs', srcRect) 347 _AppendParameter(effect2, 'Color1', values) 348 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_REVSUBTRACT) 349 self._CompositeTexture(effect, subrect) 350 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_ADD) 351 self._CompositeTexture(effect2, subrect) 352 353 def BlitTexture(self, path, maskPath, weight, subrect = None, addAlpha = False, skipAlpha = False, srcRect = None, multAlpha = False, isNormalMap = False): 354 effect = self._MakeEffect('SimpleBlit') 355 with _UpdateEffect(effect): 356 self._AppendResource(effect, 'Texture', path, 'TextureReverseUV', mapType='N' if isNormalMap else '') 357 self._AppendResource(effect, 'MaskMap', maskPath, 'MaskReverseUV') 358 _AppendParameter(effect, 'Strength', weight) 359 if multAlpha: 360 _AppendParameter(effect, 'MultAlpha', 1.0) 361 if srcRect: 362 _AppendParameter(effect, 'SourceUVs', srcRect) 363 if skipAlpha: 364 self.renderJob.SetRenderState(trinity.D3DRS_SRCBLENDALPHA, trinity.TRIBLEND_ZERO) 365 else: 366 self.renderJob.SetRenderState(trinity.D3DRS_SRCBLENDALPHA, trinity.TRIBLEND_ONE) 367 if addAlpha: 368 self.renderJob.SetRenderState(trinity.D3DRS_DESTBLENDALPHA, trinity.TRIBLEND_ONE) 369 else: 370 self.renderJob.SetRenderState(trinity.D3DRS_DESTBLENDALPHA, trinity.TRIBLEND_ZERO) 371 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_ADD) 372 self._CompositeTexture(effect, subrect) 373 374 def ColorizedBlitTexture(self, detail, zone, overlay, color1, color2, color3, subrect = None, addAlpha = False, skipAlpha = False, useAlphaTest = False, srcRect = None, weight = 1.0, mask = None): 375 if useAlphaTest: 376 effect = self._MakeEffect('ColorizedBlit_AlphaTest') 377 else: 378 effect = self._MakeEffect('ColorizedBlit') 379 with _UpdateEffect(effect): 380 self._AppendResource(effect, 'DetailMap', detail, 'DetailReverseUV') 381 self._AppendResource(effect, 'ZoneMap', zone, 'ZoneReverseUV') 382 self._AppendResource(effect, 'OverlayMap', overlay, 'OverlayReverseUV') 383 if mask: 384 self._AppendResource(effect, 'MaskMap', mask, 'MaskReverseUV2') 385 _AppendParameter(effect, 'Strength', weight) 386 _AppendParameter(effect, 'Color1', color1) 387 _AppendParameter(effect, 'Color2', color2) 388 _AppendParameter(effect, 'Color3', color3) 389 if srcRect: 390 _AppendParameter(effect, 'SourceUVs', srcRect) 391 if mask: 392 _AppendParameter(effect, 'UseMask', 1.0) 393 if skipAlpha: 394 self.renderJob.SetRenderState(trinity.D3DRS_SRCBLENDALPHA, trinity.TRIBLEND_ZERO) 395 else: 396 self.renderJob.SetRenderState(trinity.D3DRS_SRCBLENDALPHA, trinity.TRIBLEND_ONE) 397 if addAlpha: 398 self.renderJob.SetRenderState(trinity.D3DRS_DESTBLENDALPHA, trinity.TRIBLEND_ONE) 399 else: 400 self.renderJob.SetRenderState(trinity.D3DRS_DESTBLENDALPHA, trinity.TRIBLEND_ZERO) 401 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_ADD) 402 self._CompositeTexture(effect, subrect) 403 404 def ColorizedCopyBlitTexture(self, detail, zone, overlay, color1, color2, color3, subrect = None, srcRect = None, weight = 1.0): 405 effect = self._MakeEffect('ColorizedCopyBlit') 406 with _UpdateEffect(effect): 407 self._AppendResource(effect, 'DetailMap', detail, 'DetailReverseUV') 408 self._AppendResource(effect, 'ZoneMap', zone, 'ZoneReverseUV') 409 self._AppendResource(effect, 'OverlayMap', overlay, 'OverlayReverseUV') 410 _AppendParameter(effect, 'Strength', weight) 411 _AppendParameter(effect, 'Color1', color1) 412 _AppendParameter(effect, 'Color2', color2) 413 _AppendParameter(effect, 'Color3', color3) 414 if srcRect: 415 _AppendParameter(effect, 'SourceUVs', srcRect) 416 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_ADD) 417 self._CompositeTexture(effect, subrect) 418 419 def PatternBlitTexture(self, pattern, detail, zone, overlay, patterncolor1, patterncolor2, patterncolor3, color2, color3, subrect = None, patternTransform = (0, 0, 8, 8), patternRotation = 0.0, addAlpha = False, skipAlpha = False, srcRect = None): 420 effect = self._MakeEffect('PatternBlit') 421 with _UpdateEffect(effect): 422 self._AppendResource(effect, 'PatternMap', pattern, 'PatternReverseUV') 423 self._AppendResource(effect, 'DetailMap', detail, 'DetailReverseUV') 424 self._AppendResource(effect, 'ZoneMap', zone, 'ZoneReverseUV') 425 self._AppendResource(effect, 'OverlayMap', overlay, 'OverlayReverseUV') 426 _AppendParameter(effect, 'PatternColor1', patterncolor1) 427 _AppendParameter(effect, 'PatternColor2', patterncolor2) 428 _AppendParameter(effect, 'PatternColor3', patterncolor3) 429 _AppendParameter(effect, 'PatternTransform', patternTransform) 430 _AppendParameter(effect, 'PatternRotation', patternRotation) 431 _AppendParameter(effect, 'Color2', color2) 432 _AppendParameter(effect, 'Color3', color3) 433 if srcRect: 434 _AppendParameter(effect, 'SourceUVs', srcRect) 435 if skipAlpha: 436 self.renderJob.SetRenderState(trinity.D3DRS_SRCBLENDALPHA, trinity.TRIBLEND_ZERO) 437 else: 438 self.renderJob.SetRenderState(trinity.D3DRS_SRCBLENDALPHA, trinity.TRIBLEND_ONE) 439 if addAlpha: 440 self.renderJob.SetRenderState(trinity.D3DRS_DESTBLENDALPHA, trinity.TRIBLEND_ONE) 441 else: 442 self.renderJob.SetRenderState(trinity.D3DRS_DESTBLENDALPHA, trinity.TRIBLEND_ZERO) 443 self.renderJob.SetRenderState(trinity.D3DRS_BLENDOPALPHA, trinity.TRIBLENDOP_ADD) 444 self._CompositeTexture(effect, subrect)