#ifndef __SANDBOX_BI__
#define __SANDBOX_BI__

const as integer HSIZE=128

function rnd2() as single
  return rnd()-rnd()
end function

type SANDBOX_T
  public:
  declare constructor(byval fMaxApmlitude as single =50.0, _
                      byval fXZScale      as single =5.0, _
                      byval nSmoothSteps  as integer=5, _
                      byval fFilterConst  as single =0.5)
  as StaticObject ptr pObj
  as single  fSize
end type
type PSANDBOX as SANDBOX_T ptr

constructor SANDBOX_T(byval fMaxApmlitude as single , _
                      byval fXZScale      as single , _
                      byval nSmoothSteps  as integer, _
                      byval fFilterConst  as single)
  dim as single hf(HSIZE,HSIZE,2) ' simple hightfield
  dim as integer size1=HSIZE+1
  dim as integer z,x,x0,x1,z0,z1,a,b,c,d,i
  dim as single cc,l
  dim as integer Indices(2)
  dim as single xstart=(-HSIZE/2)*fXZScale
  dim as single zstart=(-HSIZE/2)*fXZScale
  dim as single ad(2)
  dim as single bd(2)
  dim as single n(2)
  fSize = HSIZE*fXZScale
  ' create a static object for the terrain
  pObj = StaticObjectCreateNew()
  dim as COLLISIONOBJECTAABBMESH ptr pMesh = CollisionObjectAABBMeshCreateNew()  
  
  dim as integer nQuads=HSIZE*HSIZE
  dim as integer nTriangles=nQuads*2 ' 2 tris = 1 quad
  '                                        nVerts      ,   nTris     ,   nIndex
  CollisionObjectAABBMeshInitialise(pMesh,size1*size1 ,nTriangles,nTriangles*3)
  
  for z = 0 to HSIZE
    for x = 0 to HSIZE
      hf(x,z,0)=xstart+x*fXZScale
      if x>10 andalso x<(HSIZE-10) andalso z>10 andalso z<(HSIZE-10) then
        hf(x,z,1)=RND2()  * fMaxApmlitude
        if int(RND()*10)=5 then
          hf(x,z,1)= fMaxApmlitude*fXZScale
        else
          hf(x,z,1)=1
        end if
      end if
      hf(x,z,2)=zstart+z*fXZScale
      
    next
  next
 
  for z = HSIZE/2-10 to HSIZE/2+10
    for x = HSIZE/2-10 to HSIZE/2+10
      hf(x,z,1)=0.0
    next
  next
  

  ' smoth the terrain grid steps times 
 if nSmoothSteps>0 then
    ' the edges of the sandbox.
  for i=0 to HSIZE
    hf(i,0,1)=1
    hf(i,1,1)=1
    hf(i,HSIZE,1)=1
    hf(i,HSIZE-1,1)=1
    hf(0,i,1)=1
    hf(1,i,1)=1
    hf(HSIZE,i,1)=1
    hf(HSIZE-1,i,1)=1
  next
  
  for i=1 to nSmoothSteps
    ' rows
    'left -> right
    for x = 1 to HSIZE
      for z = 0 to HSIZE
        hf(x,z,1) = hf(x-1,z,1) * (1.0-fFilterConst) + hf(x,z,1) * fFilterConst
      next
    next
    ' right -> left
    for x = HSIZE-1 to 0 step -1
      for z = 0 to HSIZE
        hf(x,z,1) = hf(x+1,z,1) * (1.0-fFilterConst) + hf(x,z,1) * fFilterConst
      next
    next
    ' columns
    ' bottom -> top
    for x = 0 to HSIZE
      for z = 1 to HSIZE
        hf(x,z,1) = hf(x,z-1,1) * (1.0-fFilterConst) + hf(x,z,1) * fFilterConst
      next
    next
    ' top -> bottom
    for x = 0 to HSIZE
      for z = HSIZE-1 to 0 step -1
        hf(x,z,1) = hf(x,z+1,1) * (1.0-fFilterConst) + hf(x,z,1) * fFilterConst
      next
    next
  next
 end if


  ' the edges of the sandbox.
  for i=0 to HSIZE
    hf(i,0,1)=0
    hf(i,HSIZE,1)=0
    hf(0,i,1)=0
    hf(HSIZE,i,1)=0

  next
  ' add the vertices to the collsion mesh
  for z = 0 to HSIZE
    for x = 0 to HSIZE
       CollisionObjectAABBMeshAddVertex(pMesh,hf(x,z,0),hf(x,z,1),hf(x,z,2))
    next
  next

  dim as single TX=1.0/fXZScale
  dim as single TY=1.0/fXZScale
  for z = 0 to HSIZE-1
    for x = 0 to HSIZE-1
      x0=x:x1=x+1
      z0=z:z1=z+1
      a=z0*size1+x0
      b=z1*size1+x0
      c=z1*size1+x1
      d=z0*size1+x1

      ' build triangle 1 for the CollsionMesh
      Indices(0)=d:Indices(1)=b:Indices(2)=a
      CollisionObjectAABBMeshAddPolygon pMesh,3,@Indices(0)

      ' build triangle 2 for the CollsionMesh
      Indices(0)=d:Indices(1)=c:Indices(2)=b
      CollisionObjectAABBMeshAddPolygon pMesh,3,@Indices(0)
    next
  next

  CollisionObjectAABBMeshFinishedAddingGeometry(pMesh)

  ' Initialise the Static Object with the Collision Mesh.
  StaticObjectInitialise(pObj,pMesh)
  ' We no long need the reference.
  CollisionObjectAABBMeshRelease(pMesh) 
  ' Add the static object to the simulation.
  PhysicsAddStaticObject(pObj)
end constructor
dim shared as PSANDBOX gSandbox

function SandBoxSize as single
  if gSandbox=0 then return 0.0
  return gSandbox->fSize
end function

function InitSandBox(byval fMaxApmlitude as single =50.0, _
                     byval fXZScale      as single =5.0, _
                     byval nSmoothSteps  as integer=5, _
                     byval fFilterConst  as single =0.5) as integer
  if gSandbox then return 0
  gSandbox=new SANDBOX_T(fMaxApmlitude,fXZScale,nSmoothSteps,fFilterConst)
  return 1
end function

#endif ' __SANDBOX_BI__
