  #compact
  % filename "t.exe"
  % Title "STL VIEWER (F1 Help  F5 Render)"
 '% WindowOpacity 240 'max 255
 '% Animated
  % ScaleUp
 '% PlaceCentral
 '% AnchorCentral
 '% NoEscape
  % ColorCodedPick

 'uses rtl64
  uses ConsoleG
  uses ParseUtil

  string STLfilename ' loaded file
  string status      ' info about file
  float  smax        ' max scalar size
  '
  macro readval(v)
  ================
  StepWord d,i
  v=valat p+sttw
  end macro
  '
  macro ReadVector(v)
  ===================
  'READ NUMBERS DIRECTLY FROM STL STRING
  readval v[1]
  readval v[2]
  readval v[3]
  end macro
  '
  type STLHeader
  ==============
  byte  hbytes[80]
  dword count
  end type

  packed type SurfaceElement
  ==========================
  float xn,yn,zn   'NORMAL
  float x1,y1,z1   'VERTEX 1
  float x2,y2,z2   'VERTEX 2
  float x3,y3,z3   'VERTEX 3
  word  AttribSize 'N BYTES DATA FOLLOWING
  end type


  function TextToBinary() as string
  =================================
  indexbase 1
  string d    'STRING FOR STL FILE DATA
  string bn   'STRING DOR BINARY OUTPUT
  string er   'READING ERROR MESSAGE
  sys    le   'LENGTH OF STRING
  sys    n    'FACET COUNT
  sys    tf   'TEXT FORMAT FLAG
  string wr   'EXTRACTED WORDS
  string name 'NAME OF SOLID
  sys    i=1  'INPUT STRING INDEXER
  sys    j=1  'OUTPUT STRING INDEXER
  string t    'TEMP HEADER STRING
  '
  getfile stlfilename,d

  if not d then
    er="Problem: Please check Filename and location " stlfilename
    return d
  end if

  le=len d
  bn=nuls le
 

  'TEXT FORMAT
  ============

  /*
  solid name
  where name is an optional string (though if name is omitted there must still be a space after solid). The file continues with any number of triangles, each represented as follows:

  facet normal ni nj nk
    outer loop
        vertex v1x v1y v1z
        vertex v2x v2y v2z
        vertex v3x v3y v3z
    endloop
  endfacet
  */

  t=left d,80
  i=instr t,"solid "
  'if i<>1 then
  if i=0 then
    return d 'ASSUME ALREADY IN BINARY FORM
  else
    tf=1
  end if

  StepWord d,i
  name=GetWord d,i

  sys p=strptr(d) -1 'DATA STRING POINTER BASE
  float  v[3]        'VERTEX OR NORMAL
  '
  n=0
  SurfaceElement s at ( strptr(bn) + Sizeof(STLHeader) )
  do
    wr=GetWord d,i
    if ascw=0 then exit do
    if wr="normal" then
      ReadVector v 
      s.xn ={v[1],v[2],v[3]}
    elseif wr="vertex" then
      ReadVector v : s.x1[j]={v[1],v[2],v[3]}
      j+=3
      if j>9 then
        j=1
        @s+=sizeof(SurfaceElement) 'NO ATTRIBUTES
        n++
      end if
    end if
  end do
  int v at strptr(bn)+80 'COUNT
  v=n
  return left bn, Sizeof(STLHeader) + n*sizeof(SurfaceElement)
  end function


  '
  function ModelRender()
  ======================
  indexbase 1
  string d  'STRING FOR STL FILE DATA
  string er 'READING ERROR MESSAGE
  sys    le 'LENGTH OF STRING
  sys    n  'FACET COUNT
  sys    tf 'TEXT FORMAT FLAG
  '
  getfile STLfilename,d
  '
  if not d then
    er="Problem: Please check Filename and location " stlfilename
    goto done
  end if

  le=len d
 

  'TEXT FORMAT
  ============

  string wr   'EXTRACTED WORDS
  string name 'NAME OF SOLID
  sys    i=1  'STRING INDEXER
  string t    'TEMP HEADER STRING

  t=left d,80
  i=instr t,"solid "
  'if i<>1 then
  if i=0 then
    goto BinaryFormat
  else
    tf=1
  end if

  StepWord d,i
  name=GetWord d,i

  sys p=strptr(d) -1 'DATA STRING POINTER BASE
  float  v[3]        'VERTEX OR NORMAL
  '
  glBegin GL_TRIANGLES
  smax=0
  do
    wr=GetWord d,i
    if ascw=0 then exit do
    if wr="normal" then
      ReadVector v : glNormal3fv v
      n++
    elseif wr="vertex" then
      ReadVector v : glVertex3fv v 
      if v[1]>smax then smax=v[1]
      if v[2]>smax then smax=v[2]
      if v[3]>smax then smax=v[4]
    end if
  end do
  glEnd

  goto done


  'BINARY FORMAT
  ==============

  BinaryFormat:

  /*
  UINT8[80] – Header
  UINT32 – Number of triangles

  for each triangle
  REAL32[3] – Normal vector
  REAL32[3] – Vertex 1
  REAL32[3] – Vertex 2
  REAL32[3] – Vertex 3
  UINT16 – Attribute byte count
  */

  if len(d)<sizeof(STLHeader) then
    er="binary file too small"
    goto done
  end if


  p=strptr d
  stlheader h at (p)
  n=h.count
  if n*sizeof(SufaceElement)+sizeof(STLHeader)>le then
    er="corrupt element count " n
    goto done
  end if

  SurfaceElement s at (p+sizeof(STLHeader))

  'OPENGL READ IN TRIANGLES

  glBegin GL_TRIANGLES
  smax=0
  for i=1 to n
    glNormal3fv s.xn
    glVertex3fv s.x1 
    glVertex3fv s.x2 
    glVertex3fv s.x3
    if s.x1>smax then smax=s.x1
    if s.y1>smax then smax=s.y1
    if s.z1>smax then smax=s.z1
    if s.x2>smax then smax=s.x2
    if s.y2>smax then smax=s.y2
    if s.z2>smax then smax=s.z2
    if s.x3>smax then smax=s.x3
    if s.y3>smax then smax=s.y3
    if s.z3>smax then smax=s.z3
    @s+=sizeof(s) + s.AttribSize 'STEP
  next
  glEnd
   
  done:
  if er then
    status=er
  else
    if tf then status="Text File : " else status="Binary File : "
    status+=str(n)+" Facets : " str(smax,2) " Max dimension"
  end if
  end function 'ModelRender

  function BuildForm(sys fun) as sys
  '=================================
  '
  static sys list
  if not fun then return 0
  list = CompileList list
  call fun
  glEndList
  return list
  end function

  function main()
  ===============
  sys i,p
  string s
  float  a
  '
  static sys    shape
  static string inputs="lambo.stl"

  cls 0,0.20,0.20
  picksetup

  shading
  pushstate
  static MoveableObject mover
  if not mover.id
    mover.set 0x10000,0,0,0,0
    mover.a.x =-90
    mover.aa.x=-90
  end if
  sys dt=15
  move dt,-dt*1.5,-dt -1
  mover.act
  Material Gold
  'Material Silver
  'Material RedShiny
  'Material WhiteShiny
  'go sphere
  if smax then scale 1.25*dt/smax
  go shape
  popstate
  '
  'LINE INPUT
  '
  flat
  PushState
  color .20,.80,.00,.88
  Scale 1.5
  print "File: "
  color .80,.80,.00,.88
  a=input inputs
  if key(0x74) 'F5
    stlfilename=inputs
   'string bn=TextToBinary()
   'putfile "t.stl",bn
    shape=BuildForm(@ModelRender)
    key(0x74)=0 'single shot
  end if
  scale 1/1.5
  printl status
  PopState
  printl
  printl
  printl
  '
  '
  shading 'opposite of flat
  '
  '
  'F1 HELP
  '
  if key[0x70]
    flat
    pushstate
    move 20,0
    color .9,.9,.9
    scale  1.5,1.0
    printl "Active Keys:"
    printl
    scale  1/1.5,1.0
    printl "Esc"    tab "Exit"
    printl "Ctrl-P" tab "Take snapshot"
    printl "F1 This help panel"
    printl "F5 Exec function"
    printl
    scale 1.5,1.0
    printl "Mouse:"
    scale 1/1.5,1.0
    printl "Point to Object, then"
    printl "Left button to Rotate"
    printl "Right button to Move"
    popstate
  end if
  picklabel 0
  lastkey=0
  lastchar=0

  end function


  EndScript
