Weird texture problem!

Blitz3D Forums/Blitz3D Programming/Weird texture problem!

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

Ok, here's this little emergency tool, very custom and inhouseish:
http://www.melog.ch/dl/kill_decorator18_clonetris_src.zip

or copy paste from here:
Graphics3D 640,480,32,2
SetBuffer BackBuffer()

; Sometimes Decorator 1.8 created clone Triangles which have the potential to make a lot
; of troubles. This Program may be used to remove the clone Triangles from a Mesh and
; export the result as a B3D Mesh. Cloned Triangles can be removed easily, but since they use
; individual surfaces, you may have to experiment with the "use_clone" variable to make it
; use the right material/surface!

; Use an optimated Decorator Export as mesh source. alpha, vertex normals and color are 
; not supported by now.

; The program also includes Functions to export a lightmapped Mesh, that may be useful 
; for some people.

; Version 0.1, released dec. 2005 by CSP GAMES

; init savemesh
Include "b3dfile.bb"
Global c_surfs
Dim c_surf(0)
Dim c_brush(0)
Dim c_tex(0)
Dim c_tex_name$(0)
; eo init stuff

Global do_weld=1 ; set this to one if you wish to weld the mesh
Global use_clone=1 ; set this to one to use the secondary clones, zero to use the first ones
;(try both if the clone tris are not textured as you wish)

mesh_name$="camp2_dec18weld2.b3d" ; load this mesh
export_path$="diditest.b3d" ; save this optimized mesh



mesh=LoadMesh(mesh_name$)


;Goto test_walk ; use this to skip optimation and save a 1:1 copy of the mesh (for tests only)






; --------------------- first read all surfaces and triangle data to some arrays and banks ---------
surfs=CountSurfaces(mesh)
Dim s(surfs),s2(surfs),tris(surfs),brush(surfs),texturepath$(surfs,1)
Dim same(100000,4)
same_count=0
b=1000
seenflag=990
Print "surfaces: "+ surfs

For i=1 To surfs

 s(i)=GetSurface(mesh,i)
 bru=GetSurfaceBrush(s(i))
 brush(i)=bru

 texture=GetBrushTexture( bru,0)
 name$=TextureName$(texture)
 texturepath$(i,0)=name$
 FreeTexture texture

 texture=GetBrushTexture( bru,1)
 name$=TextureName$(texture)
 texturepath$(i,1)=name$
 FreeTexture texture

 Print texturepath$(i,0)
 Print texturepath$(i,1)

 Print "surface "+i+" has "+CountTriangles(s(i))+" tris"
 tris(i)=CreateBank(CountTriangles(s(i))*b)
 total_tris=total_tris+CountTriangles(s(i))
 For j=0 To CountTriangles(s(i))-1

  PokeFloat tris(i),(j*b)+  0,VertexX		(s(i),TriangleVertex(s(i),j,0))
  PokeFloat tris(i),(j*b)+  4,VertexY		(s(i),TriangleVertex(s(i),j,0))
  PokeFloat tris(i),(j*b)+  8,VertexZ		(s(i),TriangleVertex(s(i),j,0))
  PokeFloat tris(i),(j*b)+ 12,VertexU		(s(i),TriangleVertex(s(i),j,0),0)
  PokeFloat tris(i),(j*b)+ 16,VertexV		(s(i),TriangleVertex(s(i),j,0),0)
  PokeFloat tris(i),(j*b)+ 20,VertexU		(s(i),TriangleVertex(s(i),j,0),1)
  PokeFloat tris(i),(j*b)+ 24,VertexV		(s(i),TriangleVertex(s(i),j,0),1)
  PokeFloat tris(i),(j*b)+ 28,VertexNX		(s(i),TriangleVertex(s(i),j,0))
  PokeFloat tris(i),(j*b)+ 32,VertexNY		(s(i),TriangleVertex(s(i),j,0))
  PokeFloat tris(i),(j*b)+ 36,VertexNZ		(s(i),TriangleVertex(s(i),j,0))
  PokeFloat tris(i),(j*b)+ 40,VertexRed		(s(i),TriangleVertex(s(i),j,0))
  PokeFloat tris(i),(j*b)+ 44,VertexGreen	(s(i),TriangleVertex(s(i),j,0))
  PokeFloat tris(i),(j*b)+ 48,VertexBlue	(s(i),TriangleVertex(s(i),j,0))
  PokeFloat tris(i),(j*b)+ 52,VertexAlpha	(s(i),TriangleVertex(s(i),j,0))

  PokeFloat tris(i),(j*b)+100,VertexX		(s(i),TriangleVertex(s(i),j,1))
  PokeFloat tris(i),(j*b)+104,VertexY		(s(i),TriangleVertex(s(i),j,1))
  PokeFloat tris(i),(j*b)+108,VertexZ		(s(i),TriangleVertex(s(i),j,1))
  PokeFloat tris(i),(j*b)+112,VertexU		(s(i),TriangleVertex(s(i),j,1),0)
  PokeFloat tris(i),(j*b)+116,VertexV		(s(i),TriangleVertex(s(i),j,1),0)
  PokeFloat tris(i),(j*b)+120,VertexU		(s(i),TriangleVertex(s(i),j,1),1)
  PokeFloat tris(i),(j*b)+124,VertexV		(s(i),TriangleVertex(s(i),j,1),1)
  PokeFloat tris(i),(j*b)+128,VertexNX		(s(i),TriangleVertex(s(i),j,1))
  PokeFloat tris(i),(j*b)+132,VertexNY		(s(i),TriangleVertex(s(i),j,1))
  PokeFloat tris(i),(j*b)+136,VertexNZ		(s(i),TriangleVertex(s(i),j,1))
  PokeFloat tris(i),(j*b)+140,VertexRed		(s(i),TriangleVertex(s(i),j,1))
  PokeFloat tris(i),(j*b)+144,VertexGreen	(s(i),TriangleVertex(s(i),j,1))
  PokeFloat tris(i),(j*b)+148,VertexBlue	(s(i),TriangleVertex(s(i),j,1))
  PokeFloat tris(i),(j*b)+152,VertexAlpha	(s(i),TriangleVertex(s(i),j,1))

  PokeFloat tris(i),(j*b)+200,VertexX		(s(i),TriangleVertex(s(i),j,2))
  PokeFloat tris(i),(j*b)+204,VertexY		(s(i),TriangleVertex(s(i),j,2))
  PokeFloat tris(i),(j*b)+208,VertexZ		(s(i),TriangleVertex(s(i),j,2))
  PokeFloat tris(i),(j*b)+212,VertexU		(s(i),TriangleVertex(s(i),j,2),0)
  PokeFloat tris(i),(j*b)+216,VertexV		(s(i),TriangleVertex(s(i),j,2),0)
  PokeFloat tris(i),(j*b)+220,VertexU		(s(i),TriangleVertex(s(i),j,2),1)
  PokeFloat tris(i),(j*b)+224,VertexV		(s(i),TriangleVertex(s(i),j,2),1)
  PokeFloat tris(i),(j*b)+228,VertexNX		(s(i),TriangleVertex(s(i),j,2))
  PokeFloat tris(i),(j*b)+232,VertexNY		(s(i),TriangleVertex(s(i),j,2))
  PokeFloat tris(i),(j*b)+236,VertexNZ		(s(i),TriangleVertex(s(i),j,2))
  PokeFloat tris(i),(j*b)+240,VertexRed		(s(i),TriangleVertex(s(i),j,2))
  PokeFloat tris(i),(j*b)+244,VertexGreen	(s(i),TriangleVertex(s(i),j,2))
  PokeFloat tris(i),(j*b)+248,VertexBlue	(s(i),TriangleVertex(s(i),j,2))
  PokeFloat tris(i),(j*b)+252,VertexAlpha	(s(i),TriangleVertex(s(i),j,2))

 Next
Next

;Goto quicky

Print "-------------------------"


; --------- then compare every single triangle to all other triangles if they are identical --------
; this is a brute force thing, may take a minute or so. You can abort end the app with ESC here.
AppTitle "Please wait, seeking for Clones..."
For i=1 To surfs
 For j=0 To CountTriangles(s(i))-1

  If PeekFloat(tris(i),(j*b)+seenflag)<>-1
   x0#=PeekFloat(tris(i),(j*b)+ 0)
   y0#=PeekFloat(tris(i),(j*b)+ 4)
   z0#=PeekFloat(tris(i),(j*b)+ 8)
   x1#=PeekFloat(tris(i),(j*b)+100)
   y1#=PeekFloat(tris(i),(j*b)+104)
   z1#=PeekFloat(tris(i),(j*b)+108)
   x2#=PeekFloat(tris(i),(j*b)+200)
   y2#=PeekFloat(tris(i),(j*b)+204)
   z2#=PeekFloat(tris(i),(j*b)+208)
   For ii=1 To surfs
    For jj=0 To CountTriangles(s(ii))-1
     If (ii<>i) Or (jj<>j); don't compare with myself
      xx0#=PeekFloat(tris(ii),(jj*b)+ 0)
      yy0#=PeekFloat(tris(ii),(jj*b)+ 4)
      zz0#=PeekFloat(tris(ii),(jj*b)+ 8)
      xx1#=PeekFloat(tris(ii),(jj*b)+100)
      yy1#=PeekFloat(tris(ii),(jj*b)+104)
      zz1#=PeekFloat(tris(ii),(jj*b)+108)
      xx2#=PeekFloat(tris(ii),(jj*b)+200)
      yy2#=PeekFloat(tris(ii),(jj*b)+204)
      zz2#=PeekFloat(tris(ii),(jj*b)+208)
      If (x0=xx0) And (y0=yy0) And (z0=zz0) And (x1=xx1) And (y1=yy1) And (z1=zz1) And (x2=xx2) And (y2=yy2) And (z2=zz2)
       Print "In surface:"+i+" of "+surfs
       Print "Found identic Triangle: surf:"+i+" Tri:"+j+" is the same as surf:"+ii+" Tri:"+jj
       PokeFloat tris(ii),(jj*b)+seenflag,-1 ; set this triangle to "seen"
       PokeFloat tris(i),(j*b)+seenflag,2 ; set this triangle to "seen"
       same(same_count,0)=i
       same(same_count,1)=j
       same(same_count,2)=ii
       same(same_count,3)=jj
       same(same_count,4)=same(same_count,4)+1 ; count number of clones per triangle
       same_count=same_count+1
      EndIf
     EndIf
    Next
   Next
  EndIf
  If KeyDown(1)<>0 Then End
 Next
Next

AppTitle "Ready"

max_clone=0
For i=0 To same_count-1
 If same(i,4) > max_clone Then
  max_clone=same(i,4)
 EndIf
Next

Print "double tris: "+same_count
Print "highest number of clones of one Triangle: "+max_clone ; should not be higher than 1...
Print "total tris in mesh: "+total_tris
Print "And I really didn't take any drugs o_O"
Print "Press Space for a walktrough test"
WaitKey()


; ----------------------------- recreate the mesh without the clone tris! ---------------------
.quicky


mesh2=CreateMesh()


For i=1 To surfs
 s2(i)=CreateSurface(mesh2,brush(i))
Next


For i=1 To surfs
 For j=0 To CountTriangles(s(i))-1
  If PeekFloat(tris(i),(j*b)+seenflag)<>-1

  If PeekFloat(tris(i),(j*b)+seenflag)=2 ; has clone(s)

   i2=i
   j2=j

   If use_clone=1
    For iii=0 To same_count-1 ; use latest clone that was found
     If (same(iii,0)=i) And (same(iii,1)=j)
      i2=same(iii,2)
      j2=same(iii,3)
     EndIf
    Next
   EndIf

   x0#=		PeekFloat(tris(i2),(j2*b)+0)
   y0#=		PeekFloat(tris(i2),(j2*b)+4)
   z0#=		PeekFloat(tris(i2),(j2*b)+8)
   ua0#=	PeekFloat(tris(i2),(j2*b)+12)
   va0#=	PeekFloat(tris(i2),(j2*b)+16)
   ub0#=	PeekFloat(tris(i2),(j2*b)+20)
   vb0#=	PeekFloat(tris(i2),(j2*b)+24)
   nx0#=	PeekFloat(tris(i2),(j2*b)+28)
   ny0#=	PeekFloat(tris(i2),(j2*b)+32)
   nz0#=	PeekFloat(tris(i2),(j2*b)+36)
   red0#=	PeekFloat(tris(i2),(j2*b)+40)
   gre0#=	PeekFloat(tris(i2),(j2*b)+44)
   blu0#=	PeekFloat(tris(i2),(j2*b)+48)
   alp0#=	PeekFloat(tris(i2),(j2*b)+52)

   x1#=		PeekFloat(tris(i2),(j2*b)+100)
   y1#=		PeekFloat(tris(i2),(j2*b)+104)
   z1#=		PeekFloat(tris(i2),(j2*b)+108)
   ua1#=	PeekFloat(tris(i2),(j2*b)+112)
   va1#=	PeekFloat(tris(i2),(j2*b)+116)
   ub1#=	PeekFloat(tris(i2),(j2*b)+120)
   vb1#=	PeekFloat(tris(i2),(j2*b)+124)
   nx1#=	PeekFloat(tris(i2),(j2*b)+128)
   ny1#=	PeekFloat(tris(i2),(j2*b)+132)
   nz1#=	PeekFloat(tris(i2),(j2*b)+136)
   red1#=	PeekFloat(tris(i2),(j2*b)+140)
   gre1#=	PeekFloat(tris(i2),(j2*b)+144)
   blu1#=	PeekFloat(tris(i2),(j2*b)+148)
   alp1#=	PeekFloat(tris(i2),(j2*b)+152)

   x2#=		PeekFloat(tris(i2),(j2*b)+200)
   y2#=		PeekFloat(tris(i2),(j2*b)+204)
   z2#=		PeekFloat(tris(i2),(j2*b)+208)
   ua2#=	PeekFloat(tris(i2),(j2*b)+212)
   va2#=	PeekFloat(tris(i2),(j2*b)+216)
   ub2#=	PeekFloat(tris(i2),(j2*b)+220)
   vb2#=	PeekFloat(tris(i2),(j2*b)+224)
   nx2#=	PeekFloat(tris(i2),(j2*b)+228)
   ny2#=	PeekFloat(tris(i2),(j2*b)+232)
   nz2#=	PeekFloat(tris(i2),(j2*b)+236)
   red2#=	PeekFloat(tris(i2),(j2*b)+240)
   gre2#=	PeekFloat(tris(i2),(j2*b)+244)
   blu2#=	PeekFloat(tris(i2),(j2*b)+248)
   alp2#=	PeekFloat(tris(i2),(j2*b)+252)

   vr0=AddVertex	(s2(i2),x0,y0,z0)
   VertexTexCoords 	s2(i2),vr0,ua0,va0,0,0 
   VertexTexCoords 	s2(i2),vr0,ub0,vb0,0,1 
   VertexNormal 	s2(i2),vr0,nx0,ny0,nz0
   VertexColor  	s2(i2),vr0,red0,gre0,blu0,alp0

   vr1=AddVertex	(s2(i2),x1,y1,z1)
   VertexTexCoords 	s2(i2),vr1,ua1,va1,0,0 
   VertexTexCoords 	s2(i2),vr1,ub1,vb1,0,1 
   VertexNormal 	s2(i2),vr1,nx1,ny1,nz1
   VertexColor  	s2(i2),vr1,red1,gre1,blu1,alp1

   vr2=AddVertex	(s2(i2),x2,y2,z2)
   VertexTexCoords 	s2(i2),vr2,ua2,va2,0,0 
   VertexTexCoords 	s2(i2),vr2,ub2,vb2,0,1 
   VertexNormal 	s2(i2),vr2,nx2,ny2,nz2
   VertexColor  	s2(i2),vr2,red2,gre2,blu2,alp2

   AddTriangle 		(s2(i2),vr0,vr1,vr2)



Else ; has no clone

   x0#=		PeekFloat(tris(i),(j*b)+0)
   y0#=		PeekFloat(tris(i),(j*b)+4)
   z0#=		PeekFloat(tris(i),(j*b)+8)
   ua0#=	PeekFloat(tris(i),(j*b)+12)
   va0#=	PeekFloat(tris(i),(j*b)+16)
   ub0#=	PeekFloat(tris(i),(j*b)+20)
   vb0#=	PeekFloat(tris(i),(j*b)+24)
   nx0#=	PeekFloat(tris(i),(j*b)+28)
   ny0#=	PeekFloat(tris(i),(j*b)+32)
   nz0#=	PeekFloat(tris(i),(j*b)+36)
   red0#=	PeekFloat(tris(i),(j*b)+40)
   gre0#=	PeekFloat(tris(i),(j*b)+44)
   blu0#=	PeekFloat(tris(i),(j*b)+48)
   alp0#=	PeekFloat(tris(i),(j*b)+52)

   x1#=		PeekFloat(tris(i),(j*b)+100)
   y1#=		PeekFloat(tris(i),(j*b)+104)
   z1#=		PeekFloat(tris(i),(j*b)+108)
   ua1#=	PeekFloat(tris(i),(j*b)+112)
   va1#=	PeekFloat(tris(i),(j*b)+116)
   ub1#=	PeekFloat(tris(i),(j*b)+120)
   vb1#=	PeekFloat(tris(i),(j*b)+124)
   nx1#=	PeekFloat(tris(i),(j*b)+128)
   ny1#=	PeekFloat(tris(i),(j*b)+132)
   nz1#=	PeekFloat(tris(i),(j*b)+136)
   red1#=	PeekFloat(tris(i),(j*b)+140)
   gre1#=	PeekFloat(tris(i),(j*b)+144)
   blu1#=	PeekFloat(tris(i),(j*b)+148)
   alp1#=	PeekFloat(tris(i),(j*b)+152)

   x2#=		PeekFloat(tris(i),(j*b)+200)
   y2#=		PeekFloat(tris(i),(j*b)+204)
   z2#=		PeekFloat(tris(i),(j*b)+208)
   ua2#=	PeekFloat(tris(i),(j*b)+212)
   va2#=	PeekFloat(tris(i),(j*b)+216)
   ub2#=	PeekFloat(tris(i),(j*b)+220)
   vb2#=	PeekFloat(tris(i),(j*b)+224)
   nx2#=	PeekFloat(tris(i),(j*b)+228)
   ny2#=	PeekFloat(tris(i),(j*b)+232)
   nz2#=	PeekFloat(tris(i),(j*b)+236)
   red2#=	PeekFloat(tris(i),(j*b)+240)
   gre2#=	PeekFloat(tris(i),(j*b)+244)
   blu2#=	PeekFloat(tris(i),(j*b)+248)
   alp2#=	PeekFloat(tris(i),(j*b)+252)

   vr0=AddVertex	(s2(i),x0,y0,z0)
   VertexTexCoords 	s2(i),vr0,ua0,va0,0,0 
   VertexTexCoords 	s2(i),vr0,ub0,vb0,0,1 
   VertexNormal 	s2(i),vr0,nx0,ny0,nz0
   VertexColor  	s2(i),vr0,red0,gre0,blu0,alp0

   vr1=AddVertex	(s2(i),x1,y1,z1)
   VertexTexCoords 	s2(i),vr1,ua1,va1,0,0 
   VertexTexCoords 	s2(i),vr1,ub1,vb1,0,1 
   VertexNormal 	s2(i),vr1,nx1,ny1,nz1
   VertexColor  	s2(i),vr1,red1,gre1,blu1,alp1

   vr2=AddVertex	(s2(i),x2,y2,z2)
   VertexTexCoords 	s2(i),vr2,ua2,va2,0,0 
   VertexTexCoords 	s2(i),vr2,ub2,vb2,0,1 
   VertexNormal 	s2(i),vr2,nx2,ny2,nz2
   VertexColor  	s2(i),vr2,red2,gre2,blu2,alp2

   AddTriangle 		(s2(i),vr0,vr1,vr2)

EndIf

  EndIf
  If KeyDown(1)<>0 Then End
 Next
Next


FreeEntity mesh ; original Mesh not needed anymore

mesh=mesh2

; ---------------------------------- a walktrough test code -------------------------------
.test_walk

Collisions 1,2,2,2

player=CreatePivot()
PositionEntity player,0,100,-1
EntityRadius player,0.2,0.9
EntityType player,1

camera=CreateCamera( player )
CameraRange camera,.1,200
TranslateEntity camera,0,1.8,0
CameraClsColor camera,180,200,255

light=CreateLight()
LightColor light,32,32,32
TurnEntity light,45,45,0


EntityFX mesh,1
EntityType mesh,2

sp#=.5
ey#=EntityY(player)

; walktrough loop
While Not KeyHit(1)
	If KeyHit(17)
	 wire=1-wire
	 WireFrame wire
	EndIf
	yv#=EntityY(player)-ey
	ey=EntityY(player)
	If KeyHit(57) Then jump#=1.0
	MoveEntity player,0,-Abs(yv-.005),0
	If jump>0 Then
	 jump=jump-.1
 	 If jump<0 Then jump=0
	 MoveEntity player,0,Sin(jump)*30.0,0
	EndIf
	mxa#=-MouseXSpeed()/4.0
	mya#=MouseYSpeed()/4.0
	MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
	TurnEntity player,0,mxa,0
	TurnEntity camera,mya,0,0
	If KeyDown(205) MoveEntity player,sp,0,0
	If KeyDown(203) MoveEntity player,-sp,0,0
	If KeyDown(200) MoveEntity player,0,0,sp
	If KeyDown(208) MoveEntity player,0,0,-sp
	UpdateWorld
	RenderWorld
	Text 0,0,"Tris rendered: "+TrisRendered()
	Text 0,16,"Press ESC to save and exit"
	Flip
Wend

ExportMesh(export_path$,mesh)

End
























; ----------------------------------------------------
; Mesh Saving Functions


Function ExportMesh(what_to_save$,mesh)
  Print
  If do_weld=1
   Print "Welding Mesh"
   weld(mesh)
  EndIf

  c_surfs=CountSurfaces(mesh)


  Dim c_surf(c_surfs+1)
  Dim c_brush(c_surfs+1)
  Dim c_tex(c_surfs+1)
  Dim c_tex_name$(c_surfs+1)

  Print "Saving Mesh"
	For i=1 To c_surfs
	 c_surf(i)= GetSurface(mesh,i)
	 c_brush(i)=GetSurfaceBrush( c_surf(i) )
	 c_tex(i)=GetBrushTexture( c_brush(i) )
	 c_tex_name$(i)=Lower$(TextureName$( c_tex(i)))
	 If c_tex_name$(i)="" Then Print "Warning: Surface No."+i+" has no Texture. This may produce non-working Meshes!"
     c_tex_name$(i)=strippath$(c_tex_name$(i))
	 If FileType(c_tex_name$(i))<>1 Then Print "Warning: Surface No."+i+" uses nonexistant Texture ("+c_tex_name$(i)+")."
	Next
  ; get lightmap details
  c_tex(0)=GetBrushTexture( c_brush(1),1)
  c_tex_name$(0)=Lower$(TextureName$( c_tex(0)))
  c_tex_name$(0)=StripPath$(c_tex_name$(0))


	WriteBB3D( what_to_save$,mesh )

	For i=1 To c_surfs
	 FreeBrush c_brush(i)
	 FreeTexture c_tex(i)
	Next
End Function


Function ExportMesh_wo_lightmap(what_to_save$,mesh)
  If do_weld=1
   Print "Welding Mesh"
   ;mesh=unweld(mesh)
  EndIf
;    UpdateNormals mesh
;    weld(mesh)
;    UpdateNormals mesh
	c_surfs=CountSurfaces(mesh)

  Dim c_surf(c_surfs+1)
  Dim c_brush(c_surfs+1)
  Dim c_tex(c_surfs+1)
  Dim c_tex_name$(c_surfs+1)


  Print "Saving Mesh"

	For i=1 To c_surfs
	 c_surf(i)= GetSurface(mesh,i)
	 c_brush(i)=GetSurfaceBrush( c_surf(i) )
	 c_tex(i)=GetBrushTexture( c_brush(i) )
	 c_tex_name$(i)=Lower$(TextureName$( c_tex(i)))
     c_tex_name$(i)=strippath$(c_tex_name$(i))
	 Print c_tex_name$(i)
	 If c_tex_name$(i)="" Then Print "Error: Surface No."+i+" has no Texture"
	 If FileType(c_tex_name$(i))<>1 Then Print "Warning: Surface No."+i+" uses nonexistant Texture ("+c_tex_name$(i)+")."
	Next

	WriteBB3D_wo_lightmap( what_to_save$,mesh )

	For i=1 To c_surfs
	 FreeBrush c_brush(i)
	 FreeTexture c_tex(i)
	Next
End Function


Function WriteBB3D_wo_lightmap( f_name$,mesh )

	file=WriteFile( f_name$ )

	b3dSetFile( file )
	
	b3dBeginChunk( "BB3D" )
		b3dWriteInt( 1 )	;version

		b3dBeginChunk( "TEXS" ) ; list all textures used by the mesh
		For i=1 To c_surfs
			b3dWriteString( c_tex_name$(i) ) 	;texture file
			b3dWriteInt( 1 )					;flags
			b3dWriteInt( 2 )					;blend
			b3dWriteFloat( 0 )					;x in tex 0 (hu?)
			b3dWriteFloat( 0 )					;y in tex 0
			b3dWriteFloat( 1 )					;x scale 1
			b3dWriteFloat( 1 )					;y scale 1
			b3dWriteFloat( 0 )					;rotation 0
			
		Next
		b3dEndChunk()	;end of TEXS chunk

		
		For i=1 To c_surfs
			b3dBeginChunk( "BRUS" ) ; describe all brushes used by the mesh
		
			b3dWriteInt( 1 )					;number of textures per brush ; (eg 2 with lightmap)
			b3dWriteString( "brush"+(i-1) )		;brushname
			b3dWriteFloat( 1 )					;red
			b3dWriteFloat( 1 )					;green
			b3dWriteFloat( 1 )					;blue
			b3dWriteFloat( 1 )					;alpha
			b3dWriteFloat( 0 )					;shininess
			b3dWriteInt( 1 )					;blendmode
			b3dWriteInt( 0 )					;FX
			b3dWriteInt( i-1 )					;used texture index ?
;			b3dWriteInt( i-1 )					;additional texture index (eg lightmap), but here we only use 1 (see above)

			b3dEndChunk()	;end of BRUS chunk
		Next
		
		b3dBeginChunk( "NODE" )
			b3dWriteString( "entity_name_here!" )
			b3dWriteFloat( 0 )	;x_pos
			b3dWriteFloat( 0 )	;y_pos
			b3dWriteFloat( 0 )	;y_pos
			b3dWriteFloat( 1 )	;x_scale
			b3dWriteFloat( 1 )	;y_scale
			b3dWriteFloat( 1 )	;z_scale
			b3dWriteFloat( 1 )	;rot_w
			b3dWriteFloat( 0 )	;rot_x
			b3dWriteFloat( 0 )	;rot_y
			b3dWriteFloat( 0 )	;rot_z
			WriteMESH_wo_lightmap( mesh )
		b3dEndChunk()	;end of NODE chunk
		
	b3dEndChunk()	;end of BB3D chunk
	
	CloseFile file
End Function

Function WriteMESH_wo_lightmap( mesh )

	n_surfs=CountSurfaces( mesh )
	
	b3dBeginChunk( "MESH" )
		b3dWriteInt( -1 )				;no 'entity' brush -1
		
		b3dBeginChunk( "VRTS" )
			b3dWriteInt( 0 )			;flags - 0=no normal/color
			b3dWriteInt( 1 )			;number of tex_coord sets (z.B: 2 bei lightmap)
			b3dWriteInt( 2 )			;coords per set (u,v,w?) 2 beu uv, 3 bei uvw
			
			For k=1 To n_surfs
				surf=GetSurface( mesh,k )
				n_verts=CountVertices( surf )-1
				
				For j=0 To n_verts
					b3dWriteFloat( VertexX( surf,j ) )
					b3dWriteFloat( VertexY( surf,j ) )
					b3dWriteFloat( VertexZ( surf,j ) )
					b3dWriteFloat( VertexU#( surf,j,0 ) )
					b3dWriteFloat( VertexV#( surf,j,0 ) )
;					b3dWriteFloat( VertexW#( surf,j,0 ) )
;;					b3dWriteFloat( VertexU#( surf,j,1 ) ) ; lightmap uv
;;					b3dWriteFloat( VertexV#( surf,j,1 ) ) ; lightmap uv
;					b3dWriteFloat( VertexW#( surf,j,1 ) )
				Next
			Next
		b3dEndChunk()	;end of VRTS chunk
		
		first_vert=0
		For k=1 To n_surfs
			surf=GetSurface( mesh,k )
			n_tris=CountTriangles( surf )-1
			
			b3dBeginChunk( "TRIS" )
				b3dWriteInt( k-1 )		;brush for these triangles (surf -1 !!!)
				
				For j=0 To n_tris
					b3dWriteInt( first_vert+TriangleVertex( surf,j,0 ) )
					b3dWriteInt( first_vert+TriangleVertex( surf,j,1 ) )
					b3dWriteInt( first_vert+TriangleVertex( surf,j,2 ) )
				Next
				
			b3dEndChunk()	;end of TRIS chunk
			
			first_vert=first_vert+CountVertices( surf )
			
		Next
		
	b3dEndChunk()	;end of MESH chunk
	
End Function

; save mesh WITH lightmap funcs: --------------------------------------------------------

Function WriteBB3D( f_name$,mesh )

	file=WriteFile( f_name$ )

	b3dSetFile( file )
	
	b3dBeginChunk( "BB3D" )
		b3dWriteInt( 1 )	;version

		b3dBeginChunk( "TEXS" ) ; list all textures used by the mesh
		; write lightmap tex
		limaname$=Left$(f_name$,Len(f_name$)-4)+"_lm.bmp"
;		If Upper$(Left$(limaname$,Len(runfromhere$)))=Upper$(runfromhere$)
;		 limaname$=Right$(limaname$,Len(limaname$)-Len(runfromhere$))
;		EndIf
For i=Len(limaname$) To 1 Step -1
 If Mid$(limaname$,i,1)="" Then Exit
Next
If i<1 Then i=1
limaname$=Right$(limaname$,Len(limaname$)-i)

		CopyFile "ssl_temp_lm.bmp", limaname$
		
		b3dWriteString( c_tex_name$(0) ) 	;texture file
		b3dWriteInt( 1 Or $10000 )			;flags
		b3dWriteInt( 2 )					;blend - 2
		b3dWriteFloat( 0 )					;x in tex 0 (hu?)
		b3dWriteFloat( 0 )					;y in tex 0
		b3dWriteFloat( 1 )					;x scale 1
		b3dWriteFloat( 1 )					;y scale 1
		b3dWriteFloat( 0 )					;rotation 0
			
		For i=1 To c_surfs
			b3dWriteString( c_tex_name$(i) ) 	;texture file
			b3dWriteInt( 1 )					;flags
			b3dWriteInt( 2 )					;blend - 2
			b3dWriteFloat( 0 )					;x in tex 0 (hu?)
			b3dWriteFloat( 0 )					;y in tex 0
			b3dWriteFloat( 1 )					;x scale 1
			b3dWriteFloat( 1 )					;y scale 1
			b3dWriteFloat( 0 )					;rotation 0
			
		Next
		b3dEndChunk()	;end of TEXS chunk

		
		For i=1 To c_surfs
			b3dBeginChunk( "BRUS" ) ; describe all brushes used by the mesh
		
			b3dWriteInt( 2 )					;number of textures per brush ; (eg 2 with lightmap)
			b3dWriteString( "brush"+(i-1) )		;brushname
			b3dWriteFloat( 1 )					;red
			b3dWriteFloat( 1 )					;green
			b3dWriteFloat( 1 )					;blue
			b3dWriteFloat( 1 )					;alpha
			b3dWriteFloat( 0 )					;shininess
			b3dWriteInt( 1 )					;blendmode - once 2, mow 1!
			b3dWriteInt( 1 )					;FX
			b3dWriteInt( i )					;used texture index ?
			b3dWriteInt( 0 )					;additional texture index (eg lightmap), but here we only use 1 (see above)

			b3dEndChunk()	;end of BRUS chunk
		Next
		
		b3dBeginChunk( "NODE" )
			b3dWriteString( "whatever" )
			b3dWriteFloat( 0 )	;x_pos
			b3dWriteFloat( 0 )	;y_pos
			b3dWriteFloat( 0 )	;y_pos
			b3dWriteFloat( 1 )	;x_scale
			b3dWriteFloat( 1 )	;y_scale
			b3dWriteFloat( 1 )	;z_scale
			b3dWriteFloat( 1 )	;rot_w
			b3dWriteFloat( 0 )	;rot_x
			b3dWriteFloat( 0 )	;rot_y
			b3dWriteFloat( 0 )	;rot_z
			WriteMESH( mesh )
		b3dEndChunk()	;end of NODE chunk
		
	b3dEndChunk()	;end of BB3D chunk
	
	CloseFile file
End Function

Function WriteMESH( mesh )

	n_surfs=CountSurfaces( mesh )
	
	b3dBeginChunk( "MESH" )
		b3dWriteInt( -1 )				;no 'entity' brush -1
		
		b3dBeginChunk( "VRTS" )
			b3dWriteInt( 0 )			;flags - 0=no normal/color
			b3dWriteInt( 2 )			;number of tex_coord sets (z.B: 2 bei lightmap)
			b3dWriteInt( 2 )			;coords per set (u,v,w?) 2 beu uv, 3 bei uvw
			
			For k=1 To n_surfs
				surf=GetSurface( mesh,k )
				n_verts=CountVertices( surf )-1
				
				For j=0 To n_verts
					b3dWriteFloat( VertexX( surf,j ) )
					b3dWriteFloat( VertexY( surf,j ) )
					b3dWriteFloat( VertexZ( surf,j ) )
					b3dWriteFloat( VertexU#( surf,j,0 ) )
					b3dWriteFloat( VertexV#( surf,j,0 ) )
;					b3dWriteFloat( VertexW#( surf,j,0 ) )
					b3dWriteFloat( VertexU#( surf,j,1 ) ) ; lightmap uv
					b3dWriteFloat( VertexV#( surf,j,1 ) ) ; lightmap uv
;					b3dWriteFloat( VertexW#( surf,j,1 ) )
				Next
			Next
		b3dEndChunk()	;end of VRTS chunk
		
		first_vert=0
		For k=1 To n_surfs
			surf=GetSurface( mesh,k )
			n_tris=CountTriangles( surf )-1
			
			b3dBeginChunk( "TRIS" )
				b3dWriteInt( k-1 )		;brush for these triangles (surf -1 !!!)
				
				For j=0 To n_tris
					b3dWriteInt( first_vert+TriangleVertex( surf,j,0 ) )
					b3dWriteInt( first_vert+TriangleVertex( surf,j,1 ) )
					b3dWriteInt( first_vert+TriangleVertex( surf,j,2 ) )
				Next
				
			b3dEndChunk()	;end of TRIS chunk
			
			first_vert=first_vert+CountVertices( surf )
			
		Next
		
	b3dEndChunk()	;end of MESH chunk
	
End Function


;---------------------------------- eo saving mesh functions ------------------------------------

;-------------------------------------- welding functions ---------------------------------------

; init weld
Dim txv(3)
Type TRIS
	Field x0#
	Field y0#
	Field z0#

	Field u0#
	Field v0#
	Field U20#
	Field V20#
	
	Field x1#
	Field y1#
	Field z1#

	Field u1#
	Field v1#
	Field U21#
	Field V21#
	
	Field x2#
	Field y2#
	Field z2#

	Field u2#
	Field v2#

	Field U22#
	Field V22#
	
	Field surface
End Type


Function Weld(mish)
	Dim txv(3)
	
	For nsurf = 1 To CountSurfaces(mish)
		su=GetSurface(mish,nsurf)
		For tq = 0 To CountTriangles(su)-1
			txv(0) = TriangleVertex(su,tq,0)
			txv(1) = TriangleVertex(su,tq,1)
			txv(2) = TriangleVertex(su,tq,2)

			vq.TRIS = New TRIS
			vq\x0# = VertexX(su,txv(0))
			vq\y0# = VertexY(su,txv(0))
			vq\z0# = VertexZ(su,txv(0))
			vq\u0# = VertexU(su,txv(0),0)
			vq\v0# = VertexV(su,txv(0),0)
			vq\u20# = VertexU(su,txv(0),1)
			vq\v20# = VertexV(su,txv(0),1)
			
			vq\x1# = VertexX(su,txv(1))
			vq\y1# = VertexY(su,txv(1))
			vq\z1# = VertexZ(su,txv(1))
			vq\u1# = VertexU(su,txv(1),0)
			vq\v1# = VertexV(su,txv(1),0)
			vq\u21# = VertexU(su,txv(1),1)
			vq\v21# = VertexV(su,txv(1),1)
		
			vq\x2# = VertexX(su,txv(2))
			vq\y2# = VertexY(su,txv(2))
			vq\z2# = VertexZ(su,txv(2))
			vq\u2# = VertexU(su,txv(2),0)
			vq\v2# = VertexV(su,txv(2),0)
			vq\u22# = VertexU(su,txv(2),1)
			vq\v22# = VertexV(su,txv(2),1)
		Next
		
		ClearSurface su
		
		For vq.tris = Each tris
		
				vt1=findvert(su,vq\x0#,vq\y0#,vq\z0#,vq\u0#,vq\v0#,vq\u20#,vq\v20#)
				
				If vt1=-1 Then
					vt1=AddVertex(su,vq\x0#,vq\y0#,vq\z0#,vq\u0#,vq\v0#)
					loc_u#=(vq\u20#)
					loc_v#=(vq\v20#)
;					If loc_u> 1.0 Then loc_u=loc_u-(loc_u-1.0)
;					If loc_u<-1.0 Then loc_u=loc_u+(Abs(loc_u)-1.0)
;					If loc_v> 1.0 Then loc_v=loc_v-(loc_v-1.0)
;					If loc_v<-1.0 Then loc_v=loc_v+(Abs(loc_v)-1.0)

					VertexTexCoords su,mycount,loc_u,loc_v,0,1
					vt1 = mycount
					mycount = mycount +1
				EndIf
		
				vt2=findvert(su,vq\x1#,vq\y1#,vq\z1#,vq\u1#,vq\v1#,vq\u21#,vq\v21#)
				If Vt2=-1 Then
					vt2=AddVertex( su,vq\x1#,vq\y1#,vq\z1#,vq\u1#,vq\v1#)
					loc_u#=(vq\u21#)
					loc_v#=(vq\v21#)
;					If loc_u> 1.0 Then loc_u=loc_u-(loc_u-1.0)
;					If loc_u<-1.0 Then loc_u=loc_u+(Abs(loc_u)-1.0)
;					If loc_v> 1.0 Then loc_v=loc_v-(loc_v-1.0)
;					If loc_v<-1.0 Then loc_v=loc_v+(Abs(loc_v)-1.0)
					VertexTexCoords su,mycount,loc_u,loc_v,0,1
					vt2 = mycount
					mycount = mycount +1
				EndIf
				
				vt3=findvert(su,vq\x2#,vq\y2#,vq\z2#,vq\u2#,vq\v2#,vq\u22#,vq\v22#)
				
				If vt3=-1 Then 
					vt3=AddVertex(su,vq\x2#,vq\y2#,vq\z2#,vq\u2#,vq\v2#)
					loc_u#=(vq\u22#)
					loc_v#=(vq\v22#)
;					If loc_u> 1.0 Then loc_u=loc_u-(loc_u-1.0)
;					If loc_u<-1.0 Then loc_u=loc_u+(Abs(loc_u)-1.0)
;					If loc_v> 1.0 Then loc_v=loc_v-(loc_v-1.0)
;					If loc_v<-1.0 Then loc_v=loc_v+(Abs(loc_v)-1.0)
					VertexTexCoords su,mycount,loc_u,loc_v,0,1
					vt3 = mycount
					mycount = mycount +1
				EndIf
		
			AddTriangle su,vt1,vt2,vt3
		
		Next
		
		Delete Each tris
		mycount=0
	Next
End Function
	
Function findvert(su,x2#,y2#,z2#,u2#,v2#,u22#,v22#)
	Local thresh# =0.001
	
	For t=0 To CountVertices(su)-1
		If Abs(VertexX(su,t)-x2#)<thresh# Then 
			If Abs(VertexY(su,t)-y2#)<thresh# Then 
				If Abs(VertexZ(su,t)-z2#)<thresh# Then 
					If Abs(VertexU(su,t,0)-u2#)<thresh# Then 
						If Abs(VertexV(su,t,0)-v2#)<thresh# Then 
							If Abs(VertexU(su,t,1)-u22#)<thresh# Then 
								If Abs(VertexV(su,t,1)-v22#)<thresh# Then
									Return t
								EndIf
							EndIf
						EndIf
					EndIf
				EndIf
			EndIf
		EndIf
	Next
	Return -1
End Function


;----------------------------------- eo welding functions ---------------------------------------








Function StripPath$(file$)
 If Len(file$)>0 
  For i=Len(file$) To 1 Step -1 
   mi$=Mid$(file$,i,1) 
   If mi$="" Or mi$="/" Then Return name$ Else name$=mi$+name$ 
  Next 
 EndIf 
 Return name$ 
End Function




the required b3dfile.bb include file:

;
;b3d file utils to be included
;

Dim b3d_stack(100)
Global b3d_file,b3d_tos

Function b3dSetFile( file )
	b3d_tos=0
	b3d_file=file
End Function

;***** functions for reading from B3D files *****

Function b3dReadByte()
	Return ReadByte( b3d_file )
End Function

Function b3dReadInt()
	Return ReadInt( b3d_file )
End Function

Function b3dReadFloat#()
	Return ReadFloat( b3d_file )
End Function

Function b3dReadString$()
	Repeat
		ch=b3dReadByte()
		If ch=0 Return t$
		t$=t$+Chr$(ch)
	Forever
End Function

Function b3dReadChunk$()
	For k=1 To 4
		tag$=tag$+Chr$(b3dReadByte())
	Next
	sz=ReadInt( b3d_file )
	b3d_tos=b3d_tos+1
	b3d_stack(b3d_tos)=FilePos( b3d_file )+sz
	Return tag$
End Function

Function b3dExitChunk()
	SeekFile b3d_file,b3d_stack(b3d_tos)
	b3d_tos=b3d_tos-1
End Function

Function b3dChunkSize()
	Return b3d_stack(b3d_tos)-FilePos( b3d_file )
End Function

;***** Functions for writing to B3D files *****

Function b3dWriteByte( n )
	WriteByte( b3d_file,n )
End Function

Function b3dWriteInt( n )
	WriteInt( b3d_file,n )
End Function

Function b3dWriteFloat( n# )
	WriteFloat( b3d_file,n )
End Function

Function b3dWriteString( t$ )
	For k=1 To Len( t$ )
		ch=Asc(Mid$(t$,k,1))
		b3dWriteByte(ch)
		If ch=0 Return
	Next
	b3dWriteByte( 0 )
End Function

Function b3dBeginChunk( tag$ )
	b3d_tos=b3d_tos+1
	For k=1 To 4
		b3dWriteByte(Asc(Mid$( tag$,k,1 )))
	Next
	b3dWriteInt( 0 )
	b3d_stack(b3d_tos)=FilePos( b3d_file )
End Function

Function b3dEndChunk()
	n=FilePos( b3d_file )
	SeekFile b3d_file,b3d_stack(b3d_tos)-4
	b3dWriteInt( n-b3d_stack(b3d_tos) )
	SeekFile b3d_file,n
	b3d_tos=b3d_tos-1
End Function