  static ShapeObject SqPanel
  '
  def CreateSqPanel
  =================
  'VERTICES FOR SQUARE PANELS
  float m=-1,l=1,o=0
  SqPanel.init
  SqPanel.ClearVertex
  SqPanel.PutVertex float {
  '------------------------------------
  'VERTEX  NORMAL  TEXCOR
  '------------------------------------
  'FRONT
  m,m,o,   o,o,l,  o,o,  'lower left 
  l,m,o,   o,o,l,  l,o,  'lower right 
  l,l,o,   o,o,l,  l,l,  'upper right
  m,l,o,   o,o,l,  o,l   'upper left

  '------------------------------------
  },32 '8x4 floats SQUARE PANEL
  '
  'ELEMENTS FOR SQUARE PANELS
  '--------------------------
  SqPanel.ClearIndex
  SqPanel.PutIndex int {
    0,1,2, 2,3,0
  },6,GL_TRIANGLES '6 ints
  '
  loadidentity
  savematrix tm
  SqPanel.ClearMatrix
  SqPanel.Putmatrix tm,16
  SqPanel.Transfer 'transfer all data to GPU
  end def


  macro BuildTorus(boa)
  =====================
  '
  static ShapeObject boa
  boa.init
  float rmin=1.0
  float rmaj=3.0
  '
  'MINOR
  'create circle of points around minor centre
  string srn=nuls(37*6*4)
  float rn at strptr(srn)
  float x,y,z
  int i
  for i=0 to 360 step 10 '36+1 overlap
    x=cos(rad(i))
    y=-sin(rad(i)) 'go clockwise
    z=0
    rn[0]=x
    rn[1]=y
    rn[2]=z
    rn[3]=x 'norm
    rn[4]=y 'norm
    rn[5]=z 'norm
    @rn+=24
  next
  @rn=strptr(srn) 'reset
  '
  'MAJOR
  'sweep circle of points around major centre
  string srm=nuls(37*37*8*4)
  float rm at strptr srm
  int ct1,ct2 'texture mapping
  int st1=1, st2=1
  float mt1=0.999/18, mt2=0.999/6
  int i,j
  for j=0 to 360 step 10 '36 and 1 overlap
    x=cos(rad(j))
    z=-sin(rad(j)) 'go anti clockwise
    for i=0 to 360 step 10 '36 and 1 overlap
      rm[0]=x*(rmaj+rn[0])
      rm[1]=rn[1]
      rm[2]=z*(rmaj+rn[0])
      '
      rm[3]=x*rn[3] 'norm x
      rm[4]=rn[4] 'norm y
      rm[5]=z*rn[3] 'norm z
      '
      rm[6]=mt1*ct1 'texture u
      rm[7]=mt2*ct2 'texture v
      'cycle texture u coords
      ct1+=st1
      '0 1 2 3 4 3 2 1 0 .. ' mirroring textures
      if ct1>18 then st1=-st1 : ct1=17 'reversal
      if ct1<0 then st1=-st1 : ct1=1
      @rn+=24 'stride 6 floats
      @rm+=32 'stride 8 floats
    next 'i
    @rn=strptr(srn) 'reset for next circle
    'cycle texture v coords
    ct1=0 : st1=1 'reset
    ct2+=st2
    if ct2>6 then st2=-st2 : ct2=5 'reversal
    if ct2<0 then st2=-st2 : ct2=1
  next 'j
  @rm=strptr(srm) 'reset 37*37*8 floats
  boa.ClearVertex
  int e=37*37*8
  boa.putVertex rm,e '8 floats per set of vertex attributes
  srm="" : srn=""

  '
  static string sel
  sel=nuls(36*36*6*4) '(ct*4 ints)
  int el at strptr sel
  int e=36*36*6
  int k=0
  int i
  for i=0 to 35 '36 circle iterations
    for j=0 to 35 '36 point iterations
      'whole triangles anticlockwise
      el[0]=k'0  'lower right triangle
      el[1]=k+1
      el[2]=k+38
      el[3]=k+38  'upper left triangle
      el[4]=k+37
      el[5]=k'0
      @el+=24 'byte stride of 6 ints
      k+=1 'next point set
    next
    k+=1 'skip 37th
  next
  @el=strptr sel 'reset el to base
  boa.ClearIndex
  boa.putIndex el,e,GL_TRIANGLES
  'sel=""


  boa.Transfer 'transfer all buffer data from client 

  end macro 'CreateTorus


  macro BuildSphereFace(boc)
  ==========================
  static ShapeObject boc
  boc.init
  int ns=4
  int ct=ns+ns+1
  int i=-ns, j=-ns, ei=ns, ej=ns
  float a,b,sx,sy,sz,cz
  string s=nuls(4*8*ct*ct)
  float f at strptr s
  i=-ns
  while i<=ei
    j=-ns
    float cd=0.5/ns 'texture strider
    while j<=ej
      sy=i/ei
      sx=j/ej
      'sz=1.0
      '
      'normalize for sphere
      a=1/sqr(sx*sx + sy*sy + 1.0)
      sx*=a : sy*=a : sz=a
      '
      'normalize for cylinder
      'a=1/sqr(sx*sx + 1.0)
      'sx*=a : sz=a
      '
      'normalize for cone
      'a=1/sqr(sx*sx + 1.0)
      'b=(i+ei)/ct
      'sx*=a*b : sz=a*b
      '
      'vertex position
      f[0]=sx
      f[1]=sy
      f[2]=sz
      'normals same
      f[3]=sx
      f[4]=sy
      f[5]=sz
      'texture coords
      f[6]=(j+ej)*cd 'u 
      f[7]=(i+ei)*cd 'v
      @f+=32 'byte stride of 8 floats
      j++
    wend
    i++
  wend
  @f=strptr s 'reset f to base
  boc.ClearVertex
  boc.putVertex f,8*ct*ct '8 floats per set of vertex attributes
  s=""

  string s=nuls(ct*ct*3*2*4) '(ct*ct*3*2 ints)
  int el at strptr s
  int e=ct*ct*6
  int k=0
  for i=0 to ct-2
  for j=0 to ct-2
    el[0]=j+k'0  'lower right triangle
    el[1]=j+k+1
    el[2]=j+k+ct+1
    el[3]=j+k+ct+1  'upper left triangle
    el[4]=j+k+ct
    el[5]=j+k'0
    @el+=24 'byte stride of 6 ints
  next
  k+=ct
  next
  @el=strptr s 'reset el to base
  boc.ClearIndex
  boc.putIndex el,e,GL_TRIANGLES
  s=""
  '
  loadidentity
  savematrix tm
  boc.clearmatrix
  boc.putmatrix tm,16

  boc.Transfer 'transfer all buffer data from client
  '
  end macro 'CreateSphereFace


  type tParticle
  ===============
  float x,y,z
  float xsize,ysize,speed,angle
  float r,g,b
  sys   tex
  end type



  ===============
  class cloudMist
  ===============
  tparticle p[100]
  '
  method Render(sys en)
  sys       i,e
  tparticle q at (@p)
  static float fr=2*0.0167 '1/60
  static int texsetup
  if not texsetup
    'b background
    'h half
    'f forground
    int f,b,h
    f=0xffffffff : h=0x40ffffff : b=0x00ffffff
    '
    CreateSynthTexture simgc1, int {
    b,b,b,b,
    b,f,h,b,
    b,h,f,b,
    b,b,b,b
    }, bytesof
    '
    f=0xffffffff : h=0x40ffff80 : b 0x00ffffff
    CreateSynthTexture simgc2, int {
    b,b,b,b,
    b,f,h,b,
    b,h,f,b,
    b,b,b,b
    }, bytesof
    texsetup=1
  endif
  e=en
  for i = 1 to e
  if q.x > 5 or q.speed=0
    'renew
    static int n
    n=1-n 'toggle 0 and 1
    q.x     = Rnd()*.5
    q.y     = 0
    q.z     = -e*.1 / i 'z layers
    q.xsize = .01+aRnd()*0.02
    q.ysize = .01+aRnd()*0.01
    q.Speed = .05+aRnd()*.02
    q.Angle = aRnd()*360
    q.tex   = simgc1 + n
  else    
    q.xsize += .12*fr
    q.ysize += .10*fr
    q.x     += .9*q.Speed*fr
    q.y     += .3*q.Speed*fr
    'glBindTexture GL_TEXTURE_2D,q.tex
    'if q.x>.5
    '  'glColor4f .99,.99,.99,.7-q.x *.7 'fades with xdistance
    'else
    '  'glColor4f .99,.99,.99,q.x*.7 'increases with xdistance
    'end if
    '
    ShaderTexture shaderMaj.t0, 0, q.tex 't0 FOR COLOR TEXTURE
    ShaderVector4 ShaderMaj.v0, 1, float {1,1,1,.1}       'TINT
    ShaderVector4 ShaderMaj.v4, 1, float {0.0,0.0,0.0, -10000.0}  'FOG COLOR AND DIST LIMIT
    '
    'Draw
    PushMatrix
    LoadIdentity   
    Translatef q.x, q.y, q.z
    q.angle+=.03
    Scalef q.xsize,q.ysize,1.0
    Rotatef q.angle, 0, 0, 1
    SaveMatrix tm
    with SqPanel
      .ClearMatrix
      .PutMatrix(tm,16)
      .TransferMatrix
      .Render
    end with
   PopMatrix   
  end if
  @q+=sizeof tparticle
  next  
  end method
  '
  end class



  type ShapeProfile
  =================
  float px,py,pz  'position
  float nx,ny,nz  'normal
  float ax,ay,az  'angle for bending
  float tx,ty     'texture mapping
  end type

  sub CalcNormXY(ShapeProfile*p,int n)
  ====================================
  'CREATE SMOOTH NORMALS
  int i,k
  double c,d,f
  for i=0 to n-1
    k=i+1
    if k>=n then
      k=i-1
      p[i].nx=p[k].nx
      p[i].ny=p[k].ny
      exit for
    end if
    p[i].nx=1
    c=p[k].px-p[i].px
    d=p[k].py-p[i].py
    p[i].nx= d
    p[i].ny=-c
  next
  'ADJUST NORMALS: mean of 2 slopes
  for i=n-2 to 1 step-1
    k=i-1
    p[i].nx+=p[k].nx
    p[i].ny+=p[k].ny
    'UNITY ADJUST
    f=1/hypot(p[i].nx,p[i].ny)
    p[i].nx*=f
    p[i].ny*=f
  next
  end sub



  sub CalcNormXZ(ShapeProfile*p,int n)
  ====================================
  'CREATE SMOOTH NORMALS
  int i,k
  double c,d,f
  for i=0 to n-1
    k=i+1
    if k>=n then
      k=0
    end if
    c=p[k].px-p[i].px
    d=p[k].pz-p[i].pz
    p[i].nx=-d
    p[i].nz= c
  next
  'ADJUST NORMALS: mean of 2 slopes
  for i=n-1 to 0 step-1
    k=i-1
    if k<0 then k=n-1
    p[i].nx+=p[k].nx
    p[i].nz+=p[k].nz
    'UNITY ADJUST
    f=1/hypot(p[i].nx,p[i].nz)
    p[i].nx*=f
    p[i].nz*=f
  next
  end sub


  sub rotateabout(vector*p,*q,*a)
  ===============================
  Vector r
  double dxy,dxz,dzy
  double axy,axz,azy
  r.x=p.x-q.x
  r.y=p.y-q.y
  r.z=p.z-q.z
  if a.x then
    azy=atan(r.y,r.z)+a.x : dzy=hypot(r.y,r.z)
    r.z=dxz*cos(azy) : r.y=dxz*sin(azy)
  end if
  if a.y then
    axz=atan(r.z,r.x)+a.y : dxz=hypot(r.x,r.z)
    r.x=dxz*cos(axz) : r.z=dxz*sin(axz)
  end if
  if a.z then
    axy=atan(r.y,r.x)+a.z : dxy=hypot(r.x,r.y)
    r.x=dxy*cos(axy) : r.y=dxy*sin(axy)
  end if
  p.x=r.x+q.x
  p.y=r.y+q.y
  p.z=r.z+q.z
  end sub

  sub VesselMesh(ShapeObject*bov, ShapeProfile *p,*q,*r, int m,n)
  ===============================================================
  indexbase 0
  float   pr1,pr2,py1,py2,nr1,ny1,nr2,ny2
  vector  pv1,pv2,pv3,pv4
  Vector  pp1,pp2,pn1,pn2
  Vector pc0,*pc1,*pc2
  Vector *a1,*a2 'bend angle
  int     e,i,j,k
  e=m-1
  CalcNormXY(p,m)
  CalcNormXZ(q,n)
  '
  int qt=8*e*n*2
  int c=0
  string fs=nuls(qt*4)
  string gs=nuls(4*(qt+e))
  float f at strptr fs 'vertex data
  int g at strptr gs   'element index
  '
  float pt[8]={0,0,1,0,0,1,1,1} 'tex coords
  int pti=0 'tex index
  for j=0 to e-1
    k=j+1
    pr1=p[j].px : pr2=p[k].px
    py1=p[j].py : py2=p[k].py
    nr1=p[j].nx : nr2=p[k].nx
    ny1=p[j].ny : ny2=p[k].ny
    @pc1=@r[j].px
    @pc2=@r[k].px
    @a1=@r[j].ax
    @a2=@r[k].ax
    'GL_TRIANGLE_STRIP
    pti=0 'tex index
    for i=0 to n-1
      pp1={pr1*q[i].px, py1, pr1*q[i].pz}
      pp2={pr2*q[i].px, py2, pr2*q[i].pz}
      pn1={nr1*q[i].nx, ny1, nr1*q[i].nz}
      pn2={nr2*q[i].nx, ny2, nr2*q[i].nz}
      rotateabout pp1,pc1,a1
      rotateabout pp2,pc2,a2
      rotateabout pn1,pc0,a1
      rotateabout pn2,pc0,a2
      '
      'glNormal3fv pn2 : glVertex3fv pp2
      'glNormal3fv pn1 : glVertex3fv pp1
      copy @f[0], @pp2,12 'pos
      copy @f[3], @pn2,12 'norm
      copy @f[6], @pt[pti],8 'tex
      copy @f[8], @pp1,12 'pos
      copy @f[11], @pn1,12 'norm
      copy @f[14], @pt[pti+2],8 'tex
      g[0]=c++ 'index vertex
      g[1]=c++ 'index vertex
      @f+=64 'stride 2 vertexes
      @g+=8  'stride 2 indexes
      pti=4-pti 'tex 4 float toggle offset
    next 'n
    g[0]=-1 'end marker
    @g+=4
  next 'e ring
  @f=strptr(fs) 'reset
  @g=strptr(gs) 'reset
  '
  bov.init 'requires initialized opengl
  bov.putVertex f,qt
  bov.putIndex g,qt+e, GL_TRIANGLE_STRIP
  float tm[16]
  loadidentity
  savematrix tm
  bov.putmatrix tm,16 '1 instance
  bov.transfer  
  '
  end sub


  sub VesselShapeA(ShapeObject*bov)
  =================================
  indexbase 0
  static ShapeProfile p[400],q[400],r[400]
  static int i,j,m,n
  static float a,b,c
  '
  'CREATE VERTICAL SHAPE PROFILE
  m=10
  p[0].px=.99 : p[0].py=-2
  p[1].px=.99 : p[1].py=-1.9
  p[2].px=.2  : p[2].py=-1.8
  p[3].px=.1  : p[3].py=-1.6
  p[4].px=.1  : p[4].py=-1
  p[5].px=.30 : p[5].py=-.5
  p[6].px=.70 : p[6].py=0
  p[7].px=.99 : p[7].py=1
  p[8].px=.99 : p[8].py=1.5
  p[9].px=.80 : p[9].py=2
  '
  'CREATE HORIZONTAL SHAPE PROFILE
  n=121
  j=0
  for i=0 to n-1
    a=rad(j)
    b=rad(j*12)
    c=1 + .03125*sin(b)
    j+=3
    q[i].px=  cos(a)*c
    q[i].pz= -sin(a)*c
  next
  '
  'CREATE VERTICAL BENDING SHAPE PROFILE
  for i=0 to 9
   'r[i].py=p[i].py
    r[i].az=rad(i*2)
  next
  '
  'CREATE SHAPE
  VesselMesh bov, p,q,r,m,n
  end sub
  '
  macro BuildVesselShape(bov)
  ===========================
  static ShapeObject bov
  VesselShapeA bov
  end macro


  sub HemiSpheric(ShapeObject*bos, int m)
  =======================================
  indexbase 0
  float  rh,rv              'horizontal and vertical angles
  float  mr                 'minor radius
  float  px,py,pz           'vertex coords
  int    ha,va              'vertex and strip iangle terators
  int    st=m               'step degrees
  float  tx,ty              'tex coords
  float  txi=st/360         'tex step x increment
  float  tyi=txi*4          'tex step y increment
  int    ct=0               'vertex record counter
  int    b=1+(360/st)       'calc qty of vertices per strip
  int    co=b               'strip-offset including overlap
  float  f[8]               'vertex data
  int    g[8]               'element data
  '
  '
  for va=0 to 90 step st
    rv=rad(va)
    mr=cos(rv) 'minor radius
    py=sin(rv)
    tx=0.0 'reset tex x coord
    'GL_TRIANGLE_STRIPs
    for ha=0 to 360 step st '1 overlap
      rh=rad(ha) 'radians
      px=cos(rh)*mr : pz=-sin(rh)*mr
      f[0]=px : f[1]=py : f[2]=pz 'vertex coords
      f[3]=px : f[4]=py : f[5]=pz 'same for normal coords
      f[6]=tx : f[7]=ty           'tex coords
      if va<90
      if ha<360
        'element pairs 
        'g[0]=ct+co 'co offset to next ring
        'g[1]=ct
        'bos.putIndex g,2,GL_TRIANGLE_STRIP
        ------------
        g[0]=ct+co 'co offset to next ring
        g[1]=ct
        g[2]=ct+1
        g[3]=ct+1
        g[4]=ct+co+1
        g[5]=ct+co
        bos.putIndex g,6,GL_TRIANGLES
      endif
      endif
      tx+=txi
      bos.putVertex f,8
      ct++   'vertex record counter increment
    next
    'glEnd
    'g[0]=0xffffffff 'endmarker
    'bos.putIndex g,1,GL_TRIANGLE_STRIP
    ty+=tyi
  next
  '
  '  
  end sub


  sub spheric(ShapeObject*bos, int m)
  ===================================
  PushMatrix
  bos.init 'requires initialized opengl
  hemispheric bos, m
  loadidentity
  bos.putmatrix mats,16 'default single instance
  Rotatef     180,1,0,0
  bos.putmatrix mats,16
  bos.ExpandInstance 'whole sphere
  'translatef 0,0,-3
  'bos.putmatrix mats,16
  'bos.expandInstance
  bos.transfer 'all buffers
  PopMatrix
  end sub

  macro BuildSpheric(bos,m)
  =========================
  static ShapeObject bos
  Spheric bos, m 'yradius,xzradius, step degrees
  end macro





  macro BuildUFO(flyer,m)
  =======================
  '
  'applying instances of sphere
  '
  def ApplyTransform
    flyer.putmatrix mats,16
  end def
  '
  BuildSpheric flyer, m
  flyer.clearMatrix
  '
  'CRAFT MAIN BODY
  '
  PickLabel 1
  '
  PushMatrix
  LoadIdentity
  'Translatef t.p.x+dx,t.p.y+dy,t.p.z+dz
  'Rotatef    t.a.x,1,0,0
  'Rotatef    t.a.y,0,1,0
  'Rotatef    t.a.z,0,0,1
  'Rotatef    10.,1,0,0 'jaunty angle
  Scalef      3.,.5,3.
  'Material Silver
  ApplyTransform
  
  int i

  'FINS
  '
  for i=0 to 5
    pushMatrix
    Rotatef i*60.0,0,1,0
    Translatef -.5,.20,.0
    Scalef      .4,.89,.15
    ApplyTransform
    PopMatrix
  next
  '
  'THRUSTERS
  '
  for i=0 to 5
    pushMatrix
    Rotatef i*60.0,0,1,0
    Translatef -.75,-.60,.00
    Scalef      .10, .30,.10
    ApplyTransform
    PopMatrix
  next
  '
  'CABIN
  '
  Translatef .00,.99,.00
  Scalef     .50,1.99,.50
  'Material Alloy
  ApplyTransform
  '
  'PORTS
  '
  for i=0 to 5
   pushMatrix
    Rotatef 30.0+i*60.0,0,1,0
    Translatef .90,.10,.00 
    'Material BlackShiny
    scalef .10,.40,.20
    ApplyTransform
    PopMatrix
  next
  '
  PopMatrix 'end of craft main body

  flyer.ExpandInstance
  flyer.transfer 'all buffers
end macro
