@@ -28,7 +28,7 @@ namespace plugin {
2828 std::map<std::tuple<RE ::NiNode *, RE ::TESNPC *, std::string>, FaceMorphData> queued_morphs;
2929 std::unordered_map<uint32_t , RE ::ActorHandle> queued_recalcs;
3030
31- static void WalkRecalculateNormals (RE ::NiNode *node) {
31+ static void WalkRecalculateNormals (RE ::NiNode *node, std::recursive_mutex& thread_mutex, std::vector<std::thread>& spawned_threads ) {
3232 if (node == nullptr ) {
3333 return ;
3434 }
@@ -37,7 +37,7 @@ namespace plugin {
3737 continue ;
3838 }
3939 if (auto c_node = obj->AsNode ()) {
40- WalkRecalculateNormals (c_node);
40+ WalkRecalculateNormals (c_node,thread_mutex,spawned_threads );
4141 }
4242 if (auto geo = obj->AsGeometry ()) {
4343 if (geo->GetGeometryRuntimeData ().skinInstance == nullptr ) {
@@ -61,35 +61,41 @@ namespace plugin {
6161 if (!material) {
6262 continue ;
6363 }
64- RE ::NiPointer<RE ::NiObject> newPartition = nullptr ;
65- geo->GetGeometryRuntimeData ().skinInstance ->skinPartition ->CreateDeepCopy (newPartition);
66- if (!newPartition) {
67- continue ;
68- }
69- RE ::NiPointer<RE ::NiSkinPartition> newSkinPartition =
70- RE ::NiPointer<RE ::NiSkinPartition>((RE ::NiSkinPartition *) newPartition.get ());
71- if (newSkinPartition->partitions .size () == 0 ) {
72- newSkinPartition->DecRefCount ();
73- continue ;
74- }
7564 {
76- NormalApplicatorBackported applicator (RE ::NiPointer<RE ::BSGeometry>((RE ::BSGeometry *) geo), newSkinPartition);
77- applicator.Apply ();
78- }
79- for (uint32_t p = 1 ; p < newSkinPartition->partitions .size (); ++p) {
80- auto &pPartition = newSkinPartition->partitions [p];
81- memcpy (pPartition.buffData ->rawVertexData , newSkinPartition->partitions [0 ].buffData ->rawVertexData ,
82- newSkinPartition->vertexCount * newSkinPartition->partitions [0 ].buffData ->vertexDesc .GetSize ());
83- }
84- uint64_t UpdateSkinPartition_object[6 ] = {0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
85- UpdateSkinPartition_object[0 ] = NIOVTaskUpdateSkinPartitionvtable;
65+ std::lock_guard<std::recursive_mutex> l (thread_mutex);
66+ spawned_threads.push_back (std::thread ([=]() {
67+ RE ::NiPointer<RE ::NiObject> newPartition = nullptr ;
68+ geo->GetGeometryRuntimeData ().skinInstance ->skinPartition ->CreateDeepCopy (newPartition);
69+ if (!newPartition) {
70+ return ;
71+ }
72+ RE ::NiPointer<RE ::NiSkinPartition> newSkinPartition =
73+ RE ::NiPointer<RE ::NiSkinPartition>((RE ::NiSkinPartition *) newPartition.get ());
74+ if (newSkinPartition->partitions .size () == 0 ) {
75+ newSkinPartition->DecRefCount ();
76+ return ;
77+ }
78+ {
79+ NormalApplicatorBackported applicator (RE ::NiPointer<RE ::BSGeometry>((RE ::BSGeometry *) geo), newSkinPartition);
80+ applicator.Apply ();
81+ }
82+ for (uint32_t p = 1 ; p < newSkinPartition->partitions .size (); ++p) {
83+ auto &pPartition = newSkinPartition->partitions [p];
84+ memcpy (pPartition.buffData ->rawVertexData , newSkinPartition->partitions [0 ].buffData ->rawVertexData ,
85+ newSkinPartition->vertexCount * newSkinPartition->partitions [0 ].buffData ->vertexDesc .GetSize ());
86+ }
87+ uint64_t UpdateSkinPartition_object[6 ] = {0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
88+ UpdateSkinPartition_object[0 ] = NIOVTaskUpdateSkinPartitionvtable;
89+
90+ uint64_t *skinInstPtr = (uint64_t *) (geo->GetGeometryRuntimeData ().skinInstance .get ());
91+ uint64_t *skinPartPtr = (uint64_t *) (newSkinPartition.get ());
92+ UpdateSkinPartition_object[1 ] = (uint64_t ) skinPartPtr;
93+ UpdateSkinPartition_object[2 ] = (uint64_t ) skinInstPtr;
94+ auto RunNIOVTaskUpdateSkinPartition = ((void (*)(uint64_t *))((uint64_t *) UpdateSkinPartition_object[0 ])[0 ]);
95+ RunNIOVTaskUpdateSkinPartition (UpdateSkinPartition_object);
96+ }));
8697
87- uint64_t *skinInstPtr = (uint64_t *) (geo->GetGeometryRuntimeData ().skinInstance .get ());
88- uint64_t *skinPartPtr = (uint64_t *) (newSkinPartition.get ());
89- UpdateSkinPartition_object[1 ] = (uint64_t ) skinPartPtr;
90- UpdateSkinPartition_object[2 ] = (uint64_t ) skinInstPtr;
91- auto RunNIOVTaskUpdateSkinPartition = ((void (*)(uint64_t *))((uint64_t *) UpdateSkinPartition_object[0 ])[0 ]);
92- RunNIOVTaskUpdateSkinPartition (UpdateSkinPartition_object);
98+ }
9399 }
94100 }
95101 }
@@ -118,23 +124,29 @@ namespace plugin {
118124 std::vector<std::thread> spawned_threads;
119125 for (auto p: temp_recalcs) {
120126 spawned_threads.push_back (std::thread ([hp = p]() {
127+ std::recursive_mutex thread_mutex;
128+ std::vector<std::thread> spawned_threads_recalc;
121129 auto actor = hp.second .get ();
122130 if (actor->Is3DLoaded ()) {
123131 if (auto obj = actor->Get3D1 (true )) {
124132 if (auto node = obj->AsNode ()) {
125- WalkRecalculateNormals (node);
133+
134+ WalkRecalculateNormals (node,thread_mutex,spawned_threads_recalc);
126135 }
127136 }
128137 if (auto obj = actor->Get3D1 (false )) {
129138 if (auto node = obj->AsNode ()) {
130- WalkRecalculateNormals (node);
139+ WalkRecalculateNormals (node, thread_mutex, spawned_threads_recalc );
131140 }
132141 }
133142 if (auto facenode = actor->GetFaceNode ()) {
134143 UpdateFaceModel (facenode);
135- WalkRecalculateNormals (facenode);
144+ WalkRecalculateNormals (facenode, thread_mutex, spawned_threads_recalc );
136145 }
137146 }
147+ for (auto &t : spawned_threads_recalc) {
148+ t.join ();
149+ }
138150 actor->DecRefCount ();
139151 }));
140152 }
@@ -222,7 +234,6 @@ namespace plugin {
222234 AddActorToRecalculate (actor.get ());
223235 }
224236 }
225- WalkRecalculateNormals (node);
226237 }
227238 }
228239 static void (*ApplyMorphHookFaceNormalsDetour)(void *e, RE ::TESNPC *, RE ::BGSHeadPart *,
@@ -236,7 +247,6 @@ namespace plugin {
236247 AddActorToRecalculate (actor.get ());
237248 }
238249 }
239- WalkRecalculateNormals (node);
240250 }
241251 }
242252 static void (*ApplyMorphsHookBodyNormalsDetour)(void *e, RE ::TESObjectREFR *, RE ::NiNode *, bool isAttaching,
@@ -246,14 +256,12 @@ namespace plugin {
246256 ApplyMorphsHookBodyNormalsDetour (morphInterface, refr, node, isAttaching, defer);
247257 if (node) {
248258 if (node->AsNode ()) {
249- WalkRecalculateNormals (node);
250259 if (auto actor = refr->As <RE ::Actor>()) {
251260 if (actor->Is3DLoaded ()) {
252261 AddActorToRecalculate (actor);
253262 }
254263 }
255264 }
256- WalkRecalculateNormals (node);
257265 }
258266 }
259267 void GameEventHandler::onLoad () {
0 commit comments