182 lines
4.5 KiB
BlitzBasic
182 lines
4.5 KiB
BlitzBasic
;Kochanek-Bartels Splines
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
; VARIABLES
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
Const nkeyframes = 50 ;maximum number of keyframes per motion
|
|
Const nchannels = 9 ;number of channel values
|
|
Dim icv#(nchannels-1) ;stores interpolated channel values
|
|
Global key0.KeyFrame, key1.KeyFrame
|
|
key0.KeyFrame = New keyframe : key1.KeyFrame = New keyframe
|
|
|
|
Type Motion
|
|
Field nkeys ;number of keyframes
|
|
Field nsteps ;last frame number
|
|
Field keylist.KeyFrame[nkeyframes-1];array of keyframes
|
|
End Type
|
|
|
|
Type KeyFrame
|
|
Field fstep ;frame number
|
|
Field cv#[nchannels-1] ;array of channel values (x y z h p b sx sy sz)
|
|
Field linear ;linear flag
|
|
Field tens# ;Kochanek-Bartels parameters
|
|
Field cont#
|
|
Field bias#
|
|
End Type
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
; FUNCTIONS
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
Function Load_Motion( file$, m.Motion )
|
|
|
|
Local f,s$, i, ii
|
|
|
|
f = ReadFile( file )
|
|
If f = False Then Return False
|
|
|
|
If ReadLine$(f) <> "B3D Motion" Then Return False
|
|
If Int(ReadLine$(f)) <> "1" Then Return False
|
|
ReadLine$(f)
|
|
|
|
m\nkeys = Int(ReadLine$(f))
|
|
|
|
For i = 0 To m\nkeys ;read keyframe data
|
|
s$ = ReadLine$( f )
|
|
m\keylist[i] = New KeyFrame
|
|
m\keylist[i]\fstep = Int(Parse(s,1))
|
|
For ii = 0 To nchannels-1 : m\keylist[i]\cv[ii] = Float(Parse(s,2+ii)) : Next
|
|
m\keylist[i]\linear = Int(Parse(s,11))
|
|
m\keylist[i]\tens = Float(Parse(s,12))
|
|
m\keylist[i]\cont = Float(Parse(s,13))
|
|
m\keylist[i]\bias = Float(Parse(s,14))
|
|
Next
|
|
|
|
m\nsteps = m\keylist[m\nkeys-1]\fstep
|
|
|
|
CloseFile f
|
|
Return True
|
|
|
|
End Function
|
|
;------------------------------------------------------------------------
|
|
|
|
;------------------------------------------------------------------------
|
|
Function Apply_Motion(m.Motion, tstep#, e)
|
|
|
|
Local dd0a#, dd0b#, ds1a#, ds1b#
|
|
Local adj0#, adj1#, dd0#, ds1#, d2#, t#, d10#
|
|
Local t2#, t3#, z#, h#[3]
|
|
Local i, tlen, key
|
|
|
|
;*** if there's only one key, the channel values are constant ***
|
|
|
|
If (m\nkeys = 1) Then
|
|
For i = 0 To nchannels-1 : icv(i) = m\keylist[0]\cv[i] : Next
|
|
Return
|
|
End If
|
|
|
|
;*** find keyframe pair to interpolate between ***
|
|
|
|
If tstep < m\keylist[0]\fstep Then Return
|
|
|
|
For key = 1 To m\nkeys
|
|
If tstep <= m\keylist[key]\fstep Then Exit
|
|
Next
|
|
key1 = m\keylist[key]
|
|
|
|
If key = m\nkeys Then Return
|
|
|
|
key0 = m\keylist[key - 1]
|
|
|
|
tlen = key1\fstep - key0\fstep
|
|
t = (tstep - key0\fstep) / tlen
|
|
|
|
If key1\linear = 0 Then
|
|
|
|
;*** precompute hermite spline coefficients ***
|
|
|
|
t2 = t * t
|
|
t3 = t * t2
|
|
z = 3 * t2 - t3 - t3
|
|
|
|
h[0] = 1 - z
|
|
h[1] = z
|
|
h[2] = t3 - t2 - t2 + t
|
|
h[3] = t3 - t2
|
|
|
|
dd0a = (1 - key0\tens) * (1 + key0\cont) * (1 + key0\bias)
|
|
dd0b = (1 - key0\tens) * (1 - key0\cont) * (1 - key0\bias)
|
|
ds1a = (1 - key1\tens) * (1 - key1\cont) * (1 + key1\bias)
|
|
ds1b = (1 - key1\tens) * (1 + key1\cont) * (1 - key1\bias)
|
|
|
|
If key0\fstep <> 0 Then
|
|
d2 = (key1\fstep - m\keylist[key - 2]\fstep)
|
|
adj0 = tlen / d2
|
|
End If
|
|
|
|
If key1\fstep <> m\nsteps Then
|
|
d2 = (m\keylist[key+1]\fstep - key0\fstep)
|
|
adj1 = tlen / d2
|
|
End If
|
|
|
|
End If
|
|
|
|
;*** compute channel components and store in icv() ***
|
|
|
|
For i = 0 To nchannels-1
|
|
|
|
d10 = key1\cv[i] - key0\cv[i]
|
|
|
|
If key1\linear = 0 Then
|
|
|
|
If key0\fstep = 0 Then
|
|
dd0 = 0.5 * (dd0a + dd0b) * d10
|
|
Else
|
|
dd0 = adj0 * (dd0a * (key0\cv[i] - m\keylist[key - 2]\cv[i]) + dd0b * d10)
|
|
End If
|
|
|
|
If key1\fstep = m\nsteps Then
|
|
ds1 = 0.5 * (ds1a + ds1b) * d10
|
|
Else
|
|
ds1 = adj1 * (ds1a * d10 + ds1b * ( m\keylist[key + 1]\cv[i] - key1\cv[i] ))
|
|
End If
|
|
|
|
icv(i) = (h[0] * key0\cv[i]) + (h[1] * key1\cv[i]) + (h[2] * dd0) + (h[3] * ds1)
|
|
|
|
Else
|
|
icv(i) = key0\cv[i] + t * d10
|
|
End If
|
|
|
|
Next
|
|
|
|
PositionEntity e,icv(0),icv(1),icv(2)
|
|
RotateEntity e,icv(3),icv(4),icv(5)
|
|
ScaleEntity e,icv(6),icv(7),icv(8)
|
|
|
|
End Function
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
Function Parse$(s$,o)
|
|
|
|
Local a$,d$,bb,b,e#,even
|
|
s=Trim(s)+" " : d="" : bb=0 : e=0 : even=True
|
|
|
|
For b=1 To Len(s)
|
|
|
|
a = Mid(s,b,1)
|
|
|
|
If a = "'" Then e=e+1 : even = ( (e/2) = Int(e/2) )
|
|
|
|
If a = " "
|
|
If even = True
|
|
bb=bb+1
|
|
If bb = o Then Return Trim( Replace(d,"'"," ") ) Else d=""
|
|
EndIf
|
|
EndIf
|
|
d=d+a
|
|
|
|
Next
|
|
|
|
End Function |