def DoBake_t(self, projectedDecalModifier):
        while self.doingDecal or self.doingAvatar:
            PD.Yield()

        self.bakeScene = trinity.WodBakingScene()
        self.bakeScene.Avatar = self.__avatar
        if projectedDecalModifier.decalData.bodyEnabled:
            while not projectedDecalModifier.mapD[pdDef.DOLL_PARTS.BODY].isPrepared:
                PD.Yield(frameNice=False)

            bodyTex = projectedDecalModifier.mapD[pdDef.DOLL_PARTS.BODY]
            self._Bake(bodyTex, (0.0, 0.0, 2.0, 1.0))
            self._ExpandOpaque(pdDef.DOLL_PARTS.BODY, bodyTex)
        elif projectedDecalModifier.mapD.get(pdDef.DOLL_PARTS.BODY):
            del projectedDecalModifier.mapD[pdDef.DOLL_PARTS.BODY]
        if projectedDecalModifier.decalData.headEnabled:
            while not projectedDecalModifier.mapD[pdDef.DOLL_PARTS.HEAD].isPrepared:
                PD.Yield(frameNice=False)

            headTex = projectedDecalModifier.mapD[pdDef.DOLL_PARTS.HEAD]
            self._Bake(headTex, (-0.5, 0.0, 2.0, 2.0))
            self._ExpandOpaque(pdDef.DOLL_PARTS.HEAD, headTex)
        elif projectedDecalModifier.mapD.get(pdDef.DOLL_PARTS.HEAD):
            del projectedDecalModifier.mapD[pdDef.DOLL_PARTS.HEAD]
        self.bakeScene = None
        self.isReady = True
    def SetupStubble(meshes, name, stubblePath, adding = True):
        ret = []
        stubbleName = '{0}Stubble'.format(name)
        stubbleMeshes = (mesh for mesh in meshes if mesh.name.startswith(pdDef.DOLL_PARTS.HEAD))
        for mesh in stubbleMeshes:
            if adding:
                if any(map(lambda x: 'stubble' in x.name.lower(), mesh.decalAreas)):
                    ret.append(mesh)
                    continue
                c_skin_areas = (area for area in mesh.opaqueAreas if area.effect.name.lower().startswith('c_skin_'))
                for area in c_skin_areas:
                    stubbleArea = trinity.Tr2MeshArea()
                    stubbleArea.name = stubbleName
                    stubbleArea.index = area.index
                    stubbleArea.count = area.count
                    stubbleArea.effect = trinity.Load(stubblePath)
                    for resource in stubbleArea.effect.resources:
                        if resource.name == 'LengthTexture':
                            while resource.resource.IsLoading():
                                pdCf.Yield()

                    mesh.decalAreas.append(stubbleArea)
                    ret.append(mesh)
                    if SkinSpotLightShadows.instance:
                        SkinSpotLightShadows.instance.CreateEffectParamsForMesh(mesh, False)
                    for instance in SkinLightmapRenderer.instances:
                        if instance():
                            instance().BindLightmapShader(mesh)

            else:
                targetAreasToRemove = [ area for area in mesh.decalAreas if area.name == stubbleName ]
                for ta in targetAreasToRemove:
                    mesh.decalAreas.remove(ta)

        return ret
    def SetShader_t(self, avatar, targetsToIgnore, shaderres, allTargets = False):
        try:
            effect = trinity.Tr2Effect()
            effect.effectFilePath = shaderres
            while effect.effectResource.isLoading:
                PD.Yield()

            for mesh in avatar.visualModel.meshes:
                areasList = [mesh.opaqueAreas, mesh.decalAreas, mesh.transparentAreas]
                if allTargets or mesh.name not in targetsToIgnore:
                    for areas in areasList:
                        for area in areas:
                            transformUV = None
                            for p in area.effect.parameters:
                                if p.name == 'TransformUV0':
                                    transformUV = p.value
                                    break

                            area.effect.effectFilePath = shaderres
                            area.effect.PopulateParameters()
                            area.effect.RebuildCachedData()
                            for p in area.effect.parameters:
                                if p.name == 'TransformUV0':
                                    p.value = transformUV
                                    break

        except TaskletExit:
            raise
    def BakeDecalToModifier(self, decal, projectedDecalModifier):
        """
        Pre: 
            Decal is an instance of ProjectedDecal
            Avatar has been created for baking
            
        Post:
            projectedDecalModifier.decalData contains the given decal and diffuse maps on the modifier
            contain textures for body and head.
        
        Summary: Bakes out the decal using currently set avatar, the targets for outputted textures are 
        the diffuse maps for body and head in the modifier.
        """
        while self.doingAvatar:
            PD.Yield(frameNice=False)

        if type(self.__avatar) is not trinity.Tr2IntSkinnedObject:
            raise TypeError('DecalBaker::DoPrepare - Avatar is not set!')
        if type(decal) is not ProjectedDecal:
            raise TypeError('DecalBaker::BakeDecalToModifier - decal is not an instance of PaperDoll::ProjectedDecal!')
        self.isReady = False
        self.doingDecal = False
        if projectedDecalModifier.decalData != decal:
            projectedDecalModifier.decalData = decal

        def PrepareDecal_t():
            self.doingDecal = True
            self.SetDecal_t(self.__avatar, decal, True, True)
            self.doingDecal = False

        self.decalSettingTasklet = uthread.new(PrepareDecal_t)
        self.CreateTargetsOnModifier(projectedDecalModifier)
        self.bakingTasklet = uthread.new(self.DoBake_t, projectedDecalModifier)
Exemplo n.º 5
0
    def PreloadEffect(path):
        effect = trinity.Tr2Effect()
        effect.effectFilePath = path
        while effect.effectResource.isLoading:
            pdCf.Yield()

        effect.RebuildCachedData()
        return effect
Exemplo n.º 6
0
    def PreloadEffect(path):
        """
        Helper for preloading effect: create it, wait on blue, rebuild it.
        """
        effect = trinity.Tr2Effect()
        effect.effectFilePath = path
        while effect.effectResource.isLoading:
            pdCf.Yield()

        effect.RebuildCachedData()
        return effect
Exemplo n.º 7
0
    def LoadFromRes(self, resPath):
        """
        Loads the doll from the given resPath and applies it to its avatar if it has one.
        """
        self.doll = pdImpl.Doll(PaperDollCharacter.__DEFAULT_NAME)
        while not self.factory.IsLoaded:
            pdCf.Yield()

        self.doll.Load(resPath, self.factory)
        if self.avatar:
            self.doll.Update(self.factory, self.avatar)
    def BindHeroClothShader(effect, useDXT5n):
        path = effect.effectFilePath.lower()
        if 'clothavatar' not in path or 'clothavatarhair' in path:
            return
        suffix = '_dxt5n.fx' if useDXT5n else '.fx'
        effect.effectFilePath = ApplySuffix('res:/Graphics/Effect/Managed/Interior/Avatar/ClothAvatarLinear', suffix)
        while effect.effectResource.isLoading:
            pdCf.Yield()

        effect.PopulateParameters()
        PortraitTools.TweakDiffuseSampler(effect)
    def _ExpandOpaque(self, bodyPart, targetTex):
        """
        Using pre-generated masks, we bleed the opaque accross the edges defined by said masks.
        This reduces visible seams when the tattoos have been projected in object space so that 
        their pixels in UV space aren't continuous.
        """
        eoMaskPath = 'res:/graphics/character/global/tattoomask/{0}_opaque_mask_{1}.dds'.format(self._gender, bodyPart)
        eoMaskRes = blue.resMan.GetResource(eoMaskPath)
        fx = trinity.Tr2Effect()
        fx.effectFilePath = EO_SHADERRES
        while eoMaskRes.isLoading or fx.effectResource.isLoading:
            PD.Yield()

        tex = trinity.TriTexture2DParameter()
        tex.name = 'Mask'
        tex.SetResource(eoMaskRes)
        fx.resources.append(tex)
        v = trinity.Tr2Vector2Parameter()
        v.name = 'gMaskSize'
        v.value = (eoMaskRes.width, eoMaskRes.height)
        fx.parameters.append(v)
        tex = trinity.TriTexture2DParameter()
        tex.name = 'Texture'
        tex.SetResource(targetTex)
        fx.resources.append(tex)
        v = trinity.Tr2Vector2Parameter()
        v.name = 'gTextureSize'
        v.value = (targetTex.width, targetTex.height)
        fx.parameters.append(v)
        fx.RebuildCachedData()
        vp = trinity.TriViewport()
        vp.width = targetTex.width
        vp.height = targetTex.height
        expandedRT = trinity.Tr2RenderTarget(vp.width, vp.height, 1, trinity.PIXEL_FORMAT.B8G8R8A8_UNORM)
        rj = trinity.CreateRenderJob('Expanding Opaque')
        rj.PushRenderTarget(expandedRT)
        rj.SetProjection(trinity.TriProjection())
        rj.SetView(trinity.TriView())
        rj.SetViewport(vp)
        rj.PushDepthStencil(None)
        rj.Clear((0.0, 0.0, 0.0, 0.0))
        rj.SetStdRndStates(trinity.RM_FULLSCREEN)
        rj.SetRenderState(trinity.D3DRS_SEPARATEALPHABLENDENABLE, 1)
        rj.SetRenderState(trinity.D3DRS_SRCBLENDALPHA, trinity.TRIBLEND_ONE)
        rj.SetRenderState(trinity.D3DRS_DESTBLENDALPHA, trinity.TRIBLEND_ZERO)
        rj.RenderEffect(fx)
        rj.SetRenderTarget(targetTex.wrappedRenderTarget)
        rj.RenderTexture(expandedRT)
        rj.PopRenderTarget()
        rj.PopDepthStencil()
        rj.ScheduleChained()
        rj.WaitForFinish()
Exemplo n.º 10
0
    def ActOnRandomModifier(self, fun, candidates):
        limit = len(candidates)
        if limit > 0:
            ridx = random.randint(0, limit) - 1
            modifier = candidates[ridx]
            fun(modifier)
            print 'Modifier chosen is %s' % modifier.name
            self.pdc.doll.Update(self.pdc.factory, self.pdc.avatar)
            while self.pdc.doll.busyUpdating:
                pdCf.Yield()

        else:
            raise Exception('Candidates are empty!')
    def BindHeroHairShader(effect, suffix):
        path = effect.effectFilePath.lower()
        if path.find('hair') == -1:
            return False
        if path.find('clothavatarhair') != -1:
            effect.effectFilePath = ApplySuffix('res:/Graphics/Effect/Managed/Interior/Avatar/clothavatarhair_detailed', suffix)
        else:
            effect.effectFilePath = ApplySuffix('res:/Graphics/Effect/Managed/Interior/Avatar/skinnedavatarhair_detailed', suffix)
        while effect.effectResource.isLoading:
            pdCf.Yield()

        name = effect.name.lower()
        effect.PopulateParameters()
        pdCcf.SetOrAddMap(effect, 'HairNoise', 'res:/Texture/Global/noise1d.dds')
        pdCcf.SetOrAddMap(effect, 'TangentMap', 'res:/Texture/Global/50gray.dds' if not name.startswith('c_hair_head') else 'res:/Texture/Global/HeadTangents.dds')
        PortraitTools.TweakDiffuseSampler(effect)
        return True
    def BindHeroShader(effect, isOptimized, suffix):
        if not isOptimized:
            effect.effectFilePath = 'res:/Graphics/Effect/Managed/Interior/Avatar/skinnedavatarbrdf_detailed' + suffix
        else:
            effect.effectFilePath = 'res:/Graphics/Effect/Managed/Interior/Avatar/avatarbrdfcombined_detailed' + suffix
        while effect.effectResource.isLoading:
            pdCf.Yield()

        effect.PopulateParameters()
        for res in effect.resources:
            if res.name == 'NormalDetailMap':
                res.resourcePath = 'res:/Texture/Global/NormalNoise_N.dds'
                break

        for par in effect.parameters:
            if par.name == 'NormalDetailStrength':
                par.value = 0.25
            if par.name == 'NormalDetailTiling':
                par.value = 50.0
    def SetDecal_t(self, avatar, decal, setTexture, setMask):
        """
        Sets decal texture and mask map defined in 'decal' to all meshes in the avatar,
        except for the meshes that have their names in 'ignoreTargets'
        
        Precondition: The effect _must_ have loaded prior to calling this function.        
        """
        if decal is None:
            return
        while self.doingAvatar or decal.BusyLoading():
            PD.Yield(frameNice=False)

        for mesh in iter(avatar.visualModel.meshes):
            for effect in pdCcF.GetEffectsFromMesh(mesh):
                effect.StartUpdate()
                for p in effect.parameters:
                    valuesToSet = None
                    if p.name == 'TattooYawPitchRoll':
                        valuesToSet = decal.GetYPR()
                    elif p.name == 'TattooPosition':
                        valuesToSet = decal.GetPositionAndScale()
                    elif p.name == 'TattooOptions':
                        valuesToSet = decal.GetOptions()
                    elif p.name == 'TattooDimensions':
                        valuesToSet = decal.GetDimensions()
                    elif p.name == 'TattooAspectRatio' and hasattr(decal, 'aspectRatio'):
                        valuesToSet = decal.aspectRatio
                    elif p.name == 'TattooPickingLayer':
                        valuesToSet = decal.layer
                    if type(valuesToSet) == tuple:
                        valLen = len(valuesToSet)
                        if valLen < len(p.value):
                            valuesToSet = valuesToSet + p.value[valLen:]
                    if valuesToSet:
                        p.value = valuesToSet

                resourceNameFound = False
                if setTexture:
                    resourceNameFound = self.SetTexture_t('TattooTextureMap', decal.textureResource, effect)
                if setMask and resourceNameFound:
                    resourceNameFound = self.SetTexture_t('TattooTextureMask', decal.maskResource, effect)
                effect.RebuildCachedData()
                effect.EndUpdate()
Exemplo n.º 14
0
    def BakeDecalToModifier(self, decal, projectedDecalModifier):
        while self.doingAvatar:
            PD.Yield(frameNice=False)

        if type(self.__avatar) is not trinity.Tr2IntSkinnedObject:
            raise TypeError('DecalBaker::DoPrepare - Avatar is not set!')
        if type(decal) is not ProjectedDecal:
            raise TypeError('DecalBaker::BakeDecalToModifier - decal is not an instance of PaperDoll::ProjectedDecal!')
        self.isReady = False
        self.doingDecal = False
        if projectedDecalModifier.decalData != decal:
            projectedDecalModifier.decalData = decal

        def PrepareDecal_t():
            self.doingDecal = True
            self.SetDecal_t(self.__avatar, decal, True, True)
            self.doingDecal = False

        self.decalSettingTasklet = uthread.new(PrepareDecal_t)
        self.CreateTargetsOnModifier(projectedDecalModifier)
        self.bakingTasklet = uthread.new(self.DoBake_t, projectedDecalModifier)
Exemplo n.º 15
0
    def SetDecal_t(self, avatar, decal, setTexture, setMask):
        if decal is None:
            return
        while self.doingAvatar or decal.BusyLoading():
            PD.Yield(frameNice=False)

        for mesh in iter(avatar.visualModel.meshes):
            for effect in pdCcF.GetEffectsFromMesh(mesh):
                effect.StartUpdate()
                for p in effect.parameters:
                    valuesToSet = None
                    if p.name == 'TattooYawPitchRoll':
                        valuesToSet = decal.GetYPR()
                    elif p.name == 'TattooPosition':
                        valuesToSet = decal.GetPositionAndScale()
                    elif p.name == 'TattooOptions':
                        valuesToSet = decal.GetOptions()
                    elif p.name == 'TattooDimensions':
                        valuesToSet = decal.GetDimensions()
                    elif p.name == 'TattooAspectRatio' and hasattr(decal, 'aspectRatio'):
                        valuesToSet = decal.aspectRatio
                    elif p.name == 'TattooPickingLayer':
                        valuesToSet = decal.layer
                    if type(valuesToSet) == tuple:
                        valLen = len(valuesToSet)
                        if valLen < len(p.value):
                            valuesToSet = valuesToSet + p.value[valLen:]
                    if valuesToSet:
                        p.value = valuesToSet

                resourceNameFound = False
                if setTexture:
                    resourceNameFound = self.SetTexture_t('TattooTextureMap', decal.textureResource, effect)
                if setMask and resourceNameFound:
                    resourceNameFound = self.SetTexture_t('TattooTextureMask', decal.maskResource, effect)
                effect.RebuildCachedData()
                effect.EndUpdate()
Exemplo n.º 16
0
    def SetupFloorDropShadow(scene, doYield = True):
        if scene is None or SkinSpotLightShadows.instance is None:
            return

        def SetupCurve(effect):
            doll = scene.dynamics[0]
            if doll is None:
                return
            setName = 'Dropshadow foot tracker'
            set = None
            for s in doll.curveSets:
                if s.name == setName:
                    set = s
                    set.curves.removeAt(-1)
                    set.bindings.removeAt(-1)
                    break
            else:
                set = trinity.TriCurveSet()
                set.name = setName
                doll.curveSets.append(set)

            bones = ['LeftFoot', 'RightFoot']
            for bone in bones:
                curve = trinity.Tr2BoneMatrixCurve()
                curve.skinnedObject = doll
                curve.bone = bone
                curve.name = bone
                param = pdCcf.FindOrAddVec4(effect, bone)
                bind = trinity.TriValueBinding()
                bind.destinationObject = param
                bind.destinationAttribute = 'value'
                bind.sourceObject = curve
                bind.sourceAttribute = 'currentValue'
                bind.name = bone
                set.curves.append(curve)
                set.bindings.append(bind)

            set.Play()

        lights = scene.lights
        frontMainLightIndex = 0
        for light in lights:
            if light.name == 'FrontMain':
                frontMainLightIndex = lights.index(light)
                break

        values = [(1, 0, 0, 0),
         (0, 1, 0, 0),
         (0, 0, 1, 0),
         (0, 0, 0, 1)]
        for cell in scene.cells:
            for static in cell.statics:
                if SkinSpotLightShadows.instance is not None:
                    SkinSpotLightShadows.instance.CreateEffectParamsForMesh(static, isClothMesh=False)
                for area in static.enlightenAreas:
                    area.effect.effectFilePath = 'res:/Graphics/Effect/Managed/Interior/Avatar/PortraitDropShadow.fx'
                    if doYield:
                        while area.effect.effectResource.isLoading:
                            pdCf.Yield()

                    SetupCurve(area.effect)
                    area.effect.RebuildCachedData()
                    if frontMainLightIndex < len(values):
                        p = pdCcf.FindOrAddVec4(area.effect, 'ShadowSelector')
                        p.value = values[frontMainLightIndex]
Exemplo n.º 17
0
 def WaitForUpdate(self):
     """
     Wait until the doll Update has finished.
     """
     while self.doll.busyUpdating:
         pdCf.Yield()
    def BindSkinShader(effect, wrinkleFx, scattering, buildDataManager, gender, use_png, fxSuffix):
        name = effect.name.lower()
        path = effect.effectFilePath.lower()
        if name.startswith('c_skin'):
            wasDouble = 'double' in path
            fxPath = pdDef.SKINNED_AVATAR_SINGLEPASS_DOUBLE_PATH if wasDouble else pdDef.SKINNED_AVATAR_SINGLEPASS_SINGLE_PATH
            effect.effectFilePath = ApplySuffix(fxPath[:-3], fxSuffix)
            while effect.effectResource.isLoading:
                pdCf.Yield()

            effect.PopulateParameters()
            pdCcf.SetOrAddMap(effect, 'BeckmannLookup', 'res:/Texture/Global/beckmannSpecular.dds')
            PortraitTools.TweakDiffuseSampler(effect)
            suffix = 'tga'
            if use_png and not legacy_r_drive.loadFromContent:
                suffix = 'png'
            headMods = buildDataManager.GetModifiersByCategory(pdDef.DOLL_PARTS.HEAD)
            if pdDef.GENDER_ROOT:
                if gender == pdDef.GENDER.FEMALE:
                    headFolderGeneric = 'res:/Graphics/Character/Female/Paperdoll/head/Head_Generic'
                else:
                    headFolderGeneric = 'res:/Graphics/Character/Male/Paperdoll/head/Head_Generic'
            elif gender == pdDef.GENDER.FEMALE:
                headFolderGeneric = 'res:/Graphics/Character/Modular/Female/head/Head_Generic'
            else:
                headFolderGeneric = 'res:/Graphics/Character/Modular/Male/head/Head_Generic'
            headFolder = headFolderGeneric
            for hm in headMods:
                headFolder = os.path.dirname(hm.redfile)

            if scattering:
                if headFolder != '' and blue.paths.exists(headFolder + '/SkinMap.' + suffix):
                    pdCcf.SetOrAddMap(effect, 'SkinMap', headFolder + '/SkinMap.' + suffix)
                else:
                    pdCcf.SetOrAddMap(effect, 'SkinMap', headFolderGeneric + '/SkinMap.' + suffix)
            if wrinkleFx is not None:
                pdCcf.SetOrAddMap(effect, 'WrinkleZoneMap', pdDef.FEMALE_WRINKLE_FACEZONE_PREFIX + suffix)
                if headFolder != '' and blue.paths.exists(headFolder + '/WrinkleNormal.' + suffix):
                    pdCcf.SetOrAddMap(effect, 'WrinkleNormalMap', headFolder + '/WrinkleNormal.' + suffix)
                else:
                    pdCcf.SetOrAddMap(effect, 'WrinkleNormalMap', headFolderGeneric + '/WrinkleNormal.' + suffix)
                if headFolder != '' and blue.paths.exists(headFolder + '/WrinkleNormalCorrection.' + suffix):
                    pdCcf.SetOrAddMap(effect, 'WrinkleNormalCorrectionMap', headFolder + '/WrinkleNormalCorrection.' + suffix)
                else:
                    pdCcf.SetOrAddMap(effect, 'WrinkleNormalCorrectionMap', headFolderGeneric + '/WrinkleNormalCorrection.' + suffix)
                if headFolder != '' and blue.paths.exists(headFolder + '/WrinkleDiffuse.' + suffix):
                    pdCcf.SetOrAddMap(effect, 'WrinkleDiffuseMap', headFolder + '/WrinkleDiffuse.' + suffix)
                else:
                    pdCcf.SetOrAddMap(effect, 'WrinkleDiffuseMap', headFolderGeneric + '/WrinkleDiffuse.' + suffix)
                wrinkleFx.append(effect)
        elif name.startswith('c_standard'):

            def AddClothingCube(effect):
                for res in effect.resources:
                    if res.name == 'ClothingReflectionCube':
                        return

                res = trinity.TriTextureCubeParameter()
                res.name = 'ClothingReflectionCube'
                res.resourcePath = 'res:/Texture/Global/GenericReflection_cube.dds'
                effect.resources.append(res)

            AddClothingCube(effect)
        elif name.startswith('c_eyewetness'):
            effect.effectFilePath = ApplySuffix(pdDef.SKINNED_AVATAR_EYEWETNESS_SHADER[:-3], fxSuffix)
        elif name.startswith('c_tongue'):
            effect.effectFilePath = ApplySuffix(pdDef.SKINNED_AVATAR_TONGUE_SHADER[:-3], fxSuffix)
        elif name.startswith('c_teeth'):
            effect.effectFilePath = ApplySuffix(pdDef.SKINNED_AVATAR_TEETH_SHADER[:-3], fxSuffix)
        elif name.startswith('c_eyes'):
            effect.effectFilePath = ApplySuffix(pdDef.SKINNED_AVATAR_EYE_SHADER[:-3], fxSuffix)

            def AddEyeCube(effect):
                for res in effect.resources:
                    if res.name == 'EyeReflectionCube':
                        return

                res = trinity.TriTextureCubeParameter()
                res.name = 'EyeReflectionCube'
                res.resourcePath = pdDef.EYE_SHADER_REFLECTION_CUBE_PATH
                effect.resources.append(res)

            AddEyeCube(effect)
    def SetupFloorDropShadow(scene, doYield = True):
        """
        Very specialized function for something very specific to portrait mode: take over the meshes
        in the scene, which should just be a floor, and hook up a shader that will blend a dropshadow.
        That shader needs to know the location of the doll(-feet), so there is also some curve binding.
        Call this after the doll has been created for the first time.
        """
        if scene is None or SkinSpotLightShadows.instance is None:
            return

        def SetupCurve(effect):
            """
            Find the bones for the foot, and set up a curve binding that will send their positions to
            effect parameters.
            """
            doll = scene.dynamics[0]
            if doll is None:
                return
            setName = 'Dropshadow foot tracker'
            set = None
            for s in doll.curveSets:
                if s.name == setName:
                    set = s
                    set.curves.removeAt(-1)
                    set.bindings.removeAt(-1)
                    break
            else:
                set = trinity.TriCurveSet()
                set.name = setName
                doll.curveSets.append(set)

            bones = ['LeftFoot', 'RightFoot']
            for bone in bones:
                curve = trinity.Tr2BoneMatrixCurve()
                curve.skinnedObject = doll
                curve.bone = bone
                curve.name = bone
                param = pdCcf.FindOrAddVec4(effect, bone)
                bind = trinity.TriValueBinding()
                bind.destinationObject = param
                bind.destinationAttribute = 'value'
                bind.sourceObject = curve
                bind.sourceAttribute = 'currentValue'
                bind.name = bone
                set.curves.append(curve)
                set.bindings.append(bind)

            set.Play()

        lights = scene.lights
        frontMainLightIndex = 0
        for light in lights:
            if light.name == 'FrontMain':
                frontMainLightIndex = lights.index(light)
                break

        values = [(1, 0, 0, 0),
         (0, 1, 0, 0),
         (0, 0, 1, 0),
         (0, 0, 0, 1)]
        for cell in scene.cells:
            for system in cell.systems:
                for static in system.statics:
                    if SkinSpotLightShadows.instance is not None:
                        SkinSpotLightShadows.instance.CreateEffectParamsForMesh(static, isClothMesh=False)
                    for area in static.enlightenAreas:
                        area.effect.effectFilePath = 'res:/Graphics/Effect/Managed/Interior/Avatar/PortraitDropShadow.fx'
                        if doYield:
                            while area.effect.effectResource.isLoading:
                                pdCf.Yield()

                        SetupCurve(area.effect)
                        area.effect.RebuildCachedData()
                        if frontMainLightIndex < len(values):
                            p = pdCcf.FindOrAddVec4(area.effect, 'ShadowSelector')
                            p.value = values[frontMainLightIndex]
    def CreateRenderJobsForLight(self, light):
        """
        Create a renderjob to render out the shadow map for this light, and blur
        it for VSM; optionally also show it on the screen for debugging.
        """
        self.lights.append(light)
        if not SkinSpotLightShadows.REUSE_ENGINE_MAPS:
            light.shadowCasterTypes = 0
        else:
            light.shadowResolution = 1024
        ignoreLight = False
        if self.lightFilter is not None and light.name not in self.lightFilter:
            ignoreLight = True
        elif len(self.lights) > SkinSpotLightShadows.MAX_LIGHTS or light.coneAlphaOuter > 89:
            ignoreLight = True
        if ignoreLight:
            light.importanceScale = 0
            light.importanceBias = -9999
            light.shadowCasterTypes = 0
            return
        light.importanceScale = 0
        light.importanceBias = -len(self.lights)
        if SkinSpotLightShadows.REUSE_ENGINE_MAPS:
            self.RTs[light] = light.GetShadowTextureRes()
            rj = trinity.CreateRenderJob('render shadowmap ' + str(light))
            self.jobs[light] = [rj]
            cb = trinity.TriStepPythonCB()
            cb.name = 'UpdateViewProjForLight'
            cb.SetCallback(lambda : self.UpdateViewProjForLight(None, None, light, None))
            rj.steps.append(cb)
            rj.ScheduleRecurring()
            return
        rj = trinity.CreateRenderJob('render shadowmap ' + str(light))
        renderTarget = None
        while self.width > 8:
            renderTarget = trinity.Tr2RenderTarget(self.width, self.height, 1, self.format)
            if renderTarget is None or not renderTarget.isValid:
                renderTarget = None
                self.width /= 2
                self.height /= 2
                pdCf.Yield()
            else:
                break

        self.RTs[light] = renderTarget
        depthStencil = None
        while self.width > 8:
            depthStencil = trinity.Tr2DepthStencil(self.width, self.height, trinity.DEPTH_STENCIL_FORMAT.D24S8)
            if depthStencil is None or not depthStencil.isValid:
                depthStencil = None
                self.width /= 2
                self.height /= 2
                pdCf.Yield()
            else:
                break

        if not renderTarget or not depthStencil or not renderTarget.isValid or not depthStencil.isValid:
            return
        v = None
        rj.PushViewport()
        rj.PushRenderTarget(renderTarget)
        rj.PushDepthStencil(depthStencil)
        clearColor = (100.0, 1.0, 1.0, 1.0)
        rj.Clear(clearColor, 1.0)
        vp = trinity.TriViewport()
        vp.x = 0
        vp.y = 0
        vp.width = self.width
        vp.height = self.height
        rj.PushProjection()
        rj.PushViewTransform()
        rj.SetViewport(vp)
        cb = trinity.TriStepPythonCB()
        cb.name = 'UpdateViewProjForLight'
        rj.steps.append(cb)
        stepProj = rj.SetProjection(trinity.TriProjection())
        stepView = rj.SetView(trinity.TriView())
        self.UpdateViewProjForLight(stepView, stepProj, light, v)
        cb.SetCallback(lambda : self.UpdateViewProjForLight(stepView, stepProj, light, v))

        def applyVisualizer(doIt):
            for meshData in self.meshes.itervalues():
                if doIt:
                    meshData.applyShadowEffect()
                else:
                    meshData.applyOriginalEffect()

        cb = trinity.TriStepPythonCB()
        cb.name = 'applyVisualizer(True)'
        cb.SetCallback(lambda : applyVisualizer(True))
        rj.steps.append(cb)
        rj.RenderScene(self.scene)
        cb = trinity.TriStepPythonCB()
        cb.name = 'applyVisualizer(False)'
        cb.SetCallback(lambda : applyVisualizer(False))
        rj.steps.append(cb)
        rj.PopDepthStencil()
        rj.PopRenderTarget()
        rj.PopViewTransform().name = 'TriStepPopViewTransform Restoring state'
        rj.PopViewport()
        rj.PopProjection()
        if SkinSpotLightShadows.renderJob is not None and SkinSpotLightShadows.renderJob.object is not None:
            step = trinity.TriStepRunJob()
            step.job = rj
            SkinSpotLightShadows.renderJob.object.steps.insert(0, step)
        else:
            self.jobs[light] = [rj]
            rj.ScheduleRecurring(insertFront=True)
        if self.debugVisualize:
            rj2 = trinity.CreateRenderJob('visualize shadowmap ' + str(light))
            if light not in self.jobs:
                self.jobs[light] = [rj2]
            else:
                self.jobs[light].append(rj2)
            rj2.PushDepthStencil(None)
            size = 200
            vp2 = trinity.TriViewport()
            vp2.x = 10
            vp2.y = 10 + (size + 10) * (len(self.lights) - 1)
            vp2.width = size
            vp2.height = size
            rj2.PushViewport()
            rj2.PushProjection()
            rj2.PushViewTransform()
            rj2.SetViewport(vp2)
            rj2.SetStdRndStates(trinity.RM_FULLSCREEN)
            rj2.RenderTexture(renderTarget)
            rj2.PopViewTransform()
            rj2.PopProjection()
            rj2.PopViewport()
            rj2.PopDepthStencil()
            rj2.ScheduleRecurring()