This was my first attempt at one for vivid, based off's mark's dump-file.
It works on static and anims, you just have to convert the parts that feed that data into banks into the equivilent b3d func(I.e instead of poking verts into bank cverts, acctually add verts to a b3d mesh.
Sorry, it's a bit messy, but bear in mind I was butchering up someone elses code as a prototype ;) (Hence it being pd too)
Function glLoadB3dfile(file$,uvSets=2,parent=0);internal function
fS=ReadFile(file)
texc=0
name$=file
lent.ent=Null
l=Len(name)
found=False
For j=l To 1 Step -1
Select Mid(name,j,1)
Case "/",""
name=Mid(name,1,j)
found=True
End Select
If found Exit
Next
glStackEC=-1
glStackSC=-1
;1142;-
If Not fs glerror("b3d "+file+" not found")
b3dSetFile( fs )
If b3dreadchunk$()<>"BB3D"
CloseFile fs
Return
EndIf
If b3dreadInt()/100>0
CloseFile fs
Return
EndIf
top=glReadb3dChunks("",name)
Delete Each b3dnode
If lent=Null Stop
Return Handle(lent)
End Function
Function glerror(err
Function glReadb3dChunks(tab$="",localDir$="",uvSets=2,isAnim=False) ;INTERNAL FUNCTION
tt$=tab$
tab$=tab$+" "
hLevel=hLevel(tab)
While b3dChunkSize()
chunk$=b3dReadChunk$()
;tt$=Replace(tt$," ","/")
DebugLog "Level:"+hLevel+" Chunk:"+chunk$+" (size="+b3dChunkSize()+")"
Select chunk$
Case "ANIM"
flags=b3dReadInt()
DebugLog "Animation Found:"
n_frames=b3dReadInt()
; DebugLog "Frames:"+n_frames
fps=b3dReadFloat()
; DebugLog "Fps:"+fps
lent\animFrames=n_frames
lent\animFPS=fps
;lent\root=New limb
lent\isAnim=True
;DebugLog tab$+flags+" "+n_frames+" "+fps
Case "KEYS"
flags=b3dReadInt()
sz=4
sk=0
If flags And 1 sz=sz+12
If flags And 2 sz=sz+12
If flags And 4 sz=sz+16
n_keys=b3dChunkSize()/sz
If n_keys*sz=b3dChunkSize()
DebugLog tab$+n_keys+" keys"
;Read all keys in chunk
While b3dChunkSize()
frame=b3dReadInt()
isPos=False
isScale=False
isRot=False
x#=0
y#=0
z#=0
msx#=0
msy#=0
msz#=0
rw#=0
rx#=0
ry#=0
rz#=0
If flags And 1
x#=b3dReadFloat()
y#=b3dReadFloat()
z#=b3dReadFloat()
isPos=True
EndIf
If flags And 2
msx#=b3dReadFloat()
msy#=b3dReadFloat()
msz#=b3dReadFloat()
isScale=True
EndIf
If flags And 4
rw#=b3dReadFloat()
rx#=b3dReadFloat()
ry#=b3dReadFloat()
rz#=b3dReadFloat()
isRot=True
EndIf
.boneStuff
qtt.quat=quat(rw,rx,ry,rz)
If ry>0 And sk=0
DebugLog "Limb>"+nlimb\name+" Has active frame"
sk=True
EndIf
; quatToEuler(tRot[10],qtt)
; trot[10]\pitch=trot[10]\pitch+180
; eulerToQuat(qtt,trot[10]) ;this 180 conversation is needed. Saves having to do it every frame.
kf.frame=newFrame(frame,qtt,x,y,z,msx,msy,msz,ispos,isscale,isrot)
;If qtt\y>0 DebugLog nlimb\name+" Active quat"
nlimb\frame[nlimb\fc]=kf
nlimb\fc=nlimb\fc+1
Wend
If sk=False nlimb\fc=0
Else
RuntimeError "Illegal number of animation keys"
EndIf
Case "TEXS"
While b3dChunkSize()
name$=b3dReadString$()
;first check direct link
texIn=glLoadTexture(name$,glMipMap+glCompress)
If Not texIn
l=Len(name)
found=False
For j=l To 1 Step -1
Select Mid(name,j,1)
Case "/",""
name=Mid(name,j+1)
found=True
End Select
If found Exit
Next
texIn=glLoadTexture(localdir+name$,glMipMap+glCompress)
EndIf
If texIn=0
texIn=glLoadTexture("vivid\failsafe.jpg",glMipMap+glCompressed)
; glerror("Texture "+localdir+name+" not found")
EndIf
rTex.gText=Object.gtext(texIn)
If rTex=Null RuntimeError "Critical texture error. Please report"
rtex\file=name
texA[texC]=rTex
texC=texC+1
flags=b3dReadInt()
If flags And 65536
glTextureUvSet(texIn,1)
EndIf
blend=b3dReadInt()
x_pos#=b3dReadFloat()
y_pos#=b3dReadFloat()
x_scl#=b3dReadFloat()
y_scl#=b3dReadFloat()
rot#=b3dReadFloat()
DebugLog tab$+name$
Wend
Case "BRUS"
n_texs=b3dReadInt()
If n_texs=0 Exit
;read all brushes in chunk...
; brush=glBrush()
bc=0
While b3dChunkSize()
brush=glBrush()
brushA[brushC]=brush
brushC=brushC+1
name$=b3dReadString$()
red#=b3dReadFloat()
grn#=b3dReadFloat()
blu#=b3dReadFloat()
alp#=b3dReadFloat()
glBrushColor(brush,red,grn,blu,alp)
shi#=b3dReadFloat()
blend=b3dReadInt()
fx=b3dReadInt()
For k=0 To n_texs-1
tex_id=b3dReadInt()
;DebugLog "=====Brush>"+texID>"+tex_id
If tex_id>-1
glBrushTexture(brush,Handle(texA[tex_id]))
EndIf
Next
;DebugLog tab$+"Brush>"+name$+" texs:"+n_texs
Wend
Case "VRTS"
flags=b3dReadInt()
tc_sets=b3dReadInt()
tc_size=b3dReadInt()
sz=12+tc_sets*tc_size*4
If flags And 1 Then sz=sz+12
If flags And 2 Then sz=sz+16
n_verts=b3dChunkSize()/sz
lvc=n_verts
If n_verts*sz=b3dChunkSize()
;DebugLog tab$+n_verts+" vertices"
cVerts=CreateBank((n_verts+16)*12)
If isAnim
anVerts=CreateBank((n_verts+16)*12)
Else
EndIf
;read all verts in chunk
vo=0
cNorm=CreateBank((n_verts+16)*12)
cCol=CreateBank((n_verts+16)*16)
co=0
uvSize=tc_size
For cc=0 To tc_sets
lUV[cc]=CreateBank(((12)*tc_sets)*(n_verts+16))
Next
uof=0
While b3dChunkSize()
;DebugLog "Vert >"+vert
vert=vert+1
PokeFloat cVerts,vo,b3dReadFloat()
PokeFloat cVerts,vo+4,b3dReadFloat()
PokeFloat cVerts,vo+8,b3dReadFloat()
If flags And 1
PokeFloat cNorm,vo,b3dReadFloat()
PokeFloat cNorm,vo+8,b3dReadFloat()
PokeFloat cNorm,vo+12,b3dReadFloat()
EndIf
If flags And 2
PokeFloat cCol,co,b3dReadFloat()
PokeFloat cCol,co+4,b3dReadFloat()
PokeFloat cCol,co+8,b3dReadFloat()
PokeFloat cCol,co+12,b3dReadFloat()
co=co+16
EndIf
tc_size2=12
;read tex coords...
For j=1 To tc_sets;*tc_size
If tc_size2>0
inU#= b3dReadFloat()
PokeFloat luv[j-1],uof,inu
EndIf
If tc_size2>1
inV#= b3dreadfloat()
PokeFloat luv[j-1],uof+4,inv
EndIf
If tc_Size2>2
; inQ#=b3dreadfloat()
; PokeFloat luv[j-1],uof+8,inq
EndIf
If tc_size2>3
;inW#=b3dreadfloat()
; PokeFloat luv[j-1],uof+12,inW
EndIf
Next
uof=uof+tc_size2
vo=vo+12
Wend
tmpVerts=cVerts
tmpCol=cCol
tmpNorm=cNorm
Else
DebugLog tab$+"***** Illegal number of vertices *****"
EndIf
Case "TRIS" ;surface
; If isAnim Exit;Skip as we're not using tri banks to establish surfaces.
brush_id=b3dReadInt()
sz=12
n_tris=b3dChunkSize()/sz
If n_tris<4 Exit ;skip surface
sdat.sdat=New sdat
sdat\cverts=tmpverts
sdat\ccol=tmpcol
sdat\cnorm=tmpnorm
sdat\vc=lvc
sdat\uvsets=2
For j=0 To 1
sdat\cuv[j]=luv[j]
Next
sdat\ctris=CreateBank((n_tris+1000)*12)
lent\sdat[lent\sc]=sdat
lent\sc=lent\sc+1
sdat\tc=n_tris*2
; "NEW SURFACE!!!!!!"
If n_tris<1
Else
DebugLog n_tris+"< tris"
EndIf
glLockSurface(Handle(sdat)) ;not as fast as direct, but is future proof.
If n_tris*sz=b3dChunkSize()
;DebugLog tab$+n_tris+" triangles"
;read all tris in chunk
While b3dChunkSize()
v0=b3dReadInt()
v1=b3dReadInt()
v2=b3dReadInt()
glTriangle(v0,v1,v2)
Wend
Else
DebugLog tab$+"***** Illegal number of triangles *****"
EndIf
If brush_id>0 And brush_id<brushC
glPaintBrushSurface(brushA[brush_id])
;DebugLog "BRUSH TO SURFACE!"
EndIf
Case "MESH"
brush_id=b3dReadInt()
;DebugLog tab$+"brush="+brush_id
; If b3dNC=0 RuntimeError "Fatal .b3d loader error. Please report."
;b3dNS[b3dNC-1]\brushId=brush_id
If lent=Null
ent.ent=New ent
lent=ent
rent=Handle(lent)
EndIf
If ent=Null Stop
;1142;Default values
ent\r=1
ent\g=1
DebugLog "NEW mesh1'
ent\b=1
If isAnim
ent\isAnim=True
; ent\root =New limb
If nlimb=Null
RuntimeError "No prior root node for animated .b3d"
Else
ent\root=nlimb
DebugLog "Root node name is>"+ent\root\name
plimb(hLevel)=nlimb
DebugLog "Set it to hlevel>"+hLevel
EndIf
ent\name="Root" ;Internal engine root. Not accesible.
Else
;Stop
EndIf
ent\vpiv=CreatePivot()
ent\fx=glFx()
ent\a=1
ent\hLevel=hLevel
ent\eType=glemesh
eStack[eStackC]=ent
eStackC=eStackC+1
Case "BONE"
sz=8
n_weights=b3dChunkSize()/sz
If n_weights*sz=b3dChunkSize()
;DebugLog tab$+n_weights+" weights"
; If n_weights>0 DebugLog "YEAH!"
;read all weights
verts=CreateBank(n_weights*4)
weights=CreateBank(n_weights*4)
vo=0
nlimb\lverts=verts
nlimb\vc=n_weights
nlimb\lweights=verts
ldc=1
If sco=1 ldc=1
sco=1
DebugLog "Checking hlevel>"+Str(hLevel-ldc)
While b3dChunkSize()
vertex_id=b3dReadInt()
weight#=b3dReadFloat()
PokeInt verts,vo,vertex_id
PokeFloat weights,vo,weight
vo=vo+4
;DebugLog "OH YEAH!!"
Wend
Else
DebugLog tab$+"***** Illegal number of bone weights *****"
EndIf
Case "NODE" ;New Entity
;Increase entity stack
;glStackEC=glStackEC+1
;b3dNS[b3dNC]=New b3dNode
name$=b3dReadString$()
;DebugLog "-=-=-=-==-Node >"+b3dns[b3dNC]\name
x#=b3dReadFloat()
y#=b3dReadFloat()
z#=b3dReadFloat()
; DebugLog "X>"+x+" y>"+y+" z>"+z
nLimb.limb =glLimb(name$) ;create limb.
nlimb\x=x
nlimb\y=y
nlimb\z=z
If isAnim
If lent<>Null
If cVerts=0 cVerts=lent\sdat[0]\cVerts
EndIf
EndIf
nlimb\cverts=cverts
DebugLog nlimb\name+"<Name of limb"
.node
nlimb\xs#=b3dReadFloat()
nlimb\ys#=b3dReadFloat()
nlimb\zs#=b3dReadFloat()
nlimb\hLevel=hLevel
nlimb\anVerts=anVerts
setQuat(nlimb\quat,b3dreadfloat(),b3dreadfloat(),b3dreadfloat(),b3dreadfloat())
quatToEuler(nlimb\rot,nlimb\quat)
fillRotation(nlimb\rot,nlimb\rot\pitch+180,nlimb\rot\yaw,nlimb\rot\roll)
eulertoQuat(nlimb\quat,nlimb\rot)
;nlimb\rw#=b3dReadFloat()
;DebugLog "-0-0-0-0-0-0-0"
;plimb(hLevel)=nlimb
; If hLevel>0
;If plimb(hlevel-1)=Null ;no previous limb. assume root limb.
; If lent<>Null
; Stop
; If lent\root=Null
; lent\root=nlimb
; pLimb(hlevel)=nlimb
; End
; DebugLog "Made >"+lent\root\name+" The root!"
; Else
;Stop
; EndIf
; EndIf
;Else
; If lent\root=Null
; lent\root=nlimb
; pLimb(hlevel)=nlimb
; ; End
; DebugLog "Made >"+lent\root\name+" The root!"
; Else
; plimb(hlevel)=nlimb
; plimb(hlevel-1)\child[plimb(hlevel-1)\lc]=nlimb
; plimb(hlevel-1)\lc=plimb(hlevel-1)\lc+1
; EndIf
; EndIf
; DebugLog "!!!!!!!!!!!!!!!!!!!!!!!!!!!"
; EndIf
ldc=1
If isAnim
If plimb(hLevel-ldc)=Null
;Stop
Else
plimb(hLevel-ldc)\child[plimb(hLevel-ldc)\lc]=nlimb
plimb(hLevel-ldc)\lc=plimb(hLevel-ldc)\lc+1
If nlimb=Null Stop
plimb(hLevel)=nlimb
DebugLog "Connected "+plimb(hLevel-ldc)\name+" to "+nlimb\name
EndIf
EndIf
DebugLog tab$+"name="+name$
End Select
vt=glReadb3dChunks( tab$,localDir,uvsets,isAnim) ;dump any subchunks
If vt<>0 rent=vt
b3dExitChunk() ;exit this chunk
Wend
Return rent
End Function