3
3
using Dalamud . Game ;
4
4
using FFXIVClientStructs . Havok ;
5
5
using System ;
6
+ using System . Linq ;
6
7
using System . Numerics ;
7
8
using System . Runtime . InteropServices ;
8
9
9
10
namespace Brio . Game . Posing ;
10
11
internal unsafe class IKService : IDisposable
11
12
{
12
13
delegate * unmanaged< hkaCCDSolver * , int , float , void > _ccdSolverCtr ;
13
- delegate * unmanaged< hkaCCDSolver * , byte * , hkArray < IKConstraint > * , hkaPose * , byte * > _ccdSolverSolve ;
14
+ delegate * unmanaged< hkaCCDSolver * , byte * , hkArray < CCDIKConstraint > * , hkaPose * , byte * > _ccdSolverSolve ;
15
+ delegate * unmanaged< byte * , TwoJointIKSetup * , hkaPose * , byte * > _twoJointSolverSolve ;
14
16
15
17
private ( nint Aligned , nint Unaligned ) _solverAddr ;
16
- private ( nint Aligned , nint Unaligned ) _constraintAddr ;
18
+ private ( nint Aligned , nint Unaligned ) _ccdConstraintCtrAddr ;
19
+ private ( nint Aligned , nint Unaligned ) _twoJointSetupAddr ;
17
20
18
21
public IKService ( ISigScanner scanner )
19
22
{
20
23
_ccdSolverCtr = ( delegate * unmanaged< hkaCCDSolver * , int , float , void > ) scanner . ScanText ( "E8 ?? ?? ?? ?? BA ?? ?? ?? ?? 48 C7 43" ) ;
21
- _ccdSolverSolve = ( delegate * unmanaged< hkaCCDSolver * , byte * , hkArray < IKConstraint > * , hkaPose * , byte * > ) scanner . ScanText ( "E8 ?? ?? ?? ?? 8B 45 ?? 48 8B 75" ) ;
22
-
24
+ _ccdSolverSolve = ( delegate * unmanaged< hkaCCDSolver * , byte * , hkArray < CCDIKConstraint > * , hkaPose * , byte * > ) scanner . ScanText ( "E8 ?? ?? ?? ?? 8B 45 ?? 48 8B 75" ) ;
25
+ _twoJointSolverSolve = ( delegate * unmanaged< byte * , TwoJointIKSetup * , hkaPose * , byte * > ) scanner . ScanText ( "E8 ?? ?? ?? ?? 0F 28 55 ?? 41 0F 28 D8" ) ;
26
+
23
27
_solverAddr = NativeHelpers . AllocateAlignedMemory ( sizeof ( hkaCCDSolver ) , 16 ) ;
24
- _constraintAddr = NativeHelpers . AllocateAlignedMemory ( sizeof ( IKConstraint ) , 16 ) ;
28
+ _ccdConstraintCtrAddr = NativeHelpers . AllocateAlignedMemory ( sizeof ( CCDIKConstraint ) , 16 ) ;
29
+ _twoJointSetupAddr = NativeHelpers . AllocateAlignedMemory ( sizeof ( TwoJointIKSetup ) , 16 ) ;
30
+
31
+ TwoJointIKSetup * setup = ( TwoJointIKSetup * ) _twoJointSetupAddr . Aligned ;
32
+ * setup = new TwoJointIKSetup ( ) ;
25
33
}
26
34
27
- public void SolveIK ( hkaPose * pose , ushort startBone , ushort endBone , Vector3 target , int iterations )
35
+ public void SolveIK ( hkaPose * pose , BoneIKInfo ikInfo , Bone bone , Vector3 target )
28
36
{
29
- hkaCCDSolver * ccdSolver = ( hkaCCDSolver * ) _solverAddr . Aligned ;
30
- _ccdSolverCtr ( ccdSolver , iterations , 1f ) ;
31
-
32
- IKConstraint * constraint = ( IKConstraint * ) _constraintAddr . Aligned ;
33
- constraint ->StartBone = startBone ;
34
- constraint ->EndBone = endBone ;
35
- constraint ->Target . X = target . X ;
36
- constraint ->Target . Y = target . Y ;
37
- constraint ->Target . Z = target . Z ;
38
-
39
- var constraints = new hkArray < IKConstraint >
40
- {
41
- Length = 1 ,
42
- CapacityAndFlags = 1 ,
43
- Data = constraint
44
- } ;
45
-
46
- byte notSure = 0 ;
47
- _ccdSolverSolve ( ccdSolver , & notSure , & constraints , pose ) ;
37
+ ikInfo . SolverOptions . Switch (
38
+ ccd =>
39
+ {
40
+ var boneList = bone . GetBonesToDepth ( ccd . Depth , true ) ;
41
+ if ( boneList . Count <= 1 )
42
+ return ;
43
+
44
+ var startBone = ( short ) boneList . Last ( ) . Index ;
45
+ var endBone = ( short ) boneList . First ( ) . Index ;
46
+
47
+ hkaCCDSolver * ccdSolver = ( hkaCCDSolver * ) _solverAddr . Aligned ;
48
+ _ccdSolverCtr ( ccdSolver , ccd . Iterations , 1f ) ;
49
+
50
+ CCDIKConstraint * constraint = ( CCDIKConstraint * ) _ccdConstraintCtrAddr . Aligned ;
51
+ constraint ->StartBone = startBone ;
52
+ constraint ->EndBone = endBone ;
53
+ constraint ->Target . X = target . X ;
54
+ constraint ->Target . Y = target . Y ;
55
+ constraint ->Target . Z = target . Z ;
56
+
57
+ var constraints = new hkArray < CCDIKConstraint >
58
+ {
59
+ Length = 1 ,
60
+ CapacityAndFlags = 1 ,
61
+ Data = constraint
62
+ } ;
63
+
64
+ byte notSure = 0 ;
65
+ _ccdSolverSolve ( ccdSolver , & notSure , & constraints , pose ) ;
66
+ } ,
67
+ twoJoint =>
68
+ {
69
+ var boneList = bone . GetBonesToDepth ( twoJoint . FirstBone , true ) ;
70
+
71
+ if ( boneList . Count < twoJoint . FirstBone )
72
+ return ;
73
+
74
+ TwoJointIKSetup * setup = ( TwoJointIKSetup * ) _twoJointSetupAddr . Aligned ;
75
+ setup ->FirstJointIdx = ( short ) boneList [ twoJoint . FirstBone ] . Index ;
76
+ setup ->SecondJointIdx = ( short ) boneList [ twoJoint . SecondBone ] . Index ;
77
+ setup ->EndBoneIdx = ( short ) boneList [ twoJoint . EndBone ] . Index ;
78
+ setup ->EndTargetMS = new Vector4 ( target , 0 ) ;
79
+ setup ->HingeAxisLS = new Vector4 ( twoJoint . RotationAxis , 0 ) ;
80
+
81
+ byte notSure = 0 ;
82
+ _twoJointSolverSolve ( & notSure , setup , pose ) ;
83
+ }
84
+ ) ;
48
85
}
49
86
50
87
public void Dispose ( )
51
88
{
52
89
NativeHelpers . FreeAlignedMemory ( _solverAddr ) ;
53
- NativeHelpers . FreeAlignedMemory ( _constraintAddr ) ;
90
+ NativeHelpers . FreeAlignedMemory ( _ccdConstraintCtrAddr ) ;
54
91
}
55
92
56
93
[ StructLayout ( LayoutKind . Explicit , Size = 0x18 ) ]
@@ -62,11 +99,35 @@ private struct hkaCCDSolver
62
99
}
63
100
64
101
[ StructLayout ( LayoutKind . Explicit , Size = 0x2 ) ]
65
- private struct IKConstraint
102
+ private struct CCDIKConstraint
66
103
{
67
- [ FieldOffset ( 0x0 ) ] public ushort StartBone ;
68
- [ FieldOffset ( 0x2 ) ] public ushort EndBone ;
104
+ [ FieldOffset ( 0x0 ) ] public short StartBone ;
105
+ [ FieldOffset ( 0x2 ) ] public short EndBone ;
69
106
[ FieldOffset ( 0x10 ) ] public hkVector4f Target ;
70
107
}
71
108
109
+ [ StructLayout ( LayoutKind . Explicit , Size = 0x82 ) ]
110
+ private struct TwoJointIKSetup
111
+ {
112
+ [ FieldOffset ( 0x00 ) ] public short FirstJointIdx = - 1 ;
113
+ [ FieldOffset ( 0x02 ) ] public short SecondJointIdx = - 1 ;
114
+ [ FieldOffset ( 0x04 ) ] public short EndBoneIdx = - 1 ;
115
+ [ FieldOffset ( 0x06 ) ] public short FirstJointTwistIdx = - 1 ;
116
+ [ FieldOffset ( 0x08 ) ] public short SecondJointTwistIdx = - 1 ;
117
+ [ FieldOffset ( 0x10 ) ] public Vector4 HingeAxisLS = Vector4 . Zero ;
118
+ [ FieldOffset ( 0x20 ) ] public float CosineMaxHingeAngle = - 1f ;
119
+ [ FieldOffset ( 0x24 ) ] public float CosineMinHingeAngle = 1f ;
120
+ [ FieldOffset ( 0x28 ) ] public float FirstJointIkGain = 1f ;
121
+ [ FieldOffset ( 0x2C ) ] public float SecondJointIkGain = 1f ;
122
+ [ FieldOffset ( 0x30 ) ] public float EndJointIkGain = 1f ;
123
+ [ FieldOffset ( 0x40 ) ] public Vector4 EndTargetMS = Vector4 . Zero ;
124
+ [ FieldOffset ( 0x50 ) ] public Quaternion EndTargetRotationMS = Quaternion . Identity ;
125
+ [ FieldOffset ( 0x60 ) ] public Vector4 EndBoneOffsetLS = Vector4 . Zero ;
126
+ [ FieldOffset ( 0x70 ) ] public Quaternion EndBoneRotationOffsetLS = Quaternion . Identity ;
127
+ [ FieldOffset ( 0x80 ) ] public bool EnforceEndPosition = true ;
128
+ [ FieldOffset ( 0x81 ) ] public bool EnforceEndRotation = false ;
129
+
130
+ public TwoJointIKSetup ( ) { }
131
+ }
132
+
72
133
}
0 commit comments