remstart
   ==============================================================
   =  Title  : DBC Challenge - under water Create Fish Mesh
   =  Author : latch
   =  Date   : 01/15/2008
   =  Update : 01/17/2008
   =  Version: .03
   ==============================================================
   Comments    This is an example of how to build a mesh triangle
               by triangle without using memblocks.  The function
               make_fish() will create a mesh that is supposed to
               look like a cute little fishy!  For moveable fins
               and tail I just added a few primatives.
               the parameters are:
               make_fish(obj,size#,tiers)
               obj == the object number the fish will be
               size# == the x size of the body (not including tail)
               tiers == tiers^2 * 2 = number of polys (triangles)
               The minimum tiers is 4.  Going above ten is not
               a great idea.
               I tried to use a very basic method of creating 2
               grids - front and back, and then just pinching the
               ends together, separating the middle area (z) and
               then plotting the x and y with a bit of skewing on
               the y for the head and tail.  There are better
               ways to do this for a shape rounded like a fish,
               like multiple ellipse shaped rings, but I wanted
               to keep the math as basic as possible for the demo.
               I did use a parabola for the head, and that's about
               as complex as the math got!  The size of the function
               is due to the drawing of the triangles and limbs.
               The math to place the points is the smallest part.
 
               Building each model can be slow, but if a single
               model is built, it can be converted into a mesh
               and copies from it will be made much faster using
               MAKE OBJECT.
   ==============================================================
remend
 
rem =============================================================
rem = SET UP DISPLAY
rem =============================================================
   autocam off
   set display mode 800,600,32
   sync on
   sync rate 60
 
rem =============================================================
rem = MAIN
rem =============================================================
   gosub _init
   position camera 0,0,-100
   direction=1
   do
      turn object left fish1,.3
      turn object left fish2,.3
      turn object left fish3,.3
 
      ang#=wrapvalue(ang#+direction)
      if ang# = 6 then direction=-1
      if ang# = 354 then direction=1
 
      rotate limb fish1,1,limb angle x(fish1,1),wrapvalue(ang#*2),limb angle z(fish1,1)
      rotate limb fish2,1,limb angle x(fish2,1),ang#,limb angle z(fish2,1)
      rotate limb fish3,1,limb angle x(fish3,1),ang#,limb angle z(fish3,1)
 
 
      sync
   loop
 
   end
 
rem =============================================================
rem = SUBROUTINES - PROCEDURES
rem =============================================================
   _init:
      rem fish
      fish1=1
      fish2=2
      fish3=3
      fish4=4
 
      rem textures
      gosub _textures
 
      rem make fish
      make_fish(fish1,40.0,4)
      texture object fish1,fish1
      position object fish1,-30,0,0
 
      make_fish(fish2,40.0,7)
      texture object fish2,fish2
      position object fish2,30,0,0
 
      make_fish(fish3,40.0,10)
      texture object fish3,fish3
      position object fish3,0,-30,0
   return
`-----------------------------------------------------------------
   _textures:
      cls 0
      ink rgb(255,0,0),0
      dot 0,0
      dot 0,1
      get image fish1,0,0,2,2
 
      cls 0
      ink rgb(255,255,0),0
      dot 0,0
      dot 1,0
      get image fish2,0,0,2,2
 
      cls 0
      ink rgb(0,255,0),0
      dot 1,0
      dot 1,1
      get image fish3,0,0,2,2
 
   return
 
rem =============================================================
rem = FUNCTIONS
rem =============================================================
function make_fish(obj,size#,tiers)
   rem make sure the minimum is 4x4
   if tiers < 4 then tiers  = 4
 
   rem set up vertice plotting variables
   xinc#=size#/tiers
   yinc#=xinc#/3
   zinc#=size#/12.0
   tailx#=size#/4.0
   taily#=((tiers-1)/2.0)*yinc#
   mid=(tiers-1)/2
 
 
   rem array to hold points
   dim verts#((tiers^2)*2,2)
 
   rem go through x and y positions and calculate points for triangles
   for y=0 to tiers-1
      for x=0 to tiers-1
         rem v=vertices for front
         rem v2=vertices for back so we only have to run through one set of points
         v=x+(y*tiers)
         v2=v+tiers^2
 
         rem front side
         rem check if we are at the tail
         if x=tiers-1
            verts#(v,0)=(x*xinc#)+tailx#
            verts#(v,1)=taily#
         else
            rem check if we are at the head
            if x <= mid-1
               rem upper parabola for the top of the head
               rem change the head size by changing 3.5 in (x*xinc#/3.5)
               if y > mid
                  verts#(v,1)=taily#+sqrt(4*(y*yinc#/2)*(x*xinc#/3.5))
                  verts#(v,0)=x*xinc#/1.5
               endif
               rem plot the lower parabola for the bottom of the head
               if y <= mid
                  verts#(v,1)=taily#-sqrt(4*((taily#-y)*yinc#/2)*(x*xinc#/3.5))
                  verts#(v,0)=x*xinc#/1.5
               endif
            else
               rem default x and y
               verts#(v,0)=x*xinc#
               verts#(v,1)=y*yinc#
            endif
         endif
 
         rem z values.  The logic checks if we are at any edge of the grid
         rem and if so, it sets z=0 effectively "pinching" the ends closed
         rem if we are not at an edge, the -1.0 pushed the z value outwards
         rem towards the viewer (-z) by zinc#
         verts#(v,2)=-1.0*(zinc#*((y!0) & (y!tiers-1) & (x!0) & (x!tiers-1)))
 
         rem backside
         rem same x and y values, and opposite z values from front grid
         verts#(v2,0)=verts#(v,0)
         verts#(v2,1)=verts#(v,1)
         verts#(v2,2)=0.0-verts#(v,2)
      next x
   next y
   rem make triangles
   tri=obj
   lmb=0
   for y=0 to tiers-2
      for x=0 to tiers-2
         v=x+(y*tiers)
         v2=v+tiers^2
 
         rem triangle 1
         x1#=verts#(v,0)
         y1#=verts#(v,1)
         z1#=verts#(v,2)
 
         x2#=verts#(v+tiers,0)
         y2#=verts#(v+tiers,1)
         z2#=verts#(v+tiers,2)
 
         x3#=verts#(v+tiers+1,0)
         y3#=verts#(v+tiers+1,1)
         z3#=verts#(v+tiers+1,2)
 
         rem this check is here to make sure we don't overwrite
         rem the object we are assigning to the fish since we reuse
         rem and delete the same object and mesh over and over
         rem to manage overhead as we go
         while object exist(tri)=1
            inc tri
         endwhile
 
         make object triangle tri,x1#,y1#,z1#,x2#,y2#,z2#,x3#,y3#,z3#
         rem the first triangle is the root object of the mesh initially
         rem so we don't want to turn it into a limb
         if v<>0
            make mesh from object tri,tri
            inc lmb
            add limb obj,lmb,tri
            delete object tri
            delete mesh tri
         endif
 
         rem triangle 2
         x1#=verts#(v+tiers+1,0)
         y1#=verts#(v+tiers+1,1)
         z1#=verts#(v+tiers+1,2)
 
         x2#=verts#(v+1,0)
         y2#=verts#(v+1,1)
         z2#=verts#(v+1,2)
 
         x3#=verts#(v,0)
         y3#=verts#(v,1)
         z3#=verts#(v,2)
 
         rem if we successfully created the first triangle, we
         rem want to make sure to skip that as an object to
         rem manipulate
         while object exist(tri)=1
            inc tri
         endwhile
 
         make object triangle tri,x1#,y1#,z1#,x2#,y2#,z2#,x3#,y3#,z3#
         inc lmb
         make mesh from object tri,tri
         add limb obj,lmb,tri
         delete object tri
         delete mesh tri
 
         rem back
         rem triangle 1
         x1#=verts#(v2,0)
         y1#=verts#(v2,1)
         z1#=verts#(v2,2)
 
         x2#=verts#(v2+tiers,0)
         y2#=verts#(v2+tiers,1)
         z2#=verts#(v2+tiers,2)
 
         x3#=verts#(v2+tiers+1,0)
         y3#=verts#(v2+tiers+1,1)
         z3#=verts#(v2+tiers+1,2)
 
         make object triangle tri,x1#,y1#,z1#,x2#,y2#,z2#,x3#,y3#,z3#
         inc lmb
         make mesh from object tri,tri
         add limb obj,lmb,tri
         delete object tri
         delete mesh tri
 
         rem triangle 2
         x1#=verts#(v2+tiers+1,0)
         y1#=verts#(v2+tiers+1,1)
         z1#=verts#(v2+tiers+1,2)
 
         x2#=verts#(v2+1,0)
         y2#=verts#(v2+1,1)
         z2#=verts#(v2+1,2)
 
         x3#=verts#(v2,0)
         y3#=verts#(v2,1)
         z3#=verts#(v2,2)
 
         make object triangle tri,x1#,y1#,z1#,x2#,y2#,z2#,x3#,y3#,z3#
         inc lmb
         make mesh from object tri,tri
         add limb obj,lmb,tri
         delete object tri
         delete mesh tri
 
      next x
   next y
 
   rem make a whole mesh of the body to eliminate the hundreds of limbs
   rem just created
   make mesh from object obj,obj
   delete object obj
   make object obj,obj,0
   delete mesh obj
 
   rem reset limb count
   lmb=0
 
   rem add a tail
   tail=obj+1
   while object exist(tail)
      inc tail
   endwhile
   make object cone tail,size#/2.0
   rem set tail pivot
   position object tail,0,-1.0*object size y(tail)/2,0
   scale object tail,100,100,10
   make mesh from object tail,tail
   delete object tail
   inc lmb
   add limb obj,lmb,tail
   offset limb obj,lmb,size#/1.2,taily#,0
   rotate limb obj,lmb,0,0,90
   delete mesh tail
 
   rem top fin
   make object box tail,size#/4,size#/4,zinc#/8
   make mesh from object tail,tail
   delete object tail
   inc lmb
   add limb obj,lmb,tail
   offset limb obj,lmb,size#/2,taily#*1.8,0
   rotate limb obj,lmb,0,0,38
 
   rem left fin
   rem set pivot
   make object tail,tail,0
   position object tail,object size x(tail)/2,0,0
   rotate object tail,0,30,45
   delete mesh tail
   make mesh from object tail,tail
   delete object tail
   inc lmb
   add limb obj,lmb,tail
   offset limb obj,lmb,size#/4,taily#,zinc#*-1.5
   scale limb obj,lmb,70,70,70
 
   rem right fin
   inc lmb
   add limb obj,lmb,tail
   rotate limb obj,lmb,180,0,0
   offset limb obj,lmb,size#/3,taily#,zinc#*1.5
   scale limb obj,lmb,70,70,70
   delete mesh tail
 
   rem turn culling off because individual triangles only have one direction
   rem for their normals no matter how they are rotated as a limb after
   rem creting them as a mesh.  Otherwise, there will be holes in the mesh
   set object obj,1,1,0
endfunction