###################################################
# spiral.slf 
# conceptual skeleton for spiral surface assignment
# tutorial starting file
# CHS 2006/09/27
## 2006/10/05 -- some visibility control of shaells has been added;
#  unfortunately this only works on the control mesh;
#  subdivision and offset modules use all geometry (visible or invisible)!
###########################################################################


tclinit { 
  package require slideui
}

tclinit { 
  ## this block needed to make subdivision work ##
  toplevel .slfWindow.ui
  CreateSLIDESubdivisionObject oSubdivision
  set widget [CreateSLIDESubdivisionUI .slfWindow.ui oSubdivision]
  pack $widget
}

tclinit {
  ## this block needed to create thick slabs with offset surfaces ##
  toplevel .slfWindow.uiOffset1
  CreateSLIDEOffsetObject oOffset1
  set widget [CreateSLIDEOffsetUI .slfWindow.uiOffset1 oOffset1]
  pack $widget
}

########################################################################################
### A variety of parameters ...

tclinit {
  set winName .slfWindow

  source "SLIDEUI.tcl"

  proc CreateParUI { parent name } {
    set subname "slf_[subst $name]"

    if { $parent == {} } {
        set root .$subname
    } elseif { $parent == "." } {
        set root .$subname
    } else {
        set root $parent.$subname
    }

    toplevel $root

    set gr [CreateScale $name $root gr "grow-rate" 1.15 0.8 1.3 0.01 1 horizontal]
    set hlfwid [CreateScale $name $root hlfwid "half-width"   0.5 0.1 0.9 0.01 1 horizontal]
    set prfbnd [CreateScale $name $root prfbnd "profile-bend" 0.2 -0.5 0.5 0.01 1 horizontal]
    set lipwid [CreateScale $name $root lipwid "lip width"    0.3  0.1 0.5 0.01 1 horizontal]
    set lipcrl [CreateScale $name $root lipcrl "lip curl "    0.2 -0.3 0.3 0.01 1 horizontal]
    set viewrot [CreateScale $name $root viewrot "view-rotation" 45 -90 90 1 1 horizontal]
    set numS  [CreateScale $name $root numS "visib. Shells"     2  0   4  1  1 horizontal]

    pack $gr $hlfwid $prfbnd $lipwid $lipcrl  $viewrot $numS  -side top -fill x
  }

CreateParUI $winName par
}
### Variables of the above slider block need to be called as { expr $par_variable }


##### Basic Geometry ##########################################################################

point p0 (1 0 0) endpoint
point p1 (0 0 {expr $par_gr} ) endpoint
point p2 ({expr -$par_gr*$par_gr} 0 0) endpoint
point p3 (0 0 {expr -$par_gr*$par_gr*$par_gr} ) endpoint
point p4 ({expr $par_gr*$par_gr*$par_gr*$par_gr} 0 0) endpoint

point q0 ({expr 1+$par_prfbnd} {expr -$par_hlfwid} 0) endpoint
point q1 (0 {expr -$par_hlfwid} {expr (1+$par_prfbnd)*$par_gr} ) endpoint
point q2 ({expr -(1+$par_prfbnd)*$par_gr*$par_gr} {expr -$par_hlfwid} 0) endpoint
point q3 (0 {expr -$par_hlfwid} {expr -(1+$par_prfbnd)*$par_gr*$par_gr*$par_gr} ) endpoint
point q4 ({expr (1+$par_prfbnd)*$par_gr*$par_gr*$par_gr*$par_gr} {expr -$par_hlfwid} 0) endpoint

point r0 ({expr 1+$par_lipcrl} {expr -$par_hlfwid-$par_lipwid} 0) endpoint
point r1 (0 {expr -$par_hlfwid-$par_lipwid} {expr (1+$par_lipcrl)*$par_gr} ) endpoint
point r2 ({expr -(1+$par_lipcrl)*$par_gr*$par_gr} {expr -$par_hlfwid-$par_lipwid} 0) endpoint
point r3 (0 {expr -$par_hlfwid-$par_lipwid} {expr -(1+$par_lipcrl)*$par_gr*$par_gr*$par_gr} ) endpoint
point r4 ({expr (1+$par_lipcrl)*$par_gr*$par_gr*$par_gr*$par_gr} {expr -$par_hlfwid-$par_lipwid} 0) endpoint

face a1 ( p0 p1 q1 q0 )  endface
face b1 ( q0 q1 r1 r0 )  endface
face a2 ( p1 p2 q2 q1 )  endface
face b2 ( q1 q2 r2 r1 )  endface
face a3 ( p2 p3 q3 q2 )  endface
face b3 ( q2 q3 r3 r2 )  endface
face a4 ( p3 p4 q4 q3 )  endface
face b4 ( q3 q4 r4 r3 )  endface

object halfband (a1 b1 a2 b2 a3 b3 a4 b4) endobject


### Putting two mirror images together to make figure bilaterally symmetrical ###

mirror mirrorhalf   ## reverses all face orientations
  instance halfband scale(1 -1 1) endinstance
endmirror

group spiralband    ## one level of the "onion"
  instance halfband    endinstance
  instance mirrorhalf  endinstance
endgroup


group shell              ## for debugging the control polyhedron -- use before turning on subdivision
  instance spiralband  
    lod {if {$par_numS >= 1} {expr $SLF_FULL} else {expr $SLF_OFF} }
  endinstance
  instance spiralband                              ## an additional onion shell, suitably scaled
    lod {if {$par_numS >= 2} {expr $SLF_FULL} else {expr $SLF_OFF} }
    scale( {expr $par_gr*$par_gr*$par_gr*$par_gr} 
           1.0 
           {expr $par_gr*$par_gr*$par_gr*$par_gr} ) 
  endinstance  
  instance spiralband                              ## yet another onion shell
    lod {if {$par_numS >= 3} {expr $SLF_FULL} else {expr $SLF_OFF} }
    scale( {expr $par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr} 
           1.0 
           {expr $par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr} ) 
  endinstance  
  instance spiralband                              ## yet another onion shell
    lod {if {$par_numS >= 4} {expr $SLF_FULL} else {expr $SLF_OFF} }
    scale( {expr $par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr} 
           1.0 
           {expr $par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr} ) 
  endinstance  
endgroup

mirror mirrorband
  instance spiralband endinstance
endmirror

group mshell              ## for display of backfaces of band in a different color with visibility control
  instance mirrorband  
    lod {if {$par_numS >= 1} {expr $SLF_FULL} else {expr $SLF_OFF} }
  endinstance
  instance mirrorband                              ## an additional onion shell, suitably scaled
    lod {if {$par_numS >= 2} {expr $SLF_FULL} else {expr $SLF_OFF} }
    scale( {expr $par_gr*$par_gr*$par_gr*$par_gr} 
           1.0 
           {expr $par_gr*$par_gr*$par_gr*$par_gr} ) 
  endinstance  
  instance mirrorband                              ## yet another onion shell
    lod {if {$par_numS >= 3} {expr $SLF_FULL} else {expr $SLF_OFF} }
    scale( {expr $par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr} 
           1.0 
           {expr $par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr} ) 
  endinstance  
  instance mirrorband                              ## yet another onion shell
    lod {if {$par_numS >= 4} {expr $SLF_FULL} else {expr $SLF_OFF} }
    scale( {expr $par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr} 
           1.0 
           {expr $par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr*$par_gr} ) 
  endinstance  
endgroup

################ simpler way -- if you don't need visibility control  ######################
(*
### To make final output double-sided for nicer visualization, create face-reversed copy

mirror mshell
  instance shell endinstance
endmirror
*)

################# SUBDIVISION  and   OFFSET SURFACES ###################

subdivision oSubdiv
  lod {expr $oSubdivision(lod)}
  shading {expr $oSubdivision(shading)}

  type {expr $oSubdivision(type)}

  subdivisions {expr $oSubdivision(subdivisions)}
  drawcontrols {expr $oSubdivision(drawcontrols)}
  drawcurrent {expr $oSubdivision(drawcurrent)}
  drawvertices {expr $oSubdivision(drawvertices)}
  errormetric {expr $oSubdivision(errormetric)}   ## ignore

  # Hack to get non-uniform knot spacing on some of the edges  ## ignore
  uknots {expr $oSubdivision(weightededges)}
  uorder {expr $oSubdivision(weight)}
  vknots {expr $oSubdivision(a)}
  vorder {expr $oSubdivision(b)}

  # Hack to assign a tolerance value for the selective subdivision  ## ignore
  tolerance {expr $oSubdivision(tolerance)}
  facetsmax {expr $oSubdivision(facetsmax)}

  instance shell  endinstance
endsubdivision


## do the same thing for the mirror image -- 
## -- because mirroring the subdivided surface somehow gives a different geometry !! ##
## -- TURN THIS MODULE OFF WHEN USING OFFSET SURFACES ##
(*
subdivision mSubdiv
  lod {expr $oSubdivision(lod)}
  shading {expr $oSubdivision(shading)}

  type {expr $oSubdivision(type)}

  subdivisions {expr $oSubdivision(subdivisions)}
  drawcontrols {expr $oSubdivision(drawcontrols)}
  drawcurrent {expr $oSubdivision(drawcurrent)}
  drawvertices {expr $oSubdivision(drawvertices)}
  errormetric {expr $oSubdivision(errormetric)}   ## ignore

  # Hack to get non-uniform knot spacing on some of the edges  ## ignore
  uknots {expr $oSubdivision(weightededges)}
  uorder {expr $oSubdivision(weight)}
  vknots {expr $oSubdivision(a)}
  vorder {expr $oSubdivision(b)}

  # Hack to assign a tolerance value for the selective subdivision  ## ignore
  tolerance {expr $oSubdivision(tolerance)}
  facetsmax {expr $oSubdivision(facetsmax)}

  instance mshell  endinstance  ## just use the mirrored input
endsubdivision
*)

##########################################

offset oOffset1  
     #lod {expr $oOffset1(lod)}
     #shading {expr $oOffset1(shading)}
     drawcontrols {expr $oOffset1(drawcontrols)}
   
     type {expr $oOffset1(type)}     ## USE: type SLF_OFFSET_ANGULAR 
     
     height {expr $oOffset1(height)} ## USE  to  DEFINE THICKNESS OF SLAB.
   
     width  {expr $oOffset1(width)}  ## USE: width  0.00    ## Needed only for making grids with OFFSET_PERFORATED.

  instance  oSubdiv   endinstance
endoffset


############### Assembly ########################

surface R color ( 1 0 0 ) endsurface
surface Y color ( 0.9 0.7 0.2 ) endsurface
surface G color ( 0 1 0 ) endsurface
surface B color ( 0 0 1 ) endsurface

### Make final output double-sided for nicer visualization

(*  ## this should really do the same thing as the 2nd subdivision block above --
    ## -- not clear why this does not work ! ##
mirror mSubdiv
  instance oSubdiv endinstance
endmirror
*)


group gRoot
####  The raw control mesh: with visibility control of individual shells:
  instance shell    scale(0.1 0.1 0.1)  rotate(1 0 0)({expr -$par_viewrot}) surface G endinstance  # check the control polyhedron
  instance mshell   scale(0.1 0.1 0.1)  rotate(1 0 0)({expr -$par_viewrot}) surface R endinstance  # check the control polyhedron
# NOTE: subdivision=0 does not display the control polyhedron, but that polygon projected onto the limit surface !! ##

#  instance oSubdiv  scale(0.1 0.1 0.1)  rotate(1 0 0)({expr -$par_viewrot}) surface Y endinstance
#  instance mSubdiv  scale(0.1 0.1 0.1)  rotate(1 0 0)({expr -$par_viewrot}) surface R endinstance

  instance oOffset1  scale(0.1 0.1 0.1)  rotate(1 0 0)({expr -$par_viewrot}) surface Y endinstance
endgroup

################ Set up view  and  render it ##########################

group gCam
  instance cam
    id iCam
    translate ( 0 0 1 )
  endinstance
endgroup

camera cam
  projection SLF_PERSPECTIVE
  frustum ( -0.2 -0.2 -2 ) ( 0.2 0.2 -0.02 )
endcamera

light lAmbient
  type SLF_AMBIENT
  color ( 0.4 0.4 0.4 )
endlight

light lTop
  type SLF_DIRECTIONAL
  color ( 0.8 0.7 0.6 )
endlight

group gLight
  instance lTop
    id iTop
    lookat
      eye ( 0 0 0 )
      target ( -1 -1 -1 )
      up ( 0 1 0 )
    endlookat
  endinstance
endgroup

viewport Viewport Window
endviewport

window Window
  background ( 0.25 0.60 1.0 )
endwindow

render Viewport gCam.iCam.cam gRoot
  light lAmbient
  light gLight.iTop.lTop
endrender

##########################################################################