From 4bfb12c2696ea8b9ba197711350d95282c754100 Mon Sep 17 00:00:00 2001 From: expired6978 Date: Wed, 29 Aug 2018 20:17:28 -0700 Subject: [PATCH] Updated to 1.5.50 --- hudextension/main.cpp | 6 +- skee/BodyMorphInterface.cpp | 383 +++++++++++++++++------------------- skee/BodyMorphInterface.h | 36 +++- skee/SKEEHooks.cpp | 52 ++--- skee/main.cpp | 4 +- 5 files changed, 235 insertions(+), 246 deletions(-) diff --git a/hudextension/main.cpp b/hudextension/main.cpp index 86c59cd..d8af46f 100644 --- a/hudextension/main.cpp +++ b/hudextension/main.cpp @@ -115,9 +115,9 @@ bool RegisterScaleform(GFxMovieView * view, GFxValue * root) return true; } -RelocAddr HUDMenu_Hook_Target(0x0087D280 + 0x5D8); +RelocAddr HUDMenu_Hook_Target(0x0087CFC0 + 0x5D8); typedef void(*_HUDMenu_RegisterMarkers)(GFxValue * value); -RelocAddr<_HUDMenu_RegisterMarkers> HUDMenu_RegisterMarkers(0x008838E0); +RelocAddr<_HUDMenu_RegisterMarkers> HUDMenu_RegisterMarkers(0x00883620); void HUDMenu_RegisterMarkers_Hook(GFxValue * value, HUDMenu * menu) { @@ -156,7 +156,7 @@ bool SKSEPlugin_Query(const SKSEInterface * skse, PluginInfo * info) _MESSAGE("loaded in editor, marking as incompatible"); return false; } - else if(skse->runtimeVersion != RUNTIME_VERSION_1_5_39) + else if(skse->runtimeVersion != RUNTIME_VERSION_1_5_50) { _MESSAGE("unsupported runtime version %08X", skse->runtimeVersion); return false; diff --git a/skee/BodyMorphInterface.cpp b/skee/BodyMorphInterface.cpp index 6bbc6fe..6c6846d 100644 --- a/skee/BodyMorphInterface.cpp +++ b/skee/BodyMorphInterface.cpp @@ -277,122 +277,132 @@ bool BodyMorphInterface::HasMorphs(TESObjectREFR * actor) return false; } -void TriShapeFullVertexData::ApplyMorph(UInt16 vertCount, void * data, float factor) +void TriShapeFullVertexData::ApplyMorphRaw(UInt16 vertCount, void * data, float factor) { NiPoint3 * vertices = static_cast(data); if (!vertices) return; - if (g_parallelMorphing) + if (m_maxIndex < vertCount) { - concurrency::parallel_for_each(m_vertexDeltas.begin(), m_vertexDeltas.end(), [&](const TriShapeVertexDelta & vert) + for (const auto & vert : m_vertexDeltas) { - const UInt16 vertexIndex = vert.index; - const NiPoint3 * vertexDiff = &vert.diff; - if (vertexIndex < vertCount) - { - vertices[vertexIndex].x += vertexDiff->x * factor; - vertices[vertexIndex].y += vertexDiff->y * factor; - vertices[vertexIndex].z += vertexDiff->z * factor; - } - }, concurrency::static_partitioner()); + UInt16 vertexIndex = vert.index; + const DirectX::XMVECTOR * vertexDiff = &vert.delta; + + vertices[vertexIndex].x += vertexDiff->m128_f32[0] * factor; + vertices[vertexIndex].y += vertexDiff->m128_f32[1] * factor; + vertices[vertexIndex].z += vertexDiff->m128_f32[2] * factor; + + } } else { - UInt32 size = m_vertexDeltas.size(); - for (UInt32 i = 0; i < size; i++) + _ERROR("%s - Failed to apply morphs to geometry - morphs largest index is %d mesh vertex size is %d", __FUNCTION__, m_maxIndex, (UInt32)vertCount); + } +} + +void TriShapeFullVertexData::ApplyMorph(UInt16 vertexCount, NiSkinPartition::TriShape * vertexData, float factor) +{ + UInt32 offset = NiSkinPartition::GetVertexAttributeOffset(vertexData->m_VertexDesc, VertexAttribute::VA_POSITION); + UInt32 vertexSize = NiSkinPartition::GetVertexSize(vertexData->m_VertexDesc); + + if (m_maxIndex < vertexCount) + { + for (const auto & vert : m_vertexDeltas) { - TriShapeVertexDelta * vert = &m_vertexDeltas.at(i); - UInt16 vertexIndex = vert->index; - NiPoint3 * vertexDiff = &vert->diff; - if (vertexIndex < vertCount) - { - vertices[vertexIndex].x += vertexDiff->x * factor; - vertices[vertexIndex].y += vertexDiff->y * factor; - vertices[vertexIndex].z += vertexDiff->z * factor; - } - else { - _DMESSAGE("%s - Vertex %d out of bounds X:%f Y:%f Z:%f", __FUNCTION__, vertexIndex, vertexDiff->x, vertexDiff->y, vertexDiff->z); - } + DirectX::XMFLOAT4 * position = reinterpret_cast(&vertexData->m_RawVertexData[vertexSize * vert.index + offset]); + DirectX::XMStoreFloat4(position, DirectX::XMVectorAdd(DirectX::XMLoadFloat4(position), DirectX::XMVectorScale(vert.delta, factor))); } } + else + { + _ERROR("%s - Failed to apply morphs to geometry - morphs largest index is %d mesh vertex size is %d", __FUNCTION__, m_maxIndex, (UInt32)vertexCount); + } } -void TriShapePackedVertexData::ApplyMorph(UInt16 vertCount, void * data, float factor) +void TriShapePackedVertexData::ApplyMorphRaw(UInt16 vertCount, void * data, float factor) { NiPoint3 * vertices = static_cast(data); if (!vertices) return; - if (g_parallelMorphing) + if (m_maxIndex < vertCount) { - concurrency::parallel_for_each(m_vertexDeltas.begin(), m_vertexDeltas.end(), [&](const TriShapePackedVertexDelta & vert) + for (const auto & vert : m_vertexDeltas) { - UInt16 vertexIndex = vert.index; - if (vertexIndex < vertCount) - { - vertices[vertexIndex].x += (float)vert.x * m_multiplier * factor; - vertices[vertexIndex].y += (float)vert.y * m_multiplier * factor; - vertices[vertexIndex].z += (float)vert.z * m_multiplier * factor; - } - }, concurrency::static_partitioner()); + UInt32 vertexIndex = vert.index; + vertices[vertexIndex].x += (float)vert.delta.m128_f32[0] * factor; + vertices[vertexIndex].y += (float)vert.delta.m128_f32[1] * factor; + vertices[vertexIndex].z += (float)vert.delta.m128_f32[2] * factor; + } } else { - UInt32 size = m_vertexDeltas.size(); - for (UInt32 i = 0; i < size; i++) - { - TriShapePackedVertexDelta * vert = &m_vertexDeltas.at(i); + _ERROR("%s - Failed to apply morphs to geometry - morphs largest index is %d mesh vertex size is %d", __FUNCTION__, m_maxIndex, (UInt32)vertCount); + } +} - UInt16 vertexIndex = vert->index; - if (vertexIndex < vertCount) - { - vertices[vertexIndex].x += (float)vert->x * m_multiplier * factor; - vertices[vertexIndex].y += (float)vert->y * m_multiplier * factor; - vertices[vertexIndex].z += (float)vert->z * m_multiplier * factor; - } - else { - _DMESSAGE("%s - Vertex %d out of bounds X:%f Y:%f Z:%f", __FUNCTION__, vertexIndex, vert->x, vert->y, vert->z); - } +void TriShapePackedVertexData::ApplyMorph(UInt16 vertexCount, NiSkinPartition::TriShape * vertexData, float factor) +{ + UInt32 vertexSize = NiSkinPartition::GetVertexSize(vertexData->m_VertexDesc); + UInt32 offset = NiSkinPartition::GetVertexAttributeOffset(vertexData->m_VertexDesc, VertexAttribute::VA_POSITION); + + if (m_maxIndex < vertexCount) + { + for (const auto & vert : m_vertexDeltas) + { + DirectX::XMFLOAT4 * position = reinterpret_cast(&vertexData->m_RawVertexData[vertexSize * vert.index + offset]); + DirectX::XMStoreFloat4(position, DirectX::XMVectorAdd(DirectX::XMLoadFloat4(position), DirectX::XMVectorScale(vert.delta, factor))); } } + else + { + _ERROR("%s - Failed to apply morphs to geometry - morphs largest index is %d mesh vertex size is %d", __FUNCTION__, m_maxIndex, (UInt32)vertexCount); + } } -void TriShapePackedUVData::ApplyMorph(UInt16 vertCount, void * data, float factor) +void TriShapePackedUVData::ApplyMorphRaw(UInt16 vertCount, void * data, float factor) { UVCoord * deltas = static_cast(data); if (!deltas) return; - if (g_parallelMorphing) + if (m_maxIndex < vertCount) { - concurrency::parallel_for_each(m_uvDeltas.begin(), m_uvDeltas.end(), [&](const TriShapePackedUVDelta & vert) + for (const auto & delta : m_uvDeltas) { - UInt16 vertexIndex = vert.index; - if (vertexIndex < vertCount) - { - deltas[vertexIndex].u += (float)vert.u * m_multiplier * factor; - deltas[vertexIndex].v += (float)vert.v * m_multiplier * factor; - } - }, concurrency::static_partitioner()); + UInt32 vertexIndex = delta.index; + deltas[vertexIndex].u += (float)delta.u * m_multiplier * factor; + deltas[vertexIndex].v += (float)delta.v * m_multiplier * factor; + } } else { - UInt32 size = m_uvDeltas.size(); - for (UInt32 i = 0; i < size; i++) - { - TriShapePackedUVDelta * delta = &m_uvDeltas.at(i); + _ERROR("%s - Failed to apply morphs to geometry - morphs largest index is %d mesh vertex size is %d", __FUNCTION__, m_maxIndex, (UInt32)vertCount); + } +} - UInt16 vertexIndex = delta->index; - if (vertexIndex < vertCount) +void TriShapePackedUVData::ApplyMorph(UInt16 vertexCount, NiSkinPartition::TriShape * vertexData, float factor) +{ + VertexFlags flags = NiSkinPartition::GetVertexFlags(vertexData->m_VertexDesc); + if ((flags & VF_UV)) + { + UInt32 vertexSize = NiSkinPartition::GetVertexSize(vertexData->m_VertexDesc); + UInt32 offset = NiSkinPartition::GetVertexAttributeOffset(vertexData->m_VertexDesc, VertexAttribute::VA_TEXCOORD0); + if (m_maxIndex < vertexCount) + { + for (const auto & delta : m_uvDeltas) { - deltas[vertexIndex].u += (float)delta->u * m_multiplier * factor; - deltas[vertexIndex].v += (float)delta->v * m_multiplier * factor; - } - else { - _DMESSAGE("%s - Vertex %d out of bounds U:%f V:%f", __FUNCTION__, vertexIndex, delta->u, delta->v); + UVCoord * texCoord = reinterpret_cast(&vertexData->m_RawVertexData[vertexSize * delta.index + offset]); + texCoord->u += (float)delta.u * m_multiplier * factor; + texCoord->v += (float)delta.v * m_multiplier * factor; } } + else + { + _ERROR("%s - Failed to apply morphs to geometry - morphs largest index is %d mesh vertex size is %d", __FUNCTION__, m_maxIndex, (UInt32)vertexCount); + } } } @@ -488,7 +498,7 @@ namespace MinD3D11 }; }; -void MorphFileCache::ApplyMorph(TESObjectREFR * refr, NiAVObject * rootNode, bool isAttaching, const std::pair & bodyMorph) +void MorphFileCache::ApplyMorph(TESObjectREFR * refr, NiAVObject * rootNode, bool isAttaching, const std::pair & bodyMorph, std::mutex * dxLock) { BSFixedString nodeName = bodyMorph.first.data; BSGeometry * geometry = rootNode->GetAsBSGeometry(); @@ -507,22 +517,10 @@ void MorphFileCache::ApplyMorph(TESObjectREFR * refr, NiAVObject * rootNode, boo if (bodyData) { NiAutoRefCounter arc(bodyData); // Undo old morphs for this trishape - if (g_parallelMorphing) - { - concurrency::parallel_for((UInt16)0, geometryData->m_usVertices, [&](UInt16 i) - { - if (!isAttaching) - geometryData->m_pkVertex[i] -= bodyData->vertexData[i]; - bodyData->vertexData[i] = NiPoint3(0, 0, 0); - }, concurrency::static_partitioner()); - } - else - { - for (UInt16 i = 0; i < geometryData->m_usVertices; i++) { - if (!isAttaching) - geometryData->m_pkVertex[i] -= bodyData->vertexData[i]; - bodyData->vertexData[i] = NiPoint3(0, 0, 0); - } + for (UInt16 i = 0; i < geometryData->m_usVertices; i++) { + if (!isAttaching) + geometryData->m_pkVertex[i] -= bodyData->vertexData[i]; + bodyData->vertexData[i] = NiPoint3(0, 0, 0); } geometryData->m_usDirtyFlags = 0x0001; @@ -560,8 +558,8 @@ void MorphFileCache::ApplyMorph(TESObjectREFR * refr, NiAVObject * rootNode, boo NiAutoRefCounter arc(bodyData); bodyMorph.second.ApplyMorphs(refr, [&](const TriShapeVertexDataPtr morphData, float morphFactor) { - morphData->ApplyMorph(targetShapeData->m_usVertices, bodyData->vertexData, morphFactor); - morphData->ApplyMorph(targetShapeData->m_usVertices, targetShapeData->m_pkVertex, morphFactor); + morphData->ApplyMorphRaw(targetShapeData->m_usVertices, bodyData->vertexData, morphFactor); + morphData->ApplyMorphRaw(targetShapeData->m_usVertices, targetShapeData->m_pkVertex, morphFactor); }, nullptr); } @@ -584,14 +582,12 @@ void MorphFileCache::ApplyMorph(TESObjectREFR * refr, NiAVObject * rootNode, boo NiSkinPartition * skinPartition = niptr_cast(skinInstance->m_spSkinPartition); if (skinPartition) { // Undo morphs on the old shape - BSFaceGenBaseMorphExtraData * bodyData = (BSFaceGenBaseMorphExtraData *)bodyGeometry->GetExtraData("FOD"); - NiBinaryExtraData * uvData = (NiBinaryExtraData *)bodyGeometry->GetExtraData("FODUV"); + NiBinaryExtraData * bodyData = (NiBinaryExtraData *)bodyGeometry->GetExtraData("SHAPEDATA"); bool existingMorphs = !isAttaching && bodyData; - bool existingUV = !isAttaching && uvData; // Apply new morphs to new shape - if (bodyMorph.second.HasMorphs(refr) || existingMorphs || existingUV) + if (bodyMorph.second.HasMorphs(refr) || existingMorphs) { if (skinPartition) { @@ -599,143 +595,76 @@ void MorphFileCache::ApplyMorph(TESObjectREFR * refr, NiAVObject * rootNode, boo CALL_MEMBER_FN(skinPartition, DeepCopy)((NiObject **)&newSkinPartition); // Reset the Vertices directly - if (bodyData) + if (bodyData && newSkinPartition) { if (!isAttaching) { - for (UInt32 i = 0; i < newSkinPartition->vertexCount; ++i) + // Overwrite the vertex data with the original source data + for (UInt32 p = 0; p < newSkinPartition->m_uiPartitions; ++p) { - for (UInt32 p = 0; p < newSkinPartition->m_uiPartitions; ++p) - { - auto & partition = newSkinPartition->m_pkPartitions[p]; - - UInt32 vertexSize = newSkinPartition->GetVertexSize(partition.vertexDesc); - UInt32 offset = newSkinPartition->GetVertexAttributeOffset(partition.vertexDesc, VertexAttribute::VA_POSITION); - - NiPoint3 * position = reinterpret_cast(&partition.shapeData->m_RawVertexData[vertexSize * i + offset]); - *position -= bodyData->vertexData[i]; - } - } - } + auto & partition = newSkinPartition->m_pkPartitions[p]; + UInt32 vertexSize = newSkinPartition->GetVertexSize(partition.vertexDesc); - memset(bodyData->vertexData, 0, sizeof(NiPoint3)*newSkinPartition->vertexCount); - } - - // Reset the UV directly - if (uvData && bodyMorph.second.HasUV()) - { - if (!isAttaching) - { - for (UInt32 i = 0; i < newSkinPartition->vertexCount; ++i) - { - for (UInt32 p = 0; p < newSkinPartition->m_uiPartitions; ++p) - { - auto & partition = newSkinPartition->m_pkPartitions[p]; - VertexFlags flags = newSkinPartition->GetVertexFlags(partition.vertexDesc); - if (flags & VF_UV) - { - UInt32 vertexSize = newSkinPartition->GetVertexSize(partition.vertexDesc); - UInt32 offset = newSkinPartition->GetVertexAttributeOffset(partition.vertexDesc, VertexAttribute::VA_TEXCOORD0); - - TriShapePackedUVData::UVCoord * position = reinterpret_cast(&partition.shapeData->m_RawVertexData[vertexSize * i + offset]); - auto source = reinterpret_cast(uvData->m_data); - (*position).u -= source[i].u; - (*position).v -= source[i].v; - } - } + memcpy(partition.shapeData->m_RawVertexData, bodyData->m_data, newSkinPartition->vertexCount * vertexSize); } } - - memset(uvData->m_data, 0, uvData->m_size); } if (newSkinPartition) { - // No old morphs, add one + // No existing morphs, copy the current vertex block if (!bodyData) { - bodyData = BSFaceGenBaseMorphExtraData::Create(nullptr, false); - bodyData->vertexCount = skinPartition->vertexCount; - bodyData->modelVertexCount = skinPartition->vertexCount; - bodyData->vertexData = (NiPoint3*)Heap_Allocate(sizeof(NiPoint3) * bodyData->vertexCount); - memset(bodyData->vertexData, 0, sizeof(NiPoint3) * bodyData->vertexCount); - bodyGeometry->AddExtraData(bodyData); - } + auto & partition = newSkinPartition->m_pkPartitions[0]; + UInt32 vertexSize = newSkinPartition->GetVertexSize(partition.vertexDesc); - if (!uvData && bodyMorph.second.HasUV()) { - uvData = NiBinaryExtraData::Create("FODUV", nullptr, 0); - uvData->m_size = skinPartition->vertexCount * sizeof(TriShapePackedUVData::UVCoord); - uvData->m_data = (char*)Heap_Allocate(sizeof(TriShapePackedUVData::UVCoord) * skinPartition->vertexCount); - memset(uvData->m_data, 0, uvData->m_size); - bodyGeometry->AddExtraData(uvData); + bodyData = NiBinaryExtraData::Create("SHAPEDATA", reinterpret_cast(partition.shapeData->m_RawVertexData), newSkinPartition->vertexCount * vertexSize); + bodyGeometry->AddExtraData(bodyData); } if (bodyData) { - UInt32 vertexCount = skinPartition->vertexCount; - // Apply Morph data to the new partition - std::vector vertices(skinPartition->vertexCount); - memset(&vertices.at(0), 0, sizeof(NiPoint3)*vertexCount); - std::vector uvOffsets; - if (bodyMorph.second.HasUV()) - { - uvOffsets.resize(vertexCount); - memset(&uvOffsets.at(0), 0, sizeof(TriShapePackedUVData::UVCoord)*vertexCount); - } + auto & partition = newSkinPartition->m_pkPartitions[0]; + UInt32 vertexSize = newSkinPartition->GetVertexSize(partition.vertexDesc); + UInt32 vertexCount = newSkinPartition->vertexCount; std::function vertexMorpher = [&](const TriShapeVertexDataPtr morphData, float morphFactor) { - morphData->ApplyMorph(vertexCount, bodyData->vertexData, morphFactor); - morphData->ApplyMorph(vertexCount, &vertices.at(0), morphFactor); + if (morphFactor != 0.0f) + { + morphData->ApplyMorph(vertexCount, partition.shapeData, morphFactor); + } }; std::function uvMorpher = [&](const TriShapeVertexDataPtr morphData, float morphFactor) { - morphData->ApplyMorph(vertexCount, uvData->m_data, morphFactor); - morphData->ApplyMorph(vertexCount, &uvOffsets.at(0), morphFactor); + if (morphFactor != 0.0f) + { + morphData->ApplyMorph(vertexCount, partition.shapeData, morphFactor); + } }; // Applies all morphs for this shape bodyMorph.second.ApplyMorphs(refr, vertexMorpher, bodyMorph.second.HasUV() ? uvMorpher : nullptr); - } - // Do Subresource update - for (UInt32 p = 0; p < newSkinPartition->m_uiPartitions; ++p) - { - auto & partition = newSkinPartition->m_pkPartitions[p]; - UInt32 vertexSize = newSkinPartition->GetVertexSize(partition.vertexDesc); - UInt32 offsetPos = newSkinPartition->GetVertexAttributeOffset(partition.vertexDesc, VertexAttribute::VA_POSITION); - - if (bodyMorph.second.HasMorphs(refr) && bodyData) + // Copy the vertex data back onto the GPU + auto deviceContext = reinterpret_cast(g_renderManager->context); + if(dxLock) dxLock->lock(); + deviceContext->vtable->UpdateSubresource(reinterpret_cast(deviceContext), reinterpret_cast(partition.shapeData->m_VertexBuffer), 0, nullptr, partition.shapeData->m_RawVertexData, vertexCount * vertexSize, 0); + if (dxLock) dxLock->unlock(); + // Copy the remaining partitions from the first partition + for (UInt32 p = 1; p < newSkinPartition->m_uiPartitions; ++p) { - for (UInt32 i = 0; i < newSkinPartition->vertexCount; ++i) - { - NiPoint3 * position = reinterpret_cast(&partition.shapeData->m_RawVertexData[vertexSize * i + offsetPos]); - *position += bodyData->vertexData[i]; - } + auto & pPartition = newSkinPartition->m_pkPartitions[p]; + memcpy(pPartition.shapeData->m_RawVertexData, partition.shapeData->m_RawVertexData, newSkinPartition->vertexCount * vertexSize); + if (dxLock) dxLock->lock(); + deviceContext->vtable->UpdateSubresource(reinterpret_cast(deviceContext), reinterpret_cast(pPartition.shapeData->m_VertexBuffer), 0, nullptr, pPartition.shapeData->m_RawVertexData, vertexCount * vertexSize, 0); + if (dxLock) dxLock->unlock(); } - - if (bodyMorph.second.HasUV() && uvData) - { - VertexFlags flags = newSkinPartition->GetVertexFlags(partition.vertexDesc); - if ((flags & VF_UV)) - { - UInt32 offsetUV = newSkinPartition->GetVertexAttributeOffset(partition.vertexDesc, VertexAttribute::VA_TEXCOORD0); - for (UInt32 i = 0; i < newSkinPartition->vertexCount; ++i) - { - TriShapePackedUVData::UVCoord * position = reinterpret_cast(&partition.shapeData->m_RawVertexData[vertexSize * i + offsetUV]); - auto source = reinterpret_cast(uvData->m_data); - (*position).u += source[i].u; - (*position).v += source[i].v; - } - } - } - - auto deviceContext = reinterpret_cast(g_renderManager->context); - deviceContext->vtable->UpdateSubresource(reinterpret_cast(deviceContext), reinterpret_cast(partition.shapeData->m_VertexBuffer), 0, nullptr, partition.shapeData->m_RawVertexData, newSkinPartition->vertexCount * vertexSize, 0); } - } - skinInstance->m_spSkinPartition = newSkinPartition; + skinInstance->m_spSkinPartition = newSkinPartition; + newSkinPartition->DecRef(); // DeepCopy started refcount at 1 + } } } } @@ -746,9 +675,31 @@ void MorphFileCache::ApplyMorph(TESObjectREFR * refr, NiAVObject * rootNode, boo void MorphFileCache::ApplyMorphs(TESObjectREFR * refr, NiAVObject * rootNode, bool isAttaching) { - for (const auto & it : vertexMap) + if (g_parallelMorphing) { - ApplyMorph(refr, rootNode, isAttaching, it); + std::mutex dxLock; + concurrency::structured_task_group task_group; + std::vector>> task_list; + for (const auto & it : vertexMap) + { + task_list.push_back(concurrency::make_task>([&]() + { + ApplyMorph(refr, rootNode, isAttaching, it, &dxLock); + })); + } + for (auto & task : task_list) + { + task_group.run(task); + } + + task_group.wait(); + } + else + { + for (const auto & it : vertexMap) + { + ApplyMorph(refr, rootNode, isAttaching, it, nullptr); + } } } @@ -1038,8 +989,19 @@ bool MorphCache::CacheFile(const char * relativePath) for (UInt32 k = 0; k < vertexNum; k++) { TriShapeVertexDelta vertexDelta; + float x, y, z; trishapeMap.memoryUsage += binaryStream.Read((char *)&vertexDelta.index, sizeof(UInt32)); - trishapeMap.memoryUsage += binaryStream.Read((char *)&vertexDelta.diff, sizeof(NiPoint3)); + trishapeMap.memoryUsage += binaryStream.Read((char *)&x, sizeof(float)); + trishapeMap.memoryUsage += binaryStream.Read((char *)&y, sizeof(float)); + trishapeMap.memoryUsage += binaryStream.Read((char *)&z, sizeof(float)); + vertexDelta.delta.m128_f32[0] = (float)x * multiplier; + vertexDelta.delta.m128_f32[1] = (float)y * multiplier; + vertexDelta.delta.m128_f32[2] = (float)z * multiplier; + vertexDelta.delta.m128_f32[3] = 0; + + if (vertexDelta.index > fullVertexData->m_maxIndex) + fullVertexData->m_maxIndex = vertexDelta.index; + fullVertexData->m_vertexDeltas.push_back(vertexDelta); } @@ -1053,10 +1015,18 @@ bool MorphCache::CacheFile(const char * relativePath) for (UInt32 k = 0; k < vertexNum; k++) { TriShapePackedVertexDelta vertexDelta; + SInt16 x, y, z; trishapeMap.memoryUsage += binaryStream.Read((char *)&vertexDelta.index, sizeof(UInt16)); - trishapeMap.memoryUsage += binaryStream.Read((char *)&vertexDelta.x, sizeof(SInt16)); - trishapeMap.memoryUsage += binaryStream.Read((char *)&vertexDelta.y, sizeof(SInt16)); - trishapeMap.memoryUsage += binaryStream.Read((char *)&vertexDelta.z, sizeof(SInt16)); + trishapeMap.memoryUsage += binaryStream.Read((char *)&x, sizeof(SInt16)); + trishapeMap.memoryUsage += binaryStream.Read((char *)&y, sizeof(SInt16)); + trishapeMap.memoryUsage += binaryStream.Read((char *)&z, sizeof(SInt16)); + vertexDelta.delta.m128_f32[0] = (float)x * multiplier; + vertexDelta.delta.m128_f32[1] = (float)y * multiplier; + vertexDelta.delta.m128_f32[2] = (float)z * multiplier; + vertexDelta.delta.m128_f32[3] = 0; + + if (vertexDelta.index > packedVertexData->m_maxIndex) + packedVertexData->m_maxIndex = vertexDelta.index; packedVertexData->m_vertexDeltas.push_back(vertexDelta); } @@ -1150,6 +1120,9 @@ bool MorphCache::CacheFile(const char * relativePath) trishapeMap.memoryUsage += binaryStream.Read((char *)&vertexDelta.u, sizeof(SInt16)); trishapeMap.memoryUsage += binaryStream.Read((char *)&vertexDelta.v, sizeof(SInt16)); + if (vertexDelta.index > packedUVData->m_maxIndex) + packedUVData->m_maxIndex = vertexDelta.index; + packedUVData->m_uvDeltas.push_back(vertexDelta); } diff --git a/skee/BodyMorphInterface.h b/skee/BodyMorphInterface.h index 7f15c0f..b8342c5 100644 --- a/skee/BodyMorphInterface.h +++ b/skee/BodyMorphInterface.h @@ -6,6 +6,7 @@ #include "skse64/GameTypes.h" #include "skse64/GameThreads.h" #include "skse64/NiTypes.h" +#include "skse64/NiGeometry.h" #ifdef min #undef min @@ -22,6 +23,10 @@ #include #include #include +#include + +#include +#include class TESObjectREFR; struct SKSESerializationInterface; @@ -77,16 +82,14 @@ class TriShapeVertexDelta { public: UInt16 index; - NiPoint3 diff; + DirectX::XMVECTOR delta; }; class TriShapePackedVertexDelta { public: UInt16 index; - SInt16 x; - SInt16 y; - SInt16 z; + DirectX::XMVECTOR delta; }; class TriShapePackedUVDelta @@ -100,25 +103,34 @@ class TriShapePackedUVDelta class TriShapeVertexData { public: - virtual void ApplyMorph(UInt16 vertCount, void * vertices, float factor) = 0; + virtual void ApplyMorphRaw(UInt16 vertCount, void * vertices, float factor) = 0; + virtual void ApplyMorph(UInt16 vertexCount, NiSkinPartition::TriShape * vertexData, float factor) = 0; }; typedef std::shared_ptr TriShapeVertexDataPtr; class TriShapeFullVertexData : public TriShapeVertexData { public: - virtual void ApplyMorph(UInt16 vertCount, void * vertices, float factor); + TriShapeFullVertexData() : m_maxIndex(0) { } + + virtual void ApplyMorphRaw(UInt16 vertCount, void * vertices, float factor); + virtual void ApplyMorph(UInt16 vertexCount, NiSkinPartition::TriShape * vertexData, float factor); - std::vector m_vertexDeltas; + UInt32 m_maxIndex; + std::vector m_vertexDeltas; }; typedef std::shared_ptr TriShapeFullVertexDataPtr; class TriShapePackedVertexData : public TriShapeVertexData { public: - virtual void ApplyMorph(UInt16 vertCount, void * vertices, float factor); + TriShapePackedVertexData() : m_maxIndex(0) { } + + virtual void ApplyMorphRaw(UInt16 vertCount, void * vertices, float factor); + virtual void ApplyMorph(UInt16 vertexCount, NiSkinPartition::TriShape * vertexData, float factor); float m_multiplier; + UInt32 m_maxIndex; std::vector m_vertexDeltas; }; typedef std::shared_ptr TriShapePackedVertexDataPtr; @@ -126,15 +138,19 @@ typedef std::shared_ptr TriShapePackedVertexDataPtr; class TriShapePackedUVData : public TriShapeVertexData { public: + TriShapePackedUVData() : m_maxIndex(0) { } + struct UVCoord { half_float::half u; half_float::half v; }; - virtual void ApplyMorph(UInt16 vertCount, void * vertices, float factor); + virtual void ApplyMorphRaw(UInt16 vertCount, void * vertices, float factor); + virtual void ApplyMorph(UInt16 vertexCount, NiSkinPartition::TriShape * vertexData, float factor); float m_multiplier; + UInt32 m_maxIndex; std::vector m_uvDeltas; }; typedef std::shared_ptr TriShapePackedUVDataPtr; @@ -172,7 +188,7 @@ class MorphFileCache friend class BodyMorphInterface; public: void ApplyMorphs(TESObjectREFR * refr, NiAVObject * rootNode, bool erase = false); - void ApplyMorph(TESObjectREFR * refr, NiAVObject * rootNode, bool erase, const std::pair & bodyMorph); + void ApplyMorph(TESObjectREFR * refr, NiAVObject * rootNode, bool erase, const std::pair & bodyMorph, std::mutex * dxLock); private: TriShapeMap vertexMap; diff --git a/skee/SKEEHooks.cpp b/skee/SKEEHooks.cpp index d91d9f0..1c7c4da 100644 --- a/skee/SKEEHooks.cpp +++ b/skee/SKEEHooks.cpp @@ -65,27 +65,27 @@ extern bool g_externalHeads; extern bool g_extendedMorphs; extern bool g_allowAllMorphs; -RelocAddr<_CreateArmorNode> CreateArmorNode(0x001CAE50); +RelocAddr<_CreateArmorNode> CreateArmorNode(0x001CAE60); typedef void(*_RegenerateHead)(FaceGen * faceGen, BSFaceGenNiNode * headNode, BGSHeadPart * headPart, TESNPC * npc); -RelocAddr <_RegenerateHead> RegenerateHead(0x003D2DA0); +RelocAddr <_RegenerateHead> RegenerateHead(0x003D2C50); _RegenerateHead RegenerateHead_Original = nullptr; RelocPtr g_useFaceGenPreProcessedHeads(0x01E10030); // ??_7TESModelTri@@6B@ -RelocAddr TESModelTri_vtbl(0x015B0898); +RelocAddr TESModelTri_vtbl(0x015B08A0); // DB0F3961824CB053B91AC8B9D2FE917ACE7DD265+84 -RelocAddr<_AddGFXArgument> AddGFXArgument(0x008572C0); +RelocAddr<_AddGFXArgument> AddGFXArgument(0x00857000); // 57F6EC6339F20ED6A0882786A452BA66A046BDE8+1AE -RelocAddr<_FaceGenApplyMorph> FaceGenApplyMorph(0x003D2560); -RelocAddr<_AddRaceMenuSlider> AddRaceMenuSlider(0x008BCC10); -RelocAddr<_DoubleMorphCallback> DoubleMorphCallback(0x008B4CD0); +RelocAddr<_FaceGenApplyMorph> FaceGenApplyMorph(0x008B4BBE); +RelocAddr<_AddRaceMenuSlider> AddRaceMenuSlider(0x008BC950); +RelocAddr<_DoubleMorphCallback> DoubleMorphCallback(0x008B4A10); -RelocAddr<_UpdateNPCMorphs> UpdateNPCMorphs(0x00360AA0); -RelocAddr<_UpdateNPCMorph> UpdateNPCMorph(0x00360C90); +RelocAddr<_UpdateNPCMorphs> UpdateNPCMorphs(0x00360A30); +RelocAddr<_UpdateNPCMorph> UpdateNPCMorph(0x00360C20); // More in hook function @@ -1067,20 +1067,20 @@ bool InstallSKEEHooks() _ERROR("couldn't create codegen buffer. this is fatal. skipping remainder of init process."); return false; } - - RelocAddr InvokeCategoriesList_Target(0x008B56E0 + 0x9FB); + + RelocAddr InvokeCategoriesList_Target(0x008B5420 + 0x9FB); g_branchTrampoline.Write5Call(InvokeCategoriesList_Target.GetUIntPtr(), (uintptr_t)InvokeCategoryList_Hook); - RelocAddr AddSlider_Target(0x08B62D0 + 0x37E4); + RelocAddr AddSlider_Target(0x08B6010 + 0x37E4); g_branchTrampoline.Write5Call(AddSlider_Target.GetUIntPtr(), (uintptr_t)AddSlider_Hook); - RelocAddr DoubleMorphCallback1_Target(0x08B62D0 + 0x3CD5); + RelocAddr DoubleMorphCallback1_Target(0x08B6010 + 0x3CD5); g_branchTrampoline.Write5Call(DoubleMorphCallback1_Target.GetUIntPtr(), (uintptr_t)DoubleMorphCallback_Hook); - RelocAddr DoubleMorphCallback2_Target(0x08B2070 + 0x4F); // ChangeDoubleMorph callback + RelocAddr DoubleMorphCallback2_Target(0x08B1DB0 + 0x4F); // ChangeDoubleMorph callback g_branchTrampoline.Write5Call(DoubleMorphCallback2_Target.GetUIntPtr(), (uintptr_t)DoubleMorphCallback_Hook); - - RelocAddr SliderLookup_Target(0x08B62D0 + 0x3895); + + RelocAddr SliderLookup_Target(0x08B6010 + 0x3895); { struct SliderLookup_Entry_Code : Xbyak::CodeGenerator { SliderLookup_Entry_Code(void * buf, UInt64 funcAddr, UInt64 targetAddr) : Xbyak::CodeGenerator(4096, buf) @@ -1111,9 +1111,9 @@ bool InstallSKEEHooks() if (!g_externalHeads) { - RelocAddr PreprocessedHeads1_Target(0x0364040 + 0x58); - RelocAddr PreprocessedHeads2_Target(0x0364040 + 0x81); - RelocAddr PreprocessedHeads3_Target(0x0364040 + 0x67); + RelocAddr PreprocessedHeads1_Target(0x00363FD0 + 0x58); + RelocAddr PreprocessedHeads2_Target(0x00363FD0 + 0x81); + RelocAddr PreprocessedHeads3_Target(0x00363FD0 + 0x67); { struct UsePreprocessedHeads_Entry_Code : Xbyak::CodeGenerator { UsePreprocessedHeads_Entry_Code(void * buf, UInt64 funcAddr, UInt64 targetAddr) : Xbyak::CodeGenerator(4096, buf) @@ -1188,28 +1188,28 @@ bool InstallSKEEHooks() if (g_extendedMorphs) { - RelocAddr ApplyChargenMorph_Target(0x003D26C0 + 0xF3); + RelocAddr ApplyChargenMorph_Target(0x003D2570 + 0xF3); g_branchTrampoline.Write5Call(ApplyChargenMorph_Target.GetUIntPtr(), (uintptr_t)ApplyChargenMorph_Hooked); - RelocAddr ApplyRaceMorph_Target(0x003D48F0 + 0x56); + RelocAddr ApplyRaceMorph_Target(0x003D47A0 + 0x56); g_branchTrampoline.Write5Call(ApplyRaceMorph_Target.GetUIntPtr(), (uintptr_t)ApplyRaceMorph_Hooked); } - RelocAddr UpdateMorphs_Target(0x003D2830 + 0xC7); + RelocAddr UpdateMorphs_Target(0x003D26E0 + 0xC7); g_branchTrampoline.Write5Call(UpdateMorphs_Target.GetUIntPtr(), (uintptr_t)UpdateMorphs_Hooked); - RelocAddr UpdateMorph_Target(0x003DC500 + 0x79); + RelocAddr UpdateMorph_Target(0x003DC3B0 + 0x79); g_branchTrampoline.Write5Call(UpdateMorph_Target.GetUIntPtr(), (uintptr_t)UpdateMorph_Hooked); if (g_disableFaceGenCache) { - RelocAddr Cache_Target(0x008B3090); + RelocAddr Cache_Target(0x008B2DD0); SafeWrite8(Cache_Target.GetUIntPtr(), 0xC3); // Cache immediate retn - RelocAddr CacheClear_Target(0x008B3210); + RelocAddr CacheClear_Target(0x008B2F50); SafeWrite8(CacheClear_Target.GetUIntPtr(), 0xC3); // Cache clear immediate retn } - RelocAddr ArmorAddon_Target(0x001C7170 + 0xB4A); + RelocAddr ArmorAddon_Target(0x001C7180 + 0xB4A); { struct ArmorAddonHook_Entry_Code : Xbyak::CodeGenerator { ArmorAddonHook_Entry_Code(void * buf, UInt64 funcAddr, UInt64 targetAddr) : Xbyak::CodeGenerator(4096, buf) diff --git a/skee/main.cpp b/skee/main.cpp index 7e171c2..f63bb2a 100644 --- a/skee/main.cpp +++ b/skee/main.cpp @@ -646,9 +646,9 @@ bool SKSEPlugin_Query(const SKSEInterface * skse, PluginInfo * info) _MESSAGE("loaded in editor, marking as incompatible"); return false; } - else if (skse->runtimeVersion != RUNTIME_VERSION_1_5_39) + else if (skse->runtimeVersion != RUNTIME_VERSION_1_5_50) { - UInt32 runtimeVersion = RUNTIME_VERSION_1_5_39; + UInt32 runtimeVersion = RUNTIME_VERSION_1_5_50; char buf[512]; sprintf_s(buf, "RaceMenu Version Error:\nexpected game version %d.%d.%d.%d\nyour game version is %d.%d.%d.%d\nsome features may not work correctly.", GET_EXE_VERSION_MAJOR(runtimeVersion),