Files
BlitzNext/_release/samples/AGore/BirdDemo/KBSplines.bb
T
2014-02-26 16:09:18 +13:00

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