Stevie G
I gave Verlet Integration a go a while back. It merged BVH Boneset, Verlets, and Springs into one system. However, I placed it back on the burner.
;ANIMATE CLASS SPRINGLET + BVH STRUCTURE
;verlet + spring physics model system merge with bvh
Const SPRINGLING_MAX_CONSTRIANTS=128
Const SPRINGLING_MAX_NEIGHBORS%=128
Const SPRINGLING_MAX_SPRINGLETS%=128
Const SPRINGLING_MAX_ANCHOR_SPRINGLETS%=128
Global warpgravity.vector=vectorNew() ;global warp gravity
Global springlettempvector.vector=vectorNew()
Global springletpositionvector.vector=vectorNew()
Global springletdeltavector.vector=vectorNew() ;springletdeltavector
Global springletforcedirection.vector=vectorNew();
Global springletaccumulator.vector=vectorNew();
Global springletresultant.vector=vectorNew()
;============================
;BVHFRAMESET
;============================
Const BVHFRAMESET_MAX=256
Dim bvhframesetID.bvhframeset(BVHFRAMESET_MAX)
Global bvhframesetIndex.stack=stackCreateIndex(4,BVHFRAMESET_MAX,1)
Type bvhframeset
Field id%
Field typeid%
Field time#
Field springlets%
Field frames%
Field springletpointer%
Field framepointer%
Field bank%
End Type
Function bvhframesetStart.bvhframeset(filename$="Default")
;load from config
bvhframesetopen(filename$)
;setup
For this.bvhframeset=Each bvhframeset
Next
Return First bvhframeset
End Function
Function bvhframesetStop()
For this.bvhframeset=Each bvhframeset
bvhframesetDelete(this)
Next
End Function
Function bvhframesetNew.bvhframeset()
this.bvhframeset=New bvhframeset
this\id%=0
this\typeid%=0
this\time#=0.0
this\springlets%=0
this\frames%=0
this\springletpointer%=0
this\framepointer%=0
this\bank%=0
this\id%=StackPop(bvhframesetIndex.stack,1)
bvhframesetID(this\id)=this
Return this
End Function
Function bvhframesetDelete(this.bvhframeset)
bvhframesetID(this\id)=Null
StackPush(bvhframesetIndex.stack,this\id%,1)
FreeBank this\bank%
this\time#=0.0
Delete this
End Function
Function bvhframesetManager()
For this.bvhframeset=Each bvhframeset
Next
End Function
Function bvhframesetRead.bvhframeset(file)
this.bvhframeset=New bvhframeset
this\id%=ReadInt(file)
this\typeid%=ReadInt(file)
this\time#=ReadFloat(file)
this\springlets%=ReadInt(file)
this\frames%=ReadInt(file)
this\springletpointer%=ReadInt(file)
this\framepointer%=ReadInt(file)
this\bank%=ReadInt(file)
Return this
End Function
Function bvhframesetWrite(file,this.bvhframeset)
WriteInt(file,this\id%)
WriteInt(file,this\typeid%)
WriteFloat(file,this\time#)
WriteInt(file,this\springlets%)
WriteInt(file,this\frames%)
WriteInt(file,this\springletpointer%)
WriteInt(file,this\framepointer%)
WriteInt(file,this\bank%)
End Function
Function bvhframesetSave(filename$="Default")
file=WriteFile(filename$+".bvhframeset")
For this.bvhframeset= Each bvhframeset
bvhframesetWrite(file,this)
Next
CloseFile(file)
End Function
Function bvhframesetOpen(filename$="Default")
file=ReadFile(filename+".bvhframeset")
Repeat
bvhframesetRead(file)
Until Eof(file)
CloseFile(file)
End Function
Function bvhframesetCopy.bvhframeset(this.bvhframeset)
copy.bvhframeset=New bvhframeset
copy\id%=this\id%
copy\typeid%=this\typeid%
copy\time#=this\time#
copy\springlets%=this\springlets%
copy\frames%=this\frames%
copy\springletpointer%=this\springletpointer%
copy\framepointer%=this\framepointer%
copy\bank%=this\bank%
Return copy
End Function
Function bvhframesetMimic(mimic.bvhframeset,this.bvhframeset)
mimic\id%=this\id%
mimic\typeid%=this\typeid%
mimic\time#=this\time#
mimic\springlets%=this\springlets%
mimic\frames%=this\frames%
mimic\springletpointer%=this\springletpointer%
mimic\framepointer%=this\framepointer%
mimic\bank%=this\bank%
End Function
Function bvhframesetCreate.bvhframeset(typeid%,time#,springlets%,frames%,springletpointer%,framepointer%,bank%)
this.bvhframeset=bvhframesetNew()
this\typeid%=typeid%
this\time#=time#
this\springlets%=springlets%
this\frames%=frames%
this\springletpointer%=springletpointer%
this\framepointer%=framepointer%
this\bank%=bank%
Return this
End Function
Function bvhFrameSetLoad.bvhFrameSet(filename$,typeid=0)
filename$=filename$+".bvh"
file%=ReadFile(filename$)
If file% ;File Exist then process else exit
this.bvhframeset=bvhframesetNew() ;create new BVH FrameSet
this\typeid%=typeid%
Repeat
Select Upper(parseword$(file%,33,125))
Case "ROOT","JOINT"
this\springlets%=this\springlets%+1
;DebugLog parseword$(file%,33,125);name
Case "MOTION"
;FRAMES
If Upper(parseword$(file%,33,125))="FRAMES:" this\frames%=parseword$(file%,48,57)
;create bank
this\bank=CreateBank(((this\springlets%+1)*12)*this\frames%)
;FRAME TIME
keyword$=Upper(parseword$(file%,33,122)) ;skip word FRAME
If Upper(parseword$(file%,33,122))="TIME:" this\time#=parseword$(file%,45,57) ;store word in dummy
;springlet CHANNEL DATA
Repeat
PokeFloat(this\bank%,offset%,parseword$(file%,45,57))
offset%=offset%+4
Until Eof(file)
End Select
Until Eof(file%)
CloseFile(file%)
Return this
EndIf
End Function
;============================
;SPRINGLINGFRAMESET
;============================
Const SPRINGLINGFRAMESET_MAX=256
Dim springlingframesetID.springlingframeset(SPRINGLINGFRAMESET_MAX)
Global springlingframesetIndex.stack=stackCreateIndex(4,SPRINGLINGFRAMESET_MAX,1)
Type springlingframeset
Field id%
Field typeid%
Field springlets%
Field frames%
Field springletpointer%
Field framepointer%
Field bank%
End Type
Function springlingframesetNew.springlingframeset()
this.springlingframeset=New springlingframeset
this\id%=0
this\typeid%=0
this\springlets%=0
this\frames%=0
this\springletpointer%=0
this\framepointer%=0
this\bank%=0
this\id%=StackPop(springlingframesetIndex.stack,1)
springlingframesetID(this\id)=this
Return this
End Function
Function SpringlingFrameSetSave(filename$,springling.springling,bvhframeset.bvhframeset)
file%=WriteFile(filename$+".springletframeset")
DebugLog "Writing "+filename$+".springletframeset"
;springling.springlingframeset=springlingframesetNew() ;create new BVH FrameSet
;springling\typeid%=typeid%
;springling\bank=CreateBank(BankSize(bvhframeset\bank%))
WriteInt(file%,BankSize(bvhframeset\bank%))
WriteShort(file%,bvhframeset\springlets%)
WriteShort(file%,bvhframeset\frames%)
For frame = 0 To bvhframeset\frames%-1
;increment frameset frame pointer
bvhframeset\framepointer%=((bvhframeset\springlets%+1)*12)*frame%
;ROOT
springlet%=1
PositionEntity springling\springlet[springlet%]\entity%,PeekFloat(bvhframeset\bank%,bvhframeset\framepointer+springling\springlet[springlet]\channeltypeid[1]),PeekFloat(bvhframeset\bank,bvhframeset\framepointer+springling\springlet[springlet]\channeltypeid[2]),PeekFloat(bvhframeset\bank%,bvhframeset\framepointer%+springling\springlet[springlet]\channeltypeid%[3])
RotateEntity springling\springlet[springlet%]\entity%,PeekFloat(bvhframeset\bank%,bvhframeset\framepointer+springling\springlet[springlet]\channeltypeid[4]+12),PeekFloat(bvhframeset\bank,bvhframeset\framepointer+springling\springlet[springlet]\channeltypeid[5]+12),PeekFloat(bvhframeset\bank%,bvhframeset\framepointer%+springling\springlet[springlet]\channeltypeid%[6]+12)
;Write to file
WriteFloat(file%,EntityX(springling\springlet[springlet%]\entity%,True))
WriteFloat(file%,EntityY(springling\springlet[springlet%]\entity%,True))
WriteFloat(file%,EntityZ(springling\springlet[springlet%]\entity%,True))
For loop = 24 To bvhframeset\springlets%*12 Step 12
;springlets
springlet%=springlet%+1
RotateEntity springling\springlet[springlet%]\entity%,PeekFloat(bvhframeset\bank%,bvhframeset\framepointer%+loop%+springling\springlet[springlet]\channeltypeid%[1]),PeekFloat(bvhframeset\bank,bvhframeset\framepointer+loop+springling\springlet[springlet]\channeltypeid[2]),PeekFloat(bvhframeset\bank,bvhframeset\framepointer%+loop%+springling\springlet[springlet%]\channeltypeid%[3])
WriteFloat(file%,EntityX(springling\springlet[springlet%]\entity%,True))
WriteFloat(file%,EntityY(springling\springlet[springlet%]\entity%,True))
WriteFloat(file%,EntityZ(springling\springlet[springlet%]\entity%,True))
Next
Next
CloseFile(file%)
;Return springling
End Function
Function SpringlingFrameSetLoad.springlingframeset(filename$,springling.springling)
file%=ReadFile(filename$+".springletframeset")
DebugLog "Reading "+filename$+".springletframeset"
this.springlingframeset=springlingframesetNew() ;create new springling FrameSet
this\bank=CreateBank(ReadInt(file%))
this\springlets%=ReadShort(file%)
this\frames%=ReadShort(file%)
Repeat
PokeFloat(this\bank%,offset%,ReadFloat(file))
offset%=offset%+4
Until Eof(file)
CloseFile(file%)
Return this
End Function
;============================
;SPRINGLET
;============================
Type springlet ;verlet+spring = springlet v2
Field typeid%
Field entity
Field parent.springlet
Field name$
Field open
Field channels
Field channeltypeid[6]
Field position.vector ;current position and offset; restlength = distance
Field angle.vector
Field old.vector; previous positions
Field velocity.vector; position velocity
Field force.vector
Field mass#; mass
Field timestep#;
End Type
Function springletNew.springlet()
this.springlet=New springlet
this\typeid%=0
this\entity%=0
this\parent.springlet=Null
this\name$=""
this\open%=0
this\channels%=0
this\position.vector=vectorNew()
this\angle.vector=vectorNew()
this\old.vector=vectorNew()
this\velocity.vector=vectorNew()
this\force.vector =vectorNew()
this\mass#=0.0
this\timestep#=0.0
Return this
End Function
Function springletDelete(this.springlet)
this\timestep#=0.0
this\mass#=0.0
vectorDelete(this\force.vector )
vectorDelete(this\velocity.vector)
vectorDelete(this\old.vector)
vectorDelete(this\angle.vector)
vectorDelete(this\position.vector)
this\name$=""
springletDelete(this\parent.springlet)
FreeEntity this\entity%
Delete this
End Function
Function springletRead.springlet(file)
this.springlet=New springlet
this\typeid%=ReadInt(file)
this\entity%=ReadInt(file)
this\parent.springlet=springletRead(file)
this\name$=ReadLine(file)
this\open%=ReadInt(file)
this\channels%=ReadInt(file)
For loop=1 To 6:this\channeltypeid[loop]=ReadByte(file):Next
this\position.vector=vectorRead(file)
this\angle.vector=vectorRead(file)
this\old.vector=vectorRead(file)
this\velocity.vector=vectorRead(file)
this\force.vector=vectorRead(file)
this\mass#=ReadFloat(file)
this\timestep#=ReadFloat(file)
Return this
End Function
Function springletWrite(file,this.springlet)
WriteInt(file,this\typeid%)
WriteInt(file,this\entity%)
springletWrite(file,this\parent.springlet)
WriteLine(file,this\name$)
WriteInt(file,this\open%)
WriteInt(file,this\channels%)
For loop=1 To 6:WriteByte(file,this\channeltypeid[loop]):Next
vectorWrite(file,this\position.vector)
vectorWrite(file,this\angle.vector)
vectorWrite(file,this\old.vector)
vectorWrite(file,this\velocity.vector)
vectorWrite(file,this\force.vector )
WriteFloat(file,this\mass#)
WriteFloat(file,this\timestep#)
End Function
;============================
;SPRINGLETANCHOR
;============================
Type springletanchor
Field position.vector;
Field springlet.springlet
End Type
Function springletanchorNew.springletanchor()
this.springletanchor=New springletanchor
;this\springlet.springlet=springletNew()
this\position.vector=vectorNew()
Return this
End Function
Function springletanchorRead.springletanchor(file)
this.springletanchor=New springletanchor
this\position.vector=vectorRead(file)
this\springlet.springlet=springletRead(file)
Return this
End Function
Function springletanchorWrite(file,this.springletanchor)
vectorWrite(file,this\position.vector)
springletWrite(file,this\springlet.springlet)
End Function
;============================
;SPRINGLETCONSTRAINT
;============================
Type springletconstraint
Field springlet.springlet
Field neighbors%;
Field neighbor.springlet[SPRINGLING_MAX_NEIGHBORS%];
Field neighbordistance#[SPRINGLING_MAX_NEIGHBORS%];restlength#
End Type
Function springletconstraintCreate.springletconstraint(springlet1.springlet,springlet2.springlet,restlength#)
this.springletconstraint=New springletconstraint
this\springlet.springlet=springlet1
this\neighbors%=1
this\neighbor[this\neighbors%]=springlet2
this\neighbordistance#[this\neighbors%]=restlength#*restlength#
Return this
End Function
Function springletconstraintRead.springletconstraint(file)
this.springletconstraint=New springletconstraint
this\neighbors%=ReadInt(file)
For loop=1 To 128:this\neighbor.springlet[loop]=springletRead(file):Next
For loop=1 To 128:this\neighbordistance#[loop]=ReadFloat(file):Next
Return this
End Function
Function springletconstraintWrite(file,this.springletconstraint)
WriteInt(file,this\neighbors%)
For loop=1 To 128:springletWrite(file,this\neighbor.springlet[loop]):Next
For loop=1 To 128:WriteFloat(file,this\neighbordistance#[loop]):Next
End Function
;====================
;SPRINGLING
;====================
;Advance Character Physics, <a href="http://www.gamasutra.com/resource_guide/20030121/jacobson_pfv.htm" target="_blank">http://www.gamasutra.com/resource_guide/20030121/jacobson_pfv.htm</a>
;Exploring Spring Models, <a href="http://www.gamasutra.com/features/20011005/oliveira_01.htm" target="_blank">http://www.gamasutra.com/features/20011005/oliveira_01.htm</a>
Global SPRINGLING_MAX%=256
Dim springlingID.springling(SPRINGLING_MAX%)
Global springlingIndex.stack=stackCreateIndex(4,SPRINGLING_MAX%,1)
Type springling
Field id%
Field typeid%
Field springletpivot.springlet;central pivot connects to entity
Field springlets%;
Field springlet.springlet[SPRINGLING_MAX_SPRINGLETS]; ;array of springling springlets
Field springletanchors%;
Field springletanchor.springletanchor[SPRINGLING_MAX_ANCHOR_SPRINGLETS]; ;stability debug
Field springletconstraints%
Field springletconstraint.springletconstraint[SPRINGLING_MAX_CONSTRIANTS]
Field k_coef#;
Field energyloss#;
Field mass#;
Field tolerance#;
Field iterations%
Field gravity.vector ;local gravity
End Type
Function springlingNew.springling()
this.springling=New springling
this\gravity.vector=vectorNew()
this\id%=0
this\typeid%=0
this\springlets%=0
this\iterations%=1
this\id%=StackPop(springlingIndex.stack,1)
springlingID(this\id)=this
Return this
End Function
Function springlingDelete(this.springling)
springlingID(this\id)=Null
StackPush(springlingIndex.stack,this\id%,1)
;For loop = 1 To 256
; If this\springlet[loop]<>Null springletdelete(this\springlet[loop])
;Next
Delete this
End Function
Function springlingRead.springling(file)
this.springling=New springling
this\id%=ReadInt(file)
this\typeid%=ReadInt(file)
this\springlets%=ReadInt(file)
For loop=1 To 128:this\springlet.springlet[loop]=springletRead(file):Next
this\springletanchors%=ReadInt(file)
For loop=1 To 128:this\springletanchor.springletanchor[loop]=springletanchorRead(file):Next
this\springletconstraints%=ReadInt(file)
For loop=1 To 128:this\springletconstraint.springletconstraint[loop]=springletconstraintRead(file):Next
this\k_coef#=ReadFloat(file)
this\energyloss#=ReadFloat(file)
this\mass#=ReadFloat(file)
this\tolerance#=ReadFloat(file)
this\iterations%=ReadInt(file)
this\gravity.vector=vectorRead(file)
Return this
End Function
Function springlingWrite(file,this.springling)
WriteInt(file,this\id%)
WriteInt(file,this\typeid%)
WriteInt(file,this\springlets%)
For loop=1 To 128:springletWrite(file,this\springlet.springlet[loop]):Next
WriteInt(file,this\springletanchors%)
For loop=1 To 128:springletanchorWrite(file,this\springletanchor.springletanchor[loop]):Next
WriteInt(file,this\springletconstraints%)
For loop=1 To 128:springletconstraintWrite(file,this\springletconstraint.springletconstraint[loop]):Next
WriteFloat(file,this\k_coef#)
WriteFloat(file,this\energyloss#)
WriteFloat(file,this\mass#)
WriteFloat(file,this\tolerance#)
WriteInt(file,this\iterations%)
vectorWrite(file,this\gravity.vector)
End Function
;----------------------------
;SPRINGLING ANIMATION
;----------------------------
Function springlingbvhLoad.springling(filename$)
file%=ReadFile(filename$+".bvh")
If file%
;creatE skeleton
this.springling=springlingnew()
Repeat ;iterate through data til "HIERARCHY"
keyword$=Upper(parseword$(file%,33,125));get word
Select keyword$
Case "ROOT","JOINT","END"
this\springlets%=this\springlets%+1;inc springlet ct
this\springlet[this\springlets%]=springletNew()
this\springlet[this\springlets%]\entity%=CreatePivot()
this\springlet[this\springlets%]\typeid%=Len(keyword$)-4 ;0=root, 1=springlet, -1=end
;If this\springlet[this\springlets%]\typeid%=0 Root.springlet=springlet.springlet ;root springlet
this\springlet[this\springlets%]\name$=parseword$(file%,32,123);name
;testing
;DebugLog "Reading "+keyword$+" "+this\springlet[this\springlets%]\name$
NameEntity this\springlet[this\springlets%]\entity%,this\springlet[this\springlets%]\name$
this\springlet[this\springlets%]\mass#=1.0
this\springlet[this\springlets%]\timestep#=.1
Case "OFFSET"
;replaced offset with position
this\springlet[this\springlets%]\position\x#=parseword$(file%,45,57)
this\springlet[this\springlets%]\position\y#=parseword$(file%,45,57)
this\springlet[this\springlets%]\position\z#=parseword$(file%,45,57)
Case "CHANNELS"
this\springlet[this\springlets%]\channels=parseword$(file%,46,57)
;parse channel Types
For loop=1 To this\springlet[this\springlets%]\channels
Select Upper(parseword$(file%,65,122))
Case "XPOSITION" this\springlet[this\springlets%]\channeltypeid[loop]=0
Case "YPOSITION" this\springlet[this\springlets%]\channeltypeid[loop]=4
Case "ZPOSITION" this\springlet[this\springlets%]\channeltypeid[loop]=8
Case "XROTATION" this\springlet[this\springlets%]\channeltypeid[loop]=0
Case "YROTATION" this\springlet[this\springlets%]\channeltypeid[loop]=4
Case "ZROTATION" this\springlet[this\springlets%]\channeltypeid[loop]=8
End Select
Next
;order
Restore bvhRotationOrder
Read channel1%,channel2%,channel3%,x%,y%,z%
For loop = 1 To 2
If this\springlet[this\springlets%]\channeltypeid[1]=channel1% And this\springlet[this\springlets%]\channeltypeid[2]=channel2% And this\springlet[this\springlets%]\channeltypeid[3]=channel3%
this\springlet[this\springlets%]\channeltypeid[1]=x%
this\springlet[this\springlets%]\channeltypeid[2]=y%
this\springlet[this\springlets%]\channeltypeid[3]=z%
EndIf
If this\springlet[this\springlets%]\channeltypeid[4]=channel1 And this\springlet[this\springlets%]\channeltypeid[5]=channel2 And this\springlet[this\springlets%]\channeltypeid[6]=channel3
this\springlet[this\springlets%]\channeltypeid[4]=x%
this\springlet[this\springlets%]\channeltypeid[5]=y%
this\springlet[this\springlets%]\channeltypeid[6]=z%
EndIf
Next
Case "{"
this\springlet[this\springlets%]\open=True ;open position springlet hieararchy
;locate parentspringlet by transversing springlet hieararchy backwards Until parent (open springlet) is found
Parentspringlet.springlet=this\springlet[this\springlets%] ;make parentspringlet equal to position springlet
Repeat
If Not Parentspringlet=First springlet Parentspringlet=Before Parentspringlet ;if typeid not equal to root then tranverse hieararchy
If Parentspringlet\Open this\springlet[this\springlets%]\Parent=Parentspringlet
Until Parentspringlet\Open
Case "}"
this\springlet[this\springlets%]\Open=False ;close position springlet
;Find Parentspringlet
For loop = 1 To this\springlets%
If this\springlet[loop]=this\springlet[this\springlets%]\parent.springlet
this\springlet[this\springlets%]=this\springlet[loop] ;make parentspringlet position springlet
Exit
EndIf
Next
End Select
Until keyword$="MOTION"
CloseFile(file%);close file
EndIf
;correct end sites, duplicates
springling2.springling=springlingNew()
For loop=1 To this\springlets%
duplicate=False
For loop2=1 To springling2\springlets
If this\springlet[loop]\name$=springling2\springlet[loop2]\name$
duplicate=True
Exit
EndIf
Next
If Not duplicate
springling2\springlets%=springling2\springlets%+1
springling2\springlet[springling2\springlets%]=this\springlet[loop]
If loop>1
springling2\springletconstraints%=springling2\springletconstraints%+1
springling2\springletconstraint[springling2\springletconstraints%]=springletconstraintCreate(springling2\springlet[springling2\springlets%],springling2\springlet[springling2\springlets%]\parent,vectorAbsHigher#(springling2\springlet[springling2\springlets%]\position))
EntityParent(springling2\springlet[springling2\springlets%]\entity,springling2\springlet[springling2\springlets%]\parent\entity)
EndIf
EndIf
Next
For loop = 1 To springling2\springlets%
TranslateEntity springling2\springlet[loop]\entity,springling2\springlet[loop]\position\x#,springling2\springlet[loop]\position\y#,springling2\springlet[loop]\position\z#
Next
springlingDelete(this)
;adjust pointers
springling2\tolerance#=0.0000000005
springling2\k_coef#=.30;
springling2\energyloss#=.75;
springling2\mass#=1.0;
springling2\gravity\y#=-1.5;global gravity modifier
Return springling2
End Function
Function springlingBind(this.springling,parent%)
children%=CountChildren(parent%)
For loop = 1 To children%
child%=GetChild (parent%,loop)
name$=EntityName$(child%)
DebugLog name$
;bind
For loop1 = 1 To this\springlets
If name$=this\springlet[loop1]\name$
;DebugLog "Child:"+name$+" binded to Skeleton:"+this\springlet[loop1]\name$
this\springlet[loop1]\entity=child%
EndIf
Next
springlingBind(this,child%)
Next
End Function
Function springlingBVHAnimateNext(this.springling,bvhframesetIndex%,frame%)
;increment frameset frame pointer
;this.springling=First springling;(this\skeletonid)testing
bvhframeset.bvhframeset=bvhframesetID(bvhframesetIndex)
bvhframeset\framepointer=((bvhframeset\springlets+1)*12)*frame%
;ROOT
springlet%=1
PositionEntity this\springlet[springlet%]\entity%,PeekFloat(bvhframeset\bank,bvhframeset\framepointer+this\springlet[springlet]\channeltypeid[1]),PeekFloat(bvhframeset\bank,bvhframeset\framepointer+this\springlet[springlet]\channeltypeid[2]),PeekFloat(bvhframeset\bank,bvhframeset\framepointer+this\springlet[springlet]\channeltypeid[3])
RotateEntity this\springlet[springlet%]\entity%,PeekFloat(bvhframeset\bank,bvhframeset\framepointer+this\springlet[springlet]\channeltypeid[4]+12),PeekFloat(bvhframeset\bank,bvhframeset\framepointer+this\springlet[springlet]\channeltypeid[5]+12),PeekFloat(bvhframeset\bank,bvhframeset\framepointer+this\springlet[springlet]\channeltypeid[6]+12)
this\springlet[springlet%]\position\x#=EntityX(this\springlet[springlet%]\entity%,True)
this\springlet[springlet%]\position\y#=EntityY(this\springlet[springlet%]\entity%,True)
this\springlet[springlet%]\position\z#=EntityZ(this\springlet[springlet%]\entity%,True)
For loop = 24 To bvhframeset\springlets%*12 Step 12
;springlets
springlet%=springlet%+1
RotateEntity this\springlet[springlet%]\entity%,PeekFloat(bvhframeset\bank,bvhframeset\framepointer+loop+this\springlet[springlet]\channeltypeid[1]),PeekFloat(bvhframeset\bank,bvhframeset\framepointer+loop+this\springlet[springlet]\channeltypeid[2]),PeekFloat(bvhframeset\bank,bvhframeset\framepointer+loop+this\springlet[springlet]\channeltypeid[3])
this\springlet[springlet%]\position\x#=EntityX(this\springlet[springlet%]\entity%,True)
this\springlet[springlet%]\position\y#=EntityY(this\springlet[springlet%]\entity%,True)
this\springlet[springlet%]\position\z#=EntityZ(this\springlet[springlet%]\entity%,True)
Next
End Function
Function springlingAnimateNext(this.springling,springlingframesetIndex%,frame%)
;increment frameset frame pointer
springlingframeset.springlingframeset=springlingframesetID(springlingframesetIndex)
springlingframeset\framepointer=((springlingframeset\springlets)*12)*frame%
For loop = 0 To (springlingframeset\springlets-1)*12 Step 12
springlet%=springlet%+1
vectorMimic(this\springlet[springlet%]\old,this\springlet[springlet%]\position)
this\springlet[springlet%]\position\x#=PeekFloat(springlingframeset\bank,springlingframeset\framepointer+loop)
this\springlet[springlet%]\position\y#=PeekFloat(springlingframeset\bank,springlingframeset\framepointer+loop+4)
this\springlet[springlet%]\position\z#=PeekFloat(springlingframeset\bank,springlingframeset\framepointer+loop+8)
Next
End Function
;----------------------------
;SPRINGLING VERLET PHYICS
;----------------------------
Function springlingVerletCreate.springling(springlets,x#,y#,z#)
this.springling=springlingNew()
this\springlets=springlets
For i=1 To this\springlets
this\springlet.springlet[i]=springletNew()
this\springlet[i]\position\x#=x#
this\springlet[i]\position\y#=y#
this\springlet[i]\position\z#=z#
this\springlet[i]\mass#=1.0
this\springlet[i]\timestep#=.1
Next
vectorSet(this\gravity,0,-1.5,0)
Return this
End Function
;springlet verlet integration Step
Function springlingVerletIntegrator(this.springling)
For i=1 To this\springlets
;temp=old
vectorMimic(springlettempvector,this\springlet[i]\position)
;x = (x+(x-oldx)) + (a*fTimeStep#*fTimeStep#) ;a=F/m acceleration=Force/mass
vectorAdd(vectorAdd(this\springlet[i]\position,vectorSubtract2(springletpositionvector,this\springlet[i]\position,this\springlet[i]\old)),vectorScalarMultiply(this\springlet[i]\force,this\springlet[i]\timestep#*this\springlet[i]\timestep#))
;oldx=temp
vectorMimic(this\springlet[i]\old,springlettempvector);
Next
End Function
; This Function should accumulate forces For Each springlet
Function springlingVerletAccumulateForces(this.springling)
; All springlets are influenced by gravity
For i=1 To this\springlets
vectorMimic(this\springlet[i]\force,this\gravity);this\springlet[i]\gravity)
Next
End Function
; Here springletconstraints should be satisfied
Function springlingVerletSatisfyConstraints(this.springling)
For j=1 To this\iterations%
;C1
For loop=1 To this\springlets
this\springlet[loop]\position=vectorScalarMin(vectorScalarMax(this\springlet[loop]\position,100),0);
Next
For loop=1 To this\springletconstraints%
For loop1= 1 To this\springletconstraint[this\springletconstraints%]\neighbors%
;C2
;Pseudo-code For satisfying (C2) using sqrt approximation
;delta = x2-x1;
vectorSubtract2(springletdeltavector,this\springletconstraint[loop]\neighbor[loop1]\position,this\springletconstraint[loop]\springlet\position)
;delta = delta * restlength*restlength/(dotproduct(delta)+restlength*restlength)-0.5;
;Note that delta is a vector so delta*delta is actually a dot product. With restlength=100 the above pseudo-code will push apart Or pull together the springlets such that they once more attain the correct distance of 100 between them. Again we may think of the situation as If a very stiff spring with rest length 100 has been inserted between the springlets such that they are instantly placed correctly.
;restlength#=restlength#^2
vectorScalarMultiply(springletdeltavector,this\springletconstraint[loop]\neighbordistance#[loop1]/(vectorDotProduct(springletdeltavector,springletdeltavector)+this\springletconstraint[loop]\neighbordistance#[loop1])-0.5)
;x1 -= delta;
vectorSubtract(this\springletconstraint[loop]\springlet\position,springletdeltavector)
;x2 += delta;
vectorAdd(this\springletconstraint[loop]\neighbor[loop1]\position,springletdeltavector)
Next
Next
Next
End Function
Function springlingVerletTimeStep(this.springling)
springlingVerletAccumulateForces(this);
springlingVerletIntegrator(this);
springlingVerletSatisfyConstraints(this);
End Function
;----------------------------
;SPRINGLING SPRING PHYICS
;----------------------------
Function springlingSpringStringCreate.springling(distance#, springlets%, k_coef#, energyloss#, mass#, gravity#)
;If ((distance# < 0.005) Or (springlets% < 3)) Return Null
this.springling=springlingNew();
;adjust pointers
this\tolerance#=0.0000000005
this\k_coef#=k_coef#;
this\energyloss#=energyloss#;
this\mass#=mass#;
this\springlets%=springlets%
this\gravity\y#=gravity#;global gravity modifier
;setup springlets position aligned with the xz+axis
For loop=1 To springlets
this\springlet.springlet[loop]=springletNew()
this\springlet[loop]\position\x#=distance#*loop;
this\springlet[loop]\timestep#=.1
Next
;connect springlets And setup the inertial x# distances
;far Left springletconstraints
this\springletconstraints%=this\springletconstraints%+1
this\springletconstraint[this\springletconstraints%]=springletconstraintCreate(this\springlet[1],this\springlet[2],distance#)
;inner springletconstraint
For loop=2 To springlets-1
this\springletconstraints%=this\springletconstraints%+1
this\springletconstraint[this\springletconstraints%]=New springletconstraint
this\springletconstraint[this\springletconstraints%]\springlet=this\springlet[loop]
;connect To the previous
this\springletconstraint[this\springletconstraints%]\neighbor[1]=this\springlet[loop-1];
this\springletconstraint[this\springletconstraints%]\neighbordistance#[1]=distance#;
;connect To the Next
this\springletconstraint[this\springletconstraints%]\neighbor[2]=this\springlet[loop+1];
this\springletconstraint[this\springletconstraints%]\neighbordistance#[2]=distance#;
this\springletconstraint[this\springletconstraints%]\neighbors%=this\springletconstraint[this\springletconstraints%]\neighbors%+2;
Next
;far Right springletconstraint
this\springletconstraints%=this\springletconstraints%+1
this\springletconstraint[this\springletconstraints%]=springletconstraintCreate(this\springlet[springlets],this\springlet[springlets-1],distance#)
; setup springletanchor springlet, Right springlet is the only springletanchor
this\springletanchor.springletanchor[1]=springletanchorNew()
this\springletanchor[1]\springlet.springlet=this\springlet[1]
this\springletanchor[1]\position\x#=this\springlet[1]\position\x#;
this\springletanchors%=this\springletanchors%+1
Return this;
End Function
Function springlingSpringComputeSingleForce(this.springling, force.vector, pa.vector, pb.vector, k#, delta_distance#)
;get the distance
vectorSubtract2(springletdeltavector,pb,pa)
distance#=Sqr(vectorDotProduct(springletdeltavector,springletdeltavector));
If distance# < this\tolerance#
vectorReset(force)
Return;
EndIf
vectorMimic(springletforcedirection,springletdeltavector)
;normalize
vectorScalarDivide(springletforcedirection,distance#)
;store
vectorScalarMultiply2(force,springletforcedirection,k*distance#-delta_distance#);force & intensity#
End Function
Function springlingSpringAccumulateForces(this.springling)
;accumulate all forces
For loop=1 To this\springletconstraints%
;Null out springletresultant
vectorReset(springletresultant)
For loop1=1 To this\springletconstraint[loop]\neighbors%
vectorMimic(this\springlet[loop]\old,this\springlet[loop]\position)
springlingSpringComputeSingleForce(this,springlettempvector,this\springletconstraint[loop]\springlet\position,this\springletconstraint[loop]\neighbor[loop1]\position,this\k_coef#,this\springletconstraint[loop]\neighbordistance#[loop1]);
VectorAdd(springletresultant,springlettempvector);
Next
vectorMimic(this\springletconstraint[loop]\springlet\force,springletresultant)
Next
End Function
Function springlingSpringApplyForces(this.springling)
vectorReset(springletaccumulator)
;apply resultant forces To increase velocity of Each springling
For loop=1 To this\springlets
vectorAdd2(springletaccumulator,this\springlet[loop]\force,this\gravity)
;vectorScalarDivide(springletaccumulator,this\mass) ;mass is in somehow unecessary
vectorAdd(this\springlet[loop]\velocity,springletaccumulator)
vectorAdd(this\springlet[loop]\position,this\springlet[loop]\velocity)
;energy loss For velocity
vectorScalarMultiply(this\springlet[loop]\velocity,this\energyloss#)
Next
End Function
Function springlingSpringAnchorCheck(this.springling)
For loop=1 To this\springletanchors%
If this\springletanchor[loop]\springlet\position\x#<>this\springletanchor[loop]\position\x# this\springletanchor[loop]\springlet\position\x#=this\springletanchor[loop]\position\x#
If this\springletanchor[loop]\springlet\position\y#<>this\springletanchor[loop]\position\y# this\springletanchor[loop]\springlet\position\y#=this\springletanchor[loop]\position\y#
If this\springletanchor[loop]\springlet\position\z#<>this\springletanchor[loop]\position\z# this\springletanchor[loop]\springlet\position\z#=this\springletanchor[loop]\position\z#
Next
;for loop=1 to this\springlets%
;if this\springlet[loop]=anchor type vectorMimic(springlet[loop]\position,springlet[loop]\old)
;next
End Function
Function springlingSpringTimeStep(this.springling)
springlingSpringAccumulateForces(this);
springlingSpringApplyForces(this);
springlingSpringAnchorCheck(this);
End Function
;============================
;MAN
;============================
Global MAN_MAX%=256
Dim manID.man(MAN_MAX%)
Global manIndex.stack=stackCreateIndex(4,MAN_MAX%,1)
Type man
Field id%
Field typeid%
Field bvhframesetId%
Field bvhframe%
Field lod.lod
Field position.vector
Field angle.vector
End Type
Function manStart.man(filename$="Default")
;load from config
manopen(filename$)
;setup
For this.man=Each man
Next
Return First man
End Function
Function manStop()
For this.man=Each man
manDelete(this)
Next
End Function
Function manNew.man()
this.man=New man
this\id%=0
this\typeid%=0
this\bvhframe%=0
this\lod.lod=lodNew()
this\position.vector=vectorNew()
this\angle.vector=vectorNew()
this\id%=StackPop(manIndex.stack,1)
manID(this\id)=this
Return this
End Function
Function manDelete(this.man)
manID(this\id)=Null
StackPush(manIndex.stack,this\id%,1)
vectorDelete(this\angle.vector)
vectorDelete(this\position.vector)
lodDelete(this\lod.lod)
Delete this
End Function
Function manManager()
For this.man=Each man
Next
End Function
Function manRead.man(file)
this.man=New man
this\id%=ReadInt(file)
this\typeid%=ReadInt(file)
this\bvhframe%=ReadInt(file)
this\lod.lod=lodRead(file)
this\position.vector=vectorRead(file)
this\angle.vector=vectorRead(file)
Return this
End Function
Function manWrite(file,this.man)
WriteInt(file,this\id%)
WriteInt(file,this\typeid%)
WriteInt(file,this\bvhframe%)
lodWrite(file,this\lod.lod)
vectorWrite(file,this\position.vector)
vectorWrite(file,this\angle.vector)
End Function
Function manSave(filename$="Default")
file=WriteFile(filename$+".man")
For this.man= Each man
manWrite(file,this)
Next
CloseFile(file)
End Function
Function manOpen(filename$="Default")
file=ReadFile(filename+".man")
Repeat
manRead(file)
Until Eof(file)
CloseFile(file)
End Function
Function manCopy.man(this.man)
copy.man=New man
copy\id%=this\id%
copy\typeid%=this\typeid%
copy\bvhframe%=this\bvhframe%
copy\lod.lod=lodCopy(this\lod.lod)
copy\position.vector=vectorCopy(this\position.vector)
copy\angle.vector=vectorCopy(this\angle.vector)
Return copy
End Function
Function manMimic(mimic.man,this.man)
mimic\id%=this\id%
mimic\typeid%=this\typeid%
mimic\bvhframe%=this\bvhframe%
lodMimic(mimic\lod.lod,this\lod.lod)
vectorMimic(mimic\position.vector,this\position.vector)
vectorMimic(mimic\angle.vector,this\angle.vector)
End Function
Function manCreate.man(id%,typeid%,bvhframe%,lod.lod,position.vector,angle.vector)
this.man=manNew()
this\id%=id%
this\typeid%=typeid%
this\bvhframe%=bvhframe%
this\lod.lod=lod.lod
this\position.vector=position.vector
this\angle.vector=angle.vector
Return this
End Function
Function parseword$(file%,min%=33,max%=125) ;ascii character range min=33, max=125
If file%
Repeat
byte%=ReadByte(file%); byte
char$=Chr$(byte%); char
If byte%>=min% And byte%<=max%
word$=word$+char$ ;word
charct%=charct%+1 ;inc charct, count characters valid after first character in range has be accounted for
Else
If charct%>0
;DebugLog word$
Return word$
EndIf
EndIf
Until Eof(file%)=True
If charct>0
;DebugLog word$
Return word$
EndIf
EndIf
End Function
Function vectorAbsHigher#(this.vector)
n#=Abs(this\x#)
If Abs(this\y#)>n# n#=Abs(this\y#)
If Abs(this\z#)>n# n#=Abs(this\z#)
Return n#
End Function
.bvhRotationOrder
;0=x,4=y,8=z
Data 8,0,4,4,8,0;zxy
Data 4,8,0,8,0,4;yzx
Data 8,4,0,8,4,0;zyx
Data 4,0,8,4,0,8;yxz
Data 0,4,8,0,4,8;xyz
Data 0,8,4,0,8,4;xzyIt would be nice to see a high performance physics system made with Blitz3D.