#include #include #include #include #include #include #include #include #include #include #include #include #include #include __declspec(noinline) NiTriBasedGeom* GetHeadTriBasedGeom(Actor* apActor, uint32_t aPartType) { using TGetObjectByName = NiAVObject*(BSFaceGenNiNode*, const char**, char); POINTER_SKYRIMSE(TGetObjectByName, GetObjectByName, 76207); BSFaceGenNiNode* pFaceNode = apActor->GetFaceGenNiNode(); TESNPC* pActorBase = Cast(apActor->baseForm); if (pFaceNode && pActorBase) { BGSHeadPart* pFacePart = pActorBase->GetHeadPart(aPartType); if (pFacePart) { NiAVObject* pHeadNode = GetObjectByName(pFaceNode, &pFacePart->name.data, 1); if (pHeadNode) { NiTriBasedGeom* pGeometry = pHeadNode->CastToNiTriBasedGeom(); if (pGeometry) { return pGeometry; } } } } return nullptr; } struct TextureHolder; TP_THIS_FUNCTION(TCreateResourceView, Ni2DBuffer*, TextureHolder, uint32_t, uint32_t); using TCreateTexture = NiRenderedTexture*(__fastcall)(BSFixedString& aName); using TCreateTints = void(__fastcall)(const GameArray& acTints, NiRenderedTexture* apTexture); void FaceGenSystem::Update(World& aWorld, Actor* apActor, FaceGenComponent& aFaceGenComponent) noexcept { POINTER_SKYRIMSE(NiRTTI, NiMaskedShaderRTTI, 414675); POINTER_SKYRIMSE(TCreateTexture, CreateTexture, 70717); POINTER_SKYRIMSE(TCreateResourceView, CreateResourceView, 77299); POINTER_SKYRIMSE(TCreateTints, CreateTints, 27040); POINTER_SKYRIMSE(TextureHolder, s_textureHolder, 411393); if (aFaceGenComponent.Generated) return; auto pTriBasedGeom = GetHeadTriBasedGeom(apActor, 1); if (!pTriBasedGeom) return; BSShaderProperty* pShaderProperty = niptr_cast(pTriBasedGeom->effect); if (!pShaderProperty) return; pShaderProperty->IncRef(); BSLightingShaderProperty* pLightingShader = static_cast(pShaderProperty); if (pLightingShader->GetRTTI() == NiMaskedShaderRTTI.Get()) { BSMaskedShaderMaterial* pMaterial = static_cast(pLightingShader->material); BSFixedString name(""); auto pTexture = CreateTexture(name); pTexture->buffer = CreateResourceView(s_textureHolder.Get(), 512, 512); auto& tintsEntries = aFaceGenComponent.FaceTints.Entries; GameArray tints; tints.capacity = tints.length = aFaceGenComponent.FaceTints.Entries.size() & 0xFFFFFFFF; tints.data = (TintMask**)Memory::Allocate(sizeof(TintMask*) * tints.length); for (auto i = 0u; i < tints.length; ++i) { tints[i] = Memory::New(); tints[i]->alpha = tintsEntries[i].Alpha; tints[i]->color = tintsEntries[i].Color; tints[i]->type = tintsEntries[i].Type; auto pNewTexture = Memory::New(); pNewTexture->Construct(); pNewTexture->Init(); pNewTexture->name.Set(tintsEntries[i].Name.c_str()); tints[i]->texture = pNewTexture; } CreateTints(tints, pTexture); for (auto i = 0u; i < tints.length; ++i) { tints[i]->texture->~TESTexture(); Memory::Free(tints[i]->texture); Memory::Free(tints[i]); } Memory::Free(tints.data); pMaterial->renderedTexture = pTexture; aFaceGenComponent.Generated = true; } pShaderProperty->DecRef(); } void FaceGenSystem::Setup(World& aWorld, const entt::entity aEntity, const Tints& acTints) noexcept { if (acTints.Entries.empty()) return; auto& component = aWorld.emplace_or_replace(aEntity); component.FaceTints = acTints; }