TGC Codebase Backup



Memblock Matrix by Kelebrindae

9th Dec 2004 5:51
Summary

Create a matrix that can be manipulated (ex:rotated) like a common object. Advanced functionality (heigtmaps, normals calculation, tile-texturing with rotated/mirrored tiles...) ha



Description

Create a matrix that can be manipulated (ex:rotated) like a common object. Advanced functionality (heigtmaps, normals calculation, tile-texturing with rotated/mirrored tiles) has been added. Make intensive use of the memblocks.
Please download the ZIP file in attachments to get some sample codes and a short "how to" file.



Code
                                    ` This code was downloaded from The Game Creators
                                    ` It is reproduced here with full permission
                                    ` http://www.thegamecreators.com
                                    
                                    rem *******************************************************************
rem * Create and manage a "matrix-like-object" built from a memblock  *
rem * Author: Kelebrindae                                             *
rem * November 2004                                                   *
rem *******************************************************************

rem Build a memblock containing the mesh of a "matrix-like" object.
rem This mesh will be [width#] by [depth#], divided in a grid of [tilesX] by [tilesZ] squares.
rem Each square has 4 vertices, so the mesh will contain [tilesX] * [tilesZ] * 4 vertices, numeroted from 0 to [Nb verteces - 1].
rem This means that a 2x2 grid will have 16 verteces, like shown here:

rem   09--10 13--14
rem   |     |     |
rem   08__11 12__15
rem   01  02 05  06
rem   |     |     |
rem   00--03 04--07

rem The mesh's pivot (0,0,0 coordinates) is located on vertex n°0 (in the "lower-left" corner).
rem The UV coords 0,0 are located on the "upper left" corner of the matrix (in the 3x3 matrix, on vertex n°12).
rem It is so because the Y axis in images is "inverted" (pixel 0,0 is in the upper left corner of the bitmap).
rem So, to avoid a "vertical mirror" effect on the texture, I had to invert the V axis of UVmapping...
rem Matrix number of tiles and dimensions are stored in memblock 255 for fast and easy access.
` Parameters:
` Memblock number, matrix width (pixels), matrix depth (pixels)
function makeMemMatrix(memNum,width#,depth#,tilesX,tilesZ)
   if memblock exist(memNum) = 1 then  exitfunction

   rem If memblock n°255 doesn't exist yet, create it.
   if memblock exist(255) = 0
      make memblock 255,(memNum+1)*16
   else
      rem If it exists but is too small, copy its content, delete and re-create it, then copy its datas back
      size=get memblock size(255)
      if size<(memNum+1)*16
         make memblock 254,size
         copy memblock 255,254,0,0,size
         delete memblock 255
         make memblock 255,(memNum+1)*16
         copy memblock 254,255,0,0,size
      endif
   endif

   rem Compute offsets and datas sizes
   vertNum = tilesX*tilesZ*4
   faceNum = (tilesX * tilesZ) * 2
   vertOffset = 32
   normNum = vertNum
   normOffset = 32+(vertNum*12)
   faceOffset = 32+(vertNum*12)+(normNum*12)
   faceSize = 7*faceNum: rem this size is in "Dwords", not in "Bytes"! (1 Dword = 4 bytes)
   UVOffset = 32+(vertNum*12)+(normNum*12)+(faceNum*28)

   rem Create memblock
   memSize = 32 + (12*vertNum) + (12*normNum) + (28*faceNum) + (8*vertNum)
   make memblock memNum,memSize

   rem Write mesh header
   write memblock dword memNum,0,vertNum
   write memblock dword memNum,4,vertOffset
   write memblock dword memNum,8,normNum
   write memblock dword memNum,12,normOffset
   write memblock dword memNum,16,faceNum
   write memblock dword memNum,20,faceOffset
   write memblock dword memNum,24,faceSize
   write memblock dword memNum,28,UVOffset

   rem Size of matrix tile, Size of UV tile
   tileWidth# = width#/(tilesX*1.0)
   tileDepth# = depth#/(tilesZ*1.0)
   UVtileWidth# = 1.00/(tilesX*1.0)
   UVtileDepth# = 1.00/(tilesZ*1.0)

   rem Store number of tiles and tiles size in memblock 255
   write memblock Dword 255,memNum*16,tilesX
   write memblock Dword 255,(memNum*16)+4,tilesZ
   write memblock float 255,(memNum*16)+8,tileWidth#
   write memblock float 255,(memNum*16)+12,tileDepth#

   rem Create 4 vertex and 2 faces by tile
   vertCtr=0:faceCtr=0
   for cz = 0 to tilesZ-1
      for cx = 0 to tilesX-1
         rem Vertex 0 coords
         write memblock float memNum,vertOffset+(vertCtr*12),cx*tileWidth#
         write memblock float memNum,vertOffset+(vertCtr*12)+4,0.00
         write memblock float memNum,vertOffset+(vertCtr*12)+8,cz*tileDepth#
         rem Normals infos
         write memblock float memNum,normOffset+(vertCtr*12),0.0
         write memblock float memNum,normOffset+(vertCtr*12)+4,1.00
         write memblock float memNum,normOffset+(vertCtr*12)+8,0.0
         rem UV coords
         write memblock float memNum,UVoffset+(vertCtr*8),cx*UVtileWidth#
         write memblock float memNum,UVoffset+(vertCtr*8)+4,1.00-(cz*UVtileDepth#)
         rem Store vertex number and go on
         v0 = vertCtr
         inc vertCtr

         rem Vertex 1 coords
         write memblock float memNum,vertOffset+(vertCtr*12),cx*tileWidth#
         write memblock float memNum,vertOffset+(vertCtr*12)+4,0.00
         write memblock float memNum,vertOffset+(vertCtr*12)+8,(cz+1)*tileDepth#
         rem Normals infos
         write memblock float memNum,normOffset+(vertCtr*12),0.0
         write memblock float memNum,normOffset+(vertCtr*12)+4,1.00
         write memblock float memNum,normOffset+(vertCtr*12)+8,0.0
         rem UV coords
         write memblock float memNum,UVoffset+(vertCtr*8),cx*UVtileWidth#
         write memblock float memNum,UVoffset+(vertCtr*8)+4,1.00-((cz+1)*UVtileDepth#)
         rem Store vertex number and go on
         v1 = vertCtr
         inc vertCtr

         rem Vertex 2 coords
         write memblock float memNum,vertOffset+(vertCtr*12),(cx+1)*tileWidth#
         write memblock float memNum,vertOffset+(vertCtr*12)+4,0.00
         write memblock float memNum,vertOffset+(vertCtr*12)+8,(cz+1)*tileDepth#
         rem Normals infos
         write memblock float memNum,normOffset+(vertCtr*12),0.0
         write memblock float memNum,normOffset+(vertCtr*12)+4,1.00
         write memblock float memNum,normOffset+(vertCtr*12)+8,0.0
         rem UV coords
         write memblock float memNum,UVoffset+(vertCtr*8),(cx+1)*UVtileWidth#
         write memblock float memNum,UVoffset+(vertCtr*8)+4,1.00-((cz+1)*UVtileDepth#)
         rem Store vertex number and go on
         v2 = vertCtr
         inc vertCtr

         rem Vertex 3 coords
         write memblock float memNum,vertOffset+(vertCtr*12),(cx+1)*tileWidth#
         write memblock float memNum,vertOffset+(vertCtr*12)+4,0.00
         write memblock float memNum,vertOffset+(vertCtr*12)+8,cz*tileDepth#
         rem Normals infos
         write memblock float memNum,normOffset+(vertCtr*12),0.0
         write memblock float memNum,normOffset+(vertCtr*12)+4,1.00
         write memblock float memNum,normOffset+(vertCtr*12)+8,0.0
         rem UV coords
         write memblock float memNum,UVoffset+(vertCtr*8),(cx+1)*UVtileWidth#
         write memblock float memNum,UVoffset+(vertCtr*8)+4,1.00-(cz*UVtileDepth#)
         rem Store vertex number and go on
         v3 = vertCtr
         inc vertCtr

         rem First triangle of tile
         write memblock dword memNum,faceOffset+(faceCtr*28),3
         write memblock dword memNum,faceOffset+(faceCtr*28)+4,v1
         write memblock dword memNum,faceOffset+(faceCtr*28)+8,v1
         write memblock dword memNum,faceOffset+(faceCtr*28)+12,v2
         write memblock dword memNum,faceOffset+(faceCtr*28)+16,v2
         write memblock dword memNum,faceOffset+(faceCtr*28)+20,v0
         write memblock dword memNum,faceOffset+(faceCtr*28)+24,v0
         inc faceCtr

         rem Second triangle
         write memblock dword memNum,faceOffset+(faceCtr*28),3
         write memblock dword memNum,faceOffset+(faceCtr*28)+4,v3
         write memblock dword memNum,faceOffset+(faceCtr*28)+8,v3
         write memblock dword memNum,faceOffset+(faceCtr*28)+12,v0
         write memblock dword memNum,faceOffset+(faceCtr*28)+16,v0
         write memblock dword memNum,faceOffset+(faceCtr*28)+20,v2
         write memblock dword memNum,faceOffset+(faceCtr*28)+24,v2
         inc faceCtr

      next cx
   next cz

endfunction

rem Set the height of a vertex in the matrix memblock
` Parameters:
` Memblock number, x coord of the vertex to move, Z coord, new height
function setMemMatrixHeight(memNum,cx,cz,height#)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   if cx>0 and cz>0 then vertCtr=((cz-1)*(4*tilesX)) + ((cx-1)*4) + 2:write memblock float memNum,32+(vertCtr*12)+4,height#
   if cx>0 and cz<TilesZ then vertCtr=(cz*(4*tilesX)) + ((cx-1)*4) + 3:write memblock float memNum,32+(vertCtr*12)+4,height#
   if cx<TilesX and cz<TilesZ then vertCtr=(cz*(4*tilesX)) + (cx*4):write memblock float memNum,32+(vertCtr*12)+4,height#
   if cx<TilesX and cz>0 then vertCtr=((cz-1)*(4*tilesX)) + (cx*4)+1:write memblock float memNum,32+(vertCtr*12)+4,height#
endfunction

rem Get the height of a vertex in the matrix memblock
` Parameters:
` Memblock number, x coord of the vertex, Z coord
` Return: height of the vertex
function getMemMatrixHeight(memNum,cx,cz)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   height#=0
   if cx>0 and cz>0 then vertCtr=((cz-1)*(4*tilesX)) + ((cx-1)*4) + 2:exitfunction memblock float(memNum,32+(vertCtr*12)+4)
   if cx>0 and cz<TilesZ then vertCtr=(cz*(4*tilesX)) + ((cx-1)*4) + 3:exitfunction memblock float(memNum,32+(vertCtr*12)+4)
   if cx<TilesX and cz<TilesZ then vertCtr=(cz*(4*tilesX)) + (cx*4):exitfunction memblock float(memNum,32+(vertCtr*12)+4)
   if cx<TilesX and cz>0 then vertCtr=((cz-1)*(4*tilesX)) + (cx*4)+1:exitfunction memblock float(memNum,32+(vertCtr*12)+4)
endfunction height#

rem Get the height of a point in the matrix memblock
` Parameters:
` Memblock number, x coord, Z coord
` Return: height of the point
` (DBpro code by Phaelax, slightly adapted for DBC)
function getMemMatrixGroundHeight(memNum,x#,z#)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   rem retrieve tiles size
   sizex#=memblock float(255,(memnum*16)+8)
   sizez#=memblock float(255,(memnum*16)+12)

   rem If the point is in the matrix, return its height
   if x#>=0 and z#>=0 and x#<tilesX*sizex# and z#<tilesZ*sizez#
      xt=int(x#/sizex#)
      zt=int(z#/sizez#)
      if (((xt+1)*sizex#)-x#)+(z#-(zt*sizez#))<=sizex#
         dx#=getMemMatrixHeight(memNum,xt+1,zt)-getMemMatrixHeight(memNum,xt,zt)
         dz#=getMemMatrixHeight(memNum,xt+1,zt+1)-getMemMatrixHeight(memNum,xt+1,zt)
      else
         dx#=getMemMatrixHeight(memNum,xt+1,zt+1)-getMemMatrixHeight(memNum,xt,zt+1)
         dz#=getMemMatrixHeight(memNum,xt,zt+1)-getMemMatrixHeight(memNum,xt,zt)
      endif
      height#=(((x#-(xt*sizex#))/sizex#)*dx#)+(((z#-(zt*sizez#))/sizez#)*dz#)+getMemMatrixHeight(memNum,xt,zt)
   endif
endfunction height#

rem Set the normal of a vertex in the matrix memblock
rem => called in the ConfigureMemMatrixNormal function
` Parameters:
` Memblock number, x coord of the vertex, Z coord, x,y,z of the new normal vector
function setMemMatrixNormal(memNum,cx,cz,nx#,ny#,nz#)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   vertNum=memblock dword(memNum,0)
   normOffset = 32+(vertNum*12)

   if cx>0 and cz>0
      vertCtr=((cz-1)*(4*tilesX)) + ((cx-1)*4) + 2
      write memblock float memNum,normOffset+(vertCtr*12),nx#
      write memblock float memNum,normOffset+(vertCtr*12)+4,ny#
      write memblock float memNum,normOffset+(vertCtr*12)+8,nz#
   endif
   if cx>0 and cz<TilesZ
      vertCtr=(cz*(4*tilesX)) + ((cx-1)*4) + 3
      write memblock float memNum,normOffset+(vertCtr*12),nx#
      write memblock float memNum,normOffset+(vertCtr*12)+4,ny#
      write memblock float memNum,normOffset+(vertCtr*12)+8,nz#
   endif
   if cx<TilesX and cz<TilesZ
      vertCtr=(cz*(4*tilesX)) + (cx*4)
      write memblock float memNum,normOffset+(vertCtr*12),nx#
      write memblock float memNum,normOffset+(vertCtr*12)+4,ny#
      write memblock float memNum,normOffset+(vertCtr*12)+8,nz#
   endif
   if cx<TilesX and cz>0
      vertCtr=((cz-1)*(4*tilesX)) + (cx*4)+1
      write memblock float memNum,normOffset+(vertCtr*12),nx#
      write memblock float memNum,normOffset+(vertCtr*12)+4,ny#
      write memblock float memNum,normOffset+(vertCtr*12)+8,nz#
   endif
endfunction

rem Re-calculate the normal of each vertex of the matrix
` Parameters:
` Memblock number
function ConfigureMemMatrixNormals(memNum)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   rem retrieve tiles size
   sizex#=memblock float(255,(memnum*16)+8)
   sizez#=memblock float(255,(memnum*16)+12)

   for z=1 to tilesZ-1
      for x=1 to tilesX-1

         rem Get matrix heights
         h8#=getMemMatrixHeight(memNum,x,z-1)
         h4#=getMemMatrixHeight(memNum,x-1,z)
         h#=getMemMatrixHeight(memNum,x,z)
         h2#=getMemMatrixHeight(memNum,x,z)

         rem Calculate projected angle X using heights
         x1#=(x-1)*sizex# : y1#=h#
         x2#=x*sizex# : y2#=h4#
         dx#=x2#-x1#
         dy#=y2#-y1#
         ax#=atanfull(dx#,dy#)
         ax#=wrapvalue(90-ax#)

         rem Calculate projected angle Z using heights
         z1#=(z-1)*sizez# : y1#=h2#
         z2#=z*sizez# : y2#=h8#
         dz#=z2#-z1#
         dy#=y2#-y1#
         az#=atanfull(dz#,dy#)
         az#=wrapvalue(90-az#)

         rem Make normal from projected angle
         nx#=sin(ax#)
         ny#=cos(ax#)
         nz#=sin(az#)

         rem Setting matrix normal for smoothness
         setMemMatrixNormal(memNum,x,z,nx#,ny#,nz#)
      next x
   next z
endfunction

rem Re-calculate the normal of ONE vertex of the matrix
` Parameters:
` Memblock number, x coord of the vertex, Z coord
function ConfigureOneMemMatrixNormal(memNum,x,z)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   rem retrieve tiles size
   sizex#=memblock float(255,(memnum*16)+8)
   sizez#=memblock float(255,(memnum*16)+12)

   rem Get matrix heights
   h8#=getMemMatrixHeight(memNum,x,z-1)
   h4#=getMemMatrixHeight(memNum,x-1,z)
   h#=getMemMatrixHeight(memNum,x,z)
   h2#=getMemMatrixHeight(memNum,x,z)

   rem Calculate projected angle X using heights
   x1#=(x-1)*sizex# : y1#=h#
   x2#=x*sizex# : y2#=h4#
   dx#=x2#-x1#
   dy#=y2#-y1#
   ax#=atanfull(dx#,dy#)
   ax#=wrapvalue(90-ax#)

   rem Calculate projected angle Z using heights
   z1#=(z-1)*sizez# : y1#=h2#
   z2#=z*sizez# : y2#=h8#
   dz#=z2#-z1#
   dy#=y2#-y1#
   az#=atanfull(dz#,dy#)
   az#=wrapvalue(90-az#)

   rem Make normal from projected angle
   nx#=sin(ax#)
   ny#=cos(ax#)
   nz#=sin(az#)

   rem Setting matrix normal for smoothness
   setMemMatrixNormal(memNum,x,z,nx#,ny#,nz#)

endfunction

rem "Smooth" the matrix, giving it a more "round" look.
rem This smoothes the mesh; it does not affect the normals.
rem The more iterations you set, the more intense the smooth effect will be (it'll be slower, too).
` Parameters:
` Memblock number, nb iterations of smoothing
` (DBpro code by Phaelax, slightly adapted for DBC)
function smoothMemMatrix(memNum,iterations)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   rem store original heights
   dim heights#(tilesX,tilesZ)
   for z = 0 to tilesZ
      for x = 0 to tilesX
         heights#(x,z) = getMemMatrixHeight(memNum,x,z)
      next x
   next z

   rem Smooth the matrix by "averaging" the height of each vertex with the height of its neighbours
   for t = 1 to iterations
      for z = 0 to tilesZ
         for x = 0 to tilesX
            count = 0
            h1# = 0
            h2# = 0
            h3# = 0
            h4# = 0
            h5# = 0
            h6# = 0
            h7# = 0
            h8# = 0

           if z < tilesZ
               if x > 0 then h1# = heights#(x-1,z+1) : inc count
               h2# = heights#(x,z+1) : inc count
               if x < tilesX then h3# = heights#(x+1,z+1) : inc count
            endif

            if x > 0 then h4# = heights#(x-1,z) : inc count
            if x < tilesX then h5# = heights#(x+1,z) : inc count

            if z > 0
               if x > 0 then h6# = heights#(x-1,z-1) : inc count
               h7# = heights#(x,z-1) : inc count
               if x < tilesX then h8# = heights#(x+1,z-1) : inc count
            endif

            avg# = (h1#+h2#+h3#+h4#+h5#+h6#+h7#+h8#) / count

            setMemMatrixHeight(memNum,x,z,avg#)

         next x
      next z
   next t

   rem delete array
   undim heights#()
endfunction

rem Take a rectangle in the matrix (defined by x1,z1,x2,z2 parameters) and change its UVmapping
rem to show a certain area of the texture (defined by xtex1,ytex1,xtex2,ytex2 parameters).
` Parameters:
` memblock,image used to texture the matrix,
` width,depth of the matrix
` x1,z1,x2,z2 (in tiles coordinates, which define a rectangle wherein the mapping will be changed)
` xtex1,ytex1,xtex2,ytex2 (in pixels, which define a rectangle in the texture that will be mapped on the rectangle defined above)
` rotate (0 = no rotation; 1 = 90° ; 2 = 180° ; 3 = 270°. Rotation is trigonometric -> anti-clockwise)
` flip (0 = no flip; 1 = horizontal flip; 2 = vertical flip. You don't need "flip both" 'cos it's just like "rotate 180°")
` (Man, is it complicated! I must find a way to make it simplier...)
` Return: 0 - if you did everything right
`         1 - Memblock doesn't exist
`         2 - Texture image doesn't exist (did you load it before running this function?)
`         3 - Tiles coords given for mapping (x1,z1,x2,z2) exceed matrix limits
`         4 - Tiles coords are inverted (x1>x2 and/or z1>z2)
`         5 - Texture coords exceed texture limits (<0 or >texture size)
`         6 - Texture coords are inverted (xtex1>xtex2 and/or ytex1>ytex2)
`         7 - Rotate/flipping params exceeds limits (<0 or >3 for rotate or >2 for flipping)
function UVmapMemMatrix(memNum,imageNum,x1,z1,x2,z2,xtex1,ytex1,xtex2,ytex2,rotate,flip)
   if memblock exist(memNum) = 0 then exitfunction 1
   if image exist(ImageNum) = 0 then exitfunction 2

   rem Control parameter integrity
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)
   if x1<0 or x2>tilesX or z1<0 or z2>tilesZ then exitfunction 3
   if x1>x2 or z1>z2 then exitfunction 4
   if rotate<0 or rotate>3 or flip<0 or flip>2 then exitfunction 7

   rem Load texture into a memblock, to get its size
   make memblock from image 254,imageNum
   imageWidth#=memblock dword(254,0):imageHeight#=memblock dword(254,4)
   delete memblock 254
   if xtex2>imageWidth# or ytex2>imageHeight# or xtex1<0 or ytex1<0 then exitfunction 5
   if xtex1>=xtex2 or ytex1>=ytex2 then exitfunction 6

   rem Rotating and flipping
   dim rotx(4):dim rotz(4)
   rotx(1)=0:rotx(2)=0:rotx(3)=1:rotx(4)=1
   rotz(1)=0:rotz(2)=1:rotz(3)=1:rotz(4)=0
   nrotstart=1:mirrorboth=0
   if rotate=1 then nrotstart=2
   if rotate=2 then mirrorboth=1:rem 180° rotation = flip both axis
   if rotate=3 then nrotstart=2:mirrorboth=1:rem 270° rotation = 90�? rotation + flip both axis
   if mirrorboth=1
      select flip
         case 0
            newflip=3
         endcase
         case 1
            newflip=2
         endcase
         case 2
            newflip=1
         endcase
      endselect
      flip=newflip
   endif

   rem Useful values: Nb Tiles to remap, size of UV tiles, etc...
   UVOffset=memblock dword(memNum,28)
   nbtilesX=abs(x2-x1):nbtilesZ=abs(z2-z1)
   xtex1#=xtex1:xtex2#=xtex2:ytex1#=ytex1:ytex2#=ytex2
   subImageRatiox#=((1.00+xtex2#-xtex1#)/imageWidth#)
   subImageRatioy#=((1.00+ytex2#-ytex1#)/imageHeight#)
   Ustart#=xtex1#/imageWidth#
   Vstart#=(ytex2#+1.00)/imageHeight#
   UVtileWidth# = subImageRatiox#/(abs(nbtilesX)+1)
   UVtileDepth# = subImageRatioy#/(abs(nbtilesZ)+1)

   rem Mirroring: U and/or V directions are inverted
   if flip=1 or flip=3 then Ustart#=1.00-(subImageRatiox#+Ustart#):UVtileWidth#=UVtileWidth#*-1.00
   if flip=2 or flip=3 then Vstart#=1.00-(subImageRatioy#-Vstart#):UVtileDepth#=UVtileDepth#*-1.00

   rem remapping of the rectangle x1,z1 -> x2,z2
   for cz=0 to nbtilesZ
      for cx=0 to nbtilesX

         rem UV coords
         if rotate=1 or rotate=3
            vertCtr=((x1+cx)*tilesZ*4)+((z2-cz)*4)
         else
            vertCtr=((z1+cz)*tilesX*4)+((x1+cx)*4)
         endif
         nrot=nrotstart
         rem v0
         write memblock float memNum,UVoffset+(vertCtr*8),Ustart#+((cx+rotx(nrot))*UVtileWidth#)
         write memblock float memNum,UVoffset+(vertCtr*8)+4,Vstart#-((cz+rotz(nrot))*UVtileDepth#)
         inc vertCtr
         inc nrot:if nrot=5 then nrot=1
         rem v1
         write memblock float memNum,UVoffset+(vertCtr*8),Ustart#+((cx+rotx(nrot))*UVtileWidth#)
         write memblock float memNum,UVoffset+(vertCtr*8)+4,Vstart#-((cz+rotz(nrot))*UVtileDepth#)
         inc vertCtr
         inc nrot:if nrot=5 then nrot=1
         rem v2
         write memblock float memNum,UVoffset+(vertCtr*8),Ustart#+((cx+rotx(nrot))*UVtileWidth#)
         write memblock float memNum,UVoffset+(vertCtr*8)+4,Vstart#-((cz+rotz(nrot))*UVtileDepth#)
         inc vertCtr
         inc nrot:if nrot=5 then nrot=1
         rem v3
         write memblock float memNum,UVoffset+(vertCtr*8),Ustart#+((cx+rotx(nrot))*UVtileWidth#)
         write memblock float memNum,UVoffset+(vertCtr*8)+4,Vstart#-((cz+rotz(nrot))*UVtileDepth#)

      next cx
   next cz

endfunction 0

rem Randomize the height of all vertices in the matrix, within the range of 0 to heightrange#
` Parameters:
` Memblock number, height range
function randomizeMemMatrix(memNum,heightrange#)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   for i=0 to tilesX
      for j=0 to tilesZ
         setMemMatrixHeight(memNum,i,j,(rnd(heightrange#*256.00)/256.00))
      next j
   next i

endfunction

rem Move the pivot point of the matrix (usually the lower left corner) to the x,z center of the object
function centerMemMatrixPivot(memnum)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   rem retrieve tiles size
   sizex#=memblock float(255,(memnum*16)+8)
   sizez#=memblock float(255,(memnum*16)+12)

   rem Calculate x and z displacement we must apply to each vertex
   vertOffset=memblock dword(memNum,4)
   vertNum=memblock dword(memNum,0)
   xmove#=( memblock float(memNum,vertOffset)-memblock float(memNum,vertOffset+((vertnum-2)*12)) )/2.00
   zmove#=( memblock float(memNum,vertOffset+8)-memblock float(memNum,vertOffset+((vertnum-2)*12)+8) )/2.00

   rem Move vertex to their new position
   vertCtr=0
   for cz = 0 to tilesZ-1
      for cx = 0 to tilesX-1
         rem Vertex 0 coords
         write memblock float memNum,vertOffset+(vertCtr*12),xmove#+(cx*sizex#)
         write memblock float memNum,vertOffset+(vertCtr*12)+8,zmove#+(cz*sizez#)
         inc vertCtr
         rem Vertex 1 coords
         write memblock float memNum,vertOffset+(vertCtr*12),xmove#+(cx*sizex#)
         write memblock float memNum,vertOffset+(vertCtr*12)+8,zmove#+((cz+1)*sizez#)
         inc vertCtr
         rem Vertex 2 coords
         write memblock float memNum,vertOffset+(vertCtr*12),xmove#+((cx+1)*sizex#)
         write memblock float memNum,vertOffset+(vertCtr*12)+8,zmove#+((cz+1)*sizez#)
         inc vertCtr
         rem Vertex 3 coords
         write memblock float memNum,vertOffset+(vertCtr*12),xmove#+((cx+1)*sizex#)
         write memblock float memNum,vertOffset+(vertCtr*12)+8,zmove#+(cz*sizez#)
         inc vertCtr
      next cx
   next cz

endfunction

rem Move the pivot point of the matrix to its lower left corner (in case it has been centered before)
function restoreMemMatrixPivot(memnum)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   rem retrieve tiles size
   sizex#=memblock float(255,(memnum*16)+8)
   sizez#=memblock float(255,(memnum*16)+12)

   rem Calculate x and z displacement we must apply to each vertex
   vertOffset=memblock dword(memNum,4)
   vertNum=memblock dword(memNum,0)

   rem Move vertex to their new position
   vertCtr=0
   for cz = 0 to tilesZ-1
      for cx = 0 to tilesX-1
         rem Vertex 0 coords
         write memblock float memNum,vertOffset+(vertCtr*12),cx*sizex#
         write memblock float memNum,vertOffset+(vertCtr*12)+8,cz*sizez#
         inc vertCtr
         rem Vertex 1 coords
         write memblock float memNum,vertOffset+(vertCtr*12),cx*sizex#
         write memblock float memNum,vertOffset+(vertCtr*12)+8,(cz+1)*sizez#
         inc vertCtr
         rem Vertex 2 coords
         write memblock float memNum,vertOffset+(vertCtr*12),(cx+1)*sizex#
         write memblock float memNum,vertOffset+(vertCtr*12)+8,(cz+1)*sizez#
         inc vertCtr
         rem Vertex 3 coords
         write memblock float memNum,vertOffset+(vertCtr*12),(cx+1)*sizex#
         write memblock float memNum,vertOffset+(vertCtr*12)+8,cz*sizez#
         inc vertCtr
      next cx
   next cz

endfunction

Rem Given a heightmap (greyscale image), this function will assign the height of each
rem vertex or the matrix. White pixels mean high vertex, black ones mean height=0
` Parameters:
` Memblock number, Image number,Nb tiles on X axis, Nb tiles on Z axis,maximum height
` NB: minimum height after function call is 0
` (DBpro code by Phaelax, slightly adapted for DBC)
function setMemMatrixFromHeightmap(memNum,ImageNum,maxheight#)
   if image exist(ImageNum) = 0 then exitfunction

   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   rem create a memblock from the image
   make memblock from image 254, imageNum

   rem get image dimensions
   width = memblock dword(254, 0)
   height = memblock dword(254, 4)
   depth = memblock dword(254, 8)

   rem pixel offset for configuring match between pixel and tile number
   xsegs# = tilesX
   zsegs# = tilesZ
   ox# = width/(xsegs#+1.0)
   oz# = height/(zsegs#+1.0)

   rem 16 or 32
   mode = depth

   for z = 0 to tilesZ
      for x = 0 to tilesX
         if mode = 16
            pos = (int((tilesZ-z)*oz#)*width + int(x*ox#))*2 + 12
            c = memblock word(254, pos)
            c = ((c/2048)&31)*8
         endif
         if mode = 32
            pos = (int((tilesZ-z)z*oz#)*width + int(x*ox#))*4 + 12
            c = memblock byte(254, pos)
         endif
         h# = (c*maxHeight#)/255.0
         setMemMatrixHeight(memNum, x, z, h#)
      next x
   next z

   delete memblock 254
endfunction

Rem Export the matrix heightmap to disk
` Parameters:
` Memblock number, file name of the heightmap
` (DBpro code by Phaelax, slightly adapted for DBC)
function saveMemMatrixHeightmap(memNum,filename$)
   if file exist(filename$) then delete file filename$

   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   highpt# = 0
   lowpt# = 0
   for x=0 to tilesX
      for z=0 to tilesZ
         h# = getMemMatrixHeight(memNum,x,z)
         if h# > highpt# then highpt# = h#
         if h# < lowpt# then lowpt# = h#
      next z
   next x

   lowpt# = abs(lowpt#)

   width = tilesX+1
   height = tilesZ+1
   size = width*height*4 + 12
   make memblock 254, size
   write memblock dword 254, 0, width
   write memblock dword 254, 4, height
   write memblock dword 254, 8, 32

   for z=0 to tilesZ
      for x=0 to tilesX
         h# = getMemMatrixHeight(memNum,x,z) + lowpt#
         color = (h# * 255) / highpt#
         location = ((tilesZ-z)*width + x)*4 + 12
         write memblock dword 254, location, rgb(color, color, color)
      next x
   next z

   make image from memblock 254, 254
   save image filename$, 254

   delete memblock 254
   delete image 254

endfunction

rem Move all tiles one step "down" (along the Z axis), with a wrapping effect
rem -> the first line of tiles become the last, the other lines go down.
` Parameters:
` Memblock number
function shiftMemMatrixDown(memNum)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   vertOffset=memblock dword(memNum,4)
   lineSize=tilesX*48
   otherLineSize=((tilesZ-1)*lineSize)
   memsize=get memblock size(memNum)
   vertCtr=vertOffset

   rem Create a memblock and save the first line
   make memblock 254,memsize
   copy memblock 1,254,vertCtr,vertOffset,lineSize

   rem For each tile (except those in the first line), copy the vertex height to the tile beneath
   vertCtr2=vertOffset+4
   vertCtr=vertCtr2+lineSize
   numtiles=tilesX*(tilesZ-1)
   for i=1 to numtiles
         copy memblock memNum,memNum,vertCtr,vertCtr2,4
         copy memblock memNum,memNum,vertCtr+12,vertCtr2+12,4
         copy memblock memNum,memNum,vertCtr+24,vertCtr2+24,4
         copy memblock memNum,memNum,vertCtr+36,vertCtr2+36,4
         inc vertCtr,48
         inc vertCtr2,48
   next i

   rem Restore the first line and put it to the top
   vertCtr=vertOffset+4
   vertCtr2=vertCtr+otherLineSize
   for cx=1 to tilesX
      copy memblock 254,memNum,vertCtr,vertCtr2,4
      copy memblock 254,memNum,vertCtr+12,vertCtr2+12,4
      copy memblock 254,memNum,vertCtr+24,vertCtr2+24,4
      copy memblock 254,memNum,vertCtr+36,vertCtr2+36,4
      inc vertCtr,48
      inc vertCtr2,48
   next cx

   rem Data offsets and sizes for faces, normals, UV
   normOffset=memblock dword(memNum,12)
   faceOffset=memblock dword(memNum,20)
   faceSize=memblock dword(memNum,24)
   UVOffset=memblock dword(memNum,28)
   UVlineSize = tilesX*32

   rem copy the first line to the last of the new memblock
   normdecal=normOffset+((tilesZ-1)*lineSize)
   UVdecal=UVOffset+((tilesZ-1)*UVLineSize)
   copy memblock memNum,254,normOffset,normdecal,lineSize
   copy memblock memNum,254,UVoffset,UVdecal,UVLineSize

   rem copy the rest of the lines
   copy memblock memNum,254,normOffset+lineSize,normOffset,((tilesZ-1)*lineSize)
   copy memblock memNum,254,UVoffset+UVLineSize,UVOffset,((tilesZ-1)*UVLineSize)

   rem copy header and vertices infos
   copy memblock memNum,254,0,0,normOffset

   rem Copy faces
   copy memblock memNum,254,faceOffset,faceOffset,faceSize*4

   rem Copy the new memblock to the old one
   copy memblock 254,memNum,0,0,memSize
   delete memblock 254

endfunction

rem Move all tiles one step "up" (along the Z axis), with a wrapping effect
rem -> the last line of tiles become the first, the other lines go up.
` Parameters:
` Memblock number
function shiftMemMatrixUp(memNum)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   memsize=get memblock size(memNum)
   vertOffset=memblock dword(memNum,4)
   lineSize=tilesX*48
   otherLineSize=((tilesZ-1)*lineSize)
   vertCtr=vertOffset+otherLineSize

   rem Create a memblock and save the last line
   make memblock 254,memsize
   copy memblock 1,254,vertCtr,vertCtr,lineSize

   rem For each tile (except those in the last line), copy the vertex height to the tile above
   numtiles=tilesX*(tilesZ-1)
   vertCtr=vertOffset+4+otherLineSize-48
   vertCtr2=vertCtr+lineSize
   for i=1 to numtiles
      copy memblock memNum,memNum,vertCtr,vertCtr2,4
      copy memblock memNum,memNum,vertCtr+12,vertCtr2+12,4
      copy memblock memNum,memNum,vertCtr+24,vertCtr2+24,4
      copy memblock memNum,memNum,vertCtr+36,vertCtr2+36,4
      dec vertCtr,48
      dec vertCtr2,48
   next i

   rem Restore the last line and put it to the bottom
   vertCtr2=vertOffset+4
   vertCtr=vertCtr2+otherLineSize
   for cx=1 to tilesX
      copy memblock 254,memNum,vertCtr,vertCtr2,4
      copy memblock 254,memNum,vertCtr+12,vertCtr2+12,4
      copy memblock 254,memNum,vertCtr+24,vertCtr2+24,4
      copy memblock 254,memNum,vertCtr+36,vertCtr2+36,4
      inc vertCtr,48
      inc vertCtr2,48
   next cx

   rem Data offsets and sizes for faces, normals, UV
   normOffset=memblock dword(memNum,12)
   faceOffset=memblock dword(memNum,20)
   faceSize=memblock dword(memNum,24)
   UVOffset=memblock dword(memNum,28)
   UVlineSize = tilesX*32

   rem copy the last line to the first of the new memblock
   normdecal=normOffset+otherLineSize
   UVdecal=UVOffset+((tilesZ-1)*UVLineSize)
   copy memblock memNum,254,normdecal,normOffset,lineSize
   copy memblock memNum,254,UVdecal,UVoffset,UVLineSize

   rem copy the rest of the lines
   copy memblock memNum,254,normOffset,normOffset+lineSize,otherLineSize
   copy memblock memNum,254,UVOffset,UVoffset+UVLineSize,((tilesZ-1)*UVLineSize)

   rem copy header and vertices infos
   copy memblock memNum,254,0,0,normOffset

   rem Copy faces
   copy memblock memNum,254,faceOffset,faceOffset,faceSize*4

   rem Copy the new memblock to the old one
   copy memblock 254,memNum,0,0,memSize
   delete memblock 254

endfunction

rem Move all tiles one step left (along the X axis), with a wrapping effect
rem -> the first column of tiles become the last, the other columns go left.
` Parameters:
` Memblock number
function shiftMemMatrixLeft(memNum)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   rem Get datas sizes
   memsize=get memblock size(memNum)
   vertOffset=memblock dword(memNum,4)
   normOffset=memblock dword(memNum,12)
   faceOffset=memblock dword(memNum,20)
   faceSize=memblock dword(memNum,24)
   UVOffset=memblock dword(memNum,28)

   rem Useful values
   lineSize=tilesX*48
   lineMinusOneColumn=lineSize-48
   vertCtr=vertOffset+4+48
   vertCtr2=vertOffset+4
   vertCtr3=vertOffset+4
   vertCtr4=vertCtr3+lineMinusOneColumn
   UVlineSize = tilesX*32
   normCtr=normOffset
   uvCtr=UVOffset

   rem Create a memblock to store modified matrix
   make memblock 254,memsize

   rem For each line:
   for cz=1 to tilesZ
      rem Save the first column
      copy memblock memNum,254,vertCtr3,vertCtr3,40
      rem Shift each tile to the left
      for cx=2 to tilesX
         copy memblock memNum,memNum,vertCtr,vertCtr2,4
         copy memblock memNum,memNum,vertCtr+12,vertCtr2+12,4
         copy memblock memNum,memNum,vertCtr+24,vertCtr2+24,4
         copy memblock memNum,memNum,vertCtr+36,vertCtr2+36,4
         inc vertCtr,48
         inc vertCtr2,48
      next cx
      inc vertCtr,48
      inc vertCtr2,48

      rem Restore first column and put it at the right of the line
      copy memblock 254,memNum,vertCtr3,vertCtr4,4
      copy memblock 254,memNum,vertCtr3+12,vertCtr4+12,4
      copy memblock 254,memNum,vertCtr3+24,vertCtr4+24,4
      copy memblock 254,memNum,vertCtr3+36,vertCtr4+36,4
      inc vertCtr3,lineSize
      inc vertCtr4,lineSize

      rem copy shifted Normals and UV to memblock 254
      copy memblock memNum,254,normCtr+48,normCtr,lineMinusOneColumn
      copy memblock memNum,254,normCtr,normCtr+lineMinusOneColumn,48

      copy memblock memNum,254,UvCtr+32,UvCtr,UVlineSize-32
      copy memblock memNum,254,UvCtr,UvCtr+UVlineSize-32,32

      inc normCtr,lineSize
      inc UvCtr,UVlineSize
   next cz

   rem copy header and shifted vertices infos to memblock 254
   copy memblock memNum,254,0,0,normOffset

   rem Copy faces to memblock 254
   copy memblock memNum,254,faceOffset,faceOffset,faceSize*4

   rem Copy the new memblock to the old one
   copy memblock 254,memNum,0,0,memSize
   delete memblock 254

endfunction

rem Move all tiles one step right (along the X axis), with a wrapping effect
rem -> the last column of tiles become the first, the other columns go right.
` Parameters:
` Memblock number
function shiftMemMatrixRight(memNum)
   tilesX=memblock Dword(255,memnum*16)
   tilesZ=memblock Dword(255,(memnum*16)+4)

   rem Get datas sizes
   memsize=get memblock size(memNum)
   vertOffset=memblock dword(memNum,4)
   normOffset=memblock dword(memNum,12)
   faceOffset=memblock dword(memNum,20)
   faceSize=memblock dword(memNum,24)
   UVOffset=memblock dword(memNum,28)

   rem Useful values
   UVlineSize = tilesX*32
   normCtr=normOffset
   uvCtr=UVOffset
   lineSize=tilesX*48
   lineMinusOneColumn=lineSize-48
   vertCtr2=normOffset+4-48
   vertCtr=vertCtr2-48
   vertCtr3=vertCtr2
   vertCtr4=vertCtr2-lineMinusOneColumn

   rem Create a memblock to store modified matrix
   make memblock 254,memsize

   rem For each line:
   for cz=1 to tilesZ
      rem Save the last column
      copy memblock memNum,254,vertCtr3,vertCtr3,40
      rem Shift each tile to the right
      for cx=2 to tilesX
         copy memblock memNum,memNum,vertCtr,vertCtr2,4
         copy memblock memNum,memNum,vertCtr+12,vertCtr2+12,4
         copy memblock memNum,memNum,vertCtr+24,vertCtr2+24,4
         copy memblock memNum,memNum,vertCtr+36,vertCtr2+36,4
         dec vertCtr,48
         dec vertCtr2,48
      next cx
      dec vertCtr,48
      dec vertCtr2,48

      rem Restore last column and put it at the left of the line
      copy memblock 254,memNum,vertCtr3,vertCtr4,4
      copy memblock 254,memNum,vertCtr3+12,vertCtr4+12,4
      copy memblock 254,memNum,vertCtr3+24,vertCtr4+24,4
      copy memblock 254,memNum,vertCtr3+36,vertCtr4+36,4
      dec vertCtr3,lineSize
      dec vertCtr4,lineSize

      rem copy shifted Normals and UV to memblock 254
      copy memblock memNum,254,normCtr,normCtr+48,lineMinusOneColumn
      copy memblock memNum,254,normCtr+lineMinusOneColumn,normCtr,48

      copy memblock memNum,254,UvCtr,UvCtr+32,UVlineSize-32
      copy memblock memNum,254,UvCtr+UVlineSize-32,UvCtr,32

      inc normCtr,lineSize
      inc UvCtr,UVlineSize
   next cz

   rem copy header and shifted vertices infos to memblock 254
   copy memblock memNum,254,0,0,normOffset

   rem Copy faces to memblock 254
   copy memblock memNum,254,faceOffset,faceOffset,faceSize*4

   rem Copy the new memblock to the old one
   copy memblock 254,memNum,0,0,memSize
   delete memblock 254

endfunction

Rem Dump the matrix datas to disk
` Parameters:
` Memblock number, name of the file to which write the data
function dumpMemMatrix(memNum,filename$)
   if memblock exist(memNum) = 0 then exitfunction

   vertNum=memblock dword(memNum,0)
   vertOffset=memblock dword(memNum,4)
   normNum=memblock dword(memNum,8)
   normOffset=memblock dword(memNum,12)
   faceNum=memblock dword(memNum,16)
   faceOffset=memblock dword(memNum,20)
   faceSize=memblock dword(memNum,24)
   UVOffset=memblock dword(memNum,28)

   memSize = 32 + (12*vertNum) + (12*vertNum) + (28*faceNum) + (8*vertNum)

   if file exist(filename$) then delete file filename$
   open to write 1,filename$

   write string 1, "Memblock size = "+str$( get memblock size(memNum) )
   write string 1, "Nb vertex = "+str$(memblock dword(memNum,0))
   write string 1, "Vertex infos offset = "+str$(memblock dword(memNum,4))
   write string 1, "Nb normals = "+str$(memblock dword(memNum,8))
   write string 1, "Normals infos offset = "+str$(memblock dword(memNum,12))
   write string 1, "Nb Faces = "+str$(memblock dword(memNum,16))
   write string 1, "Faces infos offset = "+str$(memblock dword(memNum,20))
   write string 1, "Faces infos size = "+str$(memblock dword(memNum,24))
   write string 1, "UV infos offset = "+str$(memblock dword(memNum,28))

   write string 1,chr$(13)

   vertCtr = 0
   faceCtr = 0
   UvCtr = 0

   for i=0 to vertnum-1
         write string 1,"vertex "+str$(i)
         write string 1, str$(memblock float(memNum,vertOffset+(i*12)))+","+str$(memblock float(memNum,vertOffset+(i*12)+4))+","+str$(memblock float(memNum,vertOffset+(i*12)+8))
         write string 1, str$(memblock float(memNum,normOffset+(i*12)))+","+str$(memblock float(memNum,normOffset+(i*12)+4))+","+str$(memblock float(memNum,normOffset+(i*12)+8))
         write string 1,""
   next i
   write string 1,""
   for faceCtr=0 to facenum-1
         write string 1,"":write string 1,"Faces "+str$(faceCtr)
         f$=""
         f$=str$(memblock dword(memNum,faceOffset+(faceCtr*28)))+","+str$(memblock dword(memNum,faceOffset+(faceCtr*28)+4))+","+str$(memblock dword(memNum,faceOffset+(faceCtr*28)+8))
         f$=f$+","+str$(memblock dword(memNum,faceOffset+(faceCtr*28)+12))
         f$=f$+","+str$(memblock dword(memNum,faceOffset+(faceCtr*28)+16))+","+str$(memblock dword(memNum,faceOffset+(faceCtr*28)+20))+","+str$(memblock dword(memNum,faceOffset+(faceCtr*28)+24))
         write string 1,f$
         write string 1,""
   next faceCtr
   write string 1,"":write string 1,""
   for uvCtr=0 to vertnum-1
         write string 1,"":write string 1,"UV for vertex "+str$(UVCtr)
         write string 1, str$(memblock float(memNum,UVoffset+(UvCtr*8)))+","+str$(memblock float(memNum,UVoffset+(UvCtr*8)+4))
         write string 1,""
   next uvCtr

   close file 1

endfunction