--
--	g3dnets.occ -- graphics3d process networks.
--	Copyright (C) 2009 Fred Barnes <frmb@kent.ac.uk>
--
--	This program is free software; you can redistribute it and/or modify
--	it under the terms of the GNU General Public License as published by
--	the Free Software Foundation; either version 2 of the License, or
--	(at your option) any later version.
--
--	This program is distributed in the hope that it will be useful,
--	but WITHOUT ANY WARRANTY; without even the implied warranty of
--	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--	GNU General Public License for more details.
--
--	You should have received a copy of the GNU General Public License
--	along with this program; if not, write to the Free Software
--	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
--

--** @module graphics3d

#INCLUDE "course.module"
#INCLUDE "maths.module"
#INCLUDE "sdlraster.module"
#INCLUDE "graphics3d.inc"

#USE "graphics3d"
#USE "rasterutil"

--{{{  PROC rotate.orchestra1 (CHAN G3D.ROT.CONTROL rot.out!)
--* Orchestrates components.
--
-- @param rot.out Rotation control out.
--
PROC rotate.orchestra1 (CHAN G3D.ROT.CONTROL rot.out!)
  TIMER tim:
  INT t:
  SEQ
    tim ? t

    WHILE TRUE
      SEQ
        SEQ i = 0 FOR 20
          SEQ
            t := t PLUS 100000
            tim ? AFTER t
            rot.out ! add.increment; 0.01
        SEQ i = 0 FOR 40
          SEQ
            t := t PLUS 100000
            tim ? AFTER t
            rot.out ! add.increment; -0.01
        SEQ i = 0 FOR 20
          SEQ
            t := t PLUS 100000
            tim ? AFTER t
            rot.out ! add.increment; 0.01
:
--}}}
--{{{  PROC planar.path (CHAN G3D.PRJ.CONTROL out!, VAL REAL32 xrad, zrad, pangle, iangle, VAL INT islow, VAL [3]REAL32 pos)
--* Moves a 3D object around a plane following an elliptical path.
--
-- @param out Projection control.
-- @param xrad X-radius of path.
-- @param zrad Z-radius of path.
-- @param pangle Tilt in XY plane of the path.
-- @param iangle Tilt in XZ plane of the path.
-- @param islow Slow-down setting
-- @param pos Initial position.
--
PROC planar.path (CHAN G3D.PRJ.CONTROL out!, VAL REAL32 xrad, zrad, pangle, iangle, VAL INT islow, VAL [3]REAL32 pos)
  TIMER tim:
  INT t:
  REAL32 angle:
  SEQ
    angle := iangle
    tim ? t

    INITIAL BOOL running IS TRUE:
    WHILE running
      [3]REAL32 npos:
      SEQ
        t := t PLUS (20000 + islow)
        tim ? AFTER t

        npos[0] := pos[0] + (xrad * COS (angle))
        npos[2] := pos[2] + (zrad * SIN (angle))
        npos[1] := pos[1] + (npos[2] * SIN (pangle))

        out ! set.3dshift; npos
        angle := angle + 0.01
:
--}}}
--{{{  PROC glenz.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height)
--* Implements a basic "Glenz cube".
--
-- @param rlink.in Render link.
-- @param width Width of raster.
-- @param height Height of raster.
--
PROC glenz.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height)
  SEQ
    CHAN INT trigger:
    CHAN MOBILE []G3D.POINT3 gp1, gp2:
    CHAN MOBILE []G3D.POINT2.3 gc1:
    CHAN MOBILE []G3D.POLY pc1:
    CHAN MOBILE []G3D.POLY.SCAN ps1:
    CHAN G3D.GEN.CONTROL gen.ctl:
    CHAN G3D.ROT.CONTROL rot.ctl:
    CHAN G3D.PRJ.CONTROL prj.ctl:
    CHAN G3D.PGN.CONTROL pgn.ctl:
    CHAN G3D.PSC.CONTROL psc.ctl:
    CHAN G3D.RDR.CONTROL rdr.ctl:
    PAR
      cubepoints.generator (trigger?, gp1!, gen.ctl?)
      points3d.rotate (gp1?, gp2!, rot.ctl?)
      points.3d.to.2d3 (gp2?, gc1!, prj.ctl?, width, height)
      cubify.points (gc1?, pc1!, pgn.ctl?)
      poly.scanlines (pc1?, ps1!, psc.ctl?, width, height)
      render.polyscans.trigger (ps1?, rlink.in?, rdr.ctl?, trigger!, width, height)

      SEQ
        prj.ctl ! set.3dshift; [0.0, 0.0, 0.0]
        rdr.ctl ! set.mode; G3D.RENDER.MODE.GLENZ
        pgn.ctl ! set.trimap; FALSE
        pgn.ctl ! set.backfaces; TRUE
        rot.ctl ! add.increment; 0.03
        -- rotate.orchestra1 (rot.ctl!)
        planar.path (prj.ctl, 3.0, 4.0, 0.0, 0.0, 0, [0.0, 0.0, 0.0])
:
--}}}
--{{{  PROC glenz.network.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!)
--* Dynamically spawns a new 'glenz.network'.
--
-- @param width Raster width.
-- @param height Raster height.
-- @param new.link Channel to communicate new object link.
--
PROC glenz.network.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!)
  G3D.RENDER.ENGINE! rlink:
  G3D.RENDER.ENGINE? rsvr:
  SEQ
    rsvr, rlink := MOBILE G3D.RENDER.ENGINE
    FORK glenz.network (rsvr?, width, height)
    new.link ! rlink
:
--}}}
--{{{  PROC normal.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height)
--* Implements a basic "Normal cube".
--
-- @param rlink.in Render link.
-- @param width Width of raster.
-- @param height Height of raster.
--
PROC normal.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height)
  SEQ
    CHAN INT trigger:
    CHAN MOBILE []G3D.POINT3 gp1, gp2:
    CHAN MOBILE []G3D.POINT2.3 gc1:
    CHAN MOBILE []G3D.POLY pc1:
    CHAN MOBILE []G3D.POLY.SCAN ps1:
    CHAN G3D.GEN.CONTROL gen.ctl:
    CHAN G3D.ROT.CONTROL rot.ctl:
    CHAN G3D.PRJ.CONTROL prj.ctl:
    CHAN G3D.PGN.CONTROL pgn.ctl:
    CHAN G3D.PSC.CONTROL psc.ctl:
    CHAN G3D.RDR.CONTROL rdr.ctl:
    PAR
      cubepoints.generator (trigger?, gp1!, gen.ctl?)
      points3d.rotate (gp1?, gp2!, rot.ctl?)
      points.3d.to.2d3 (gp2?, gc1!, prj.ctl?, width, height)
      cubify.points (gc1?, pc1!, pgn.ctl?)
      poly.scanlines (pc1?, ps1!, psc.ctl?, width, height)
      render.polyscans.trigger (ps1?, rlink.in?, rdr.ctl?, trigger!, width, height)

      SEQ
        prj.ctl ! set.3dshift; [0.0, 0.0, 0.0]
        rdr.ctl ! set.mode; G3D.RENDER.MODE.NORM
        pgn.ctl ! set.trimap; FALSE
        pgn.ctl ! set.backfaces; FALSE
        rot.ctl ! add.increment; 0.03
        -- rotate.orchestra1 (rot.ctl!)
        planar.path (prj.ctl, 3.0, 4.0, 0.0, 0.0, 0, [0.0, 0.0, 0.0])
:
--}}}
--{{{  PROC normal.network.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!)
--* Dynamically spawns a new 'normal.network'.
--
-- @param width Raster width.
-- @param height Raster height.
-- @param new.link Channel to communicate new object link.
--
PROC normal.network.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!)
  G3D.RENDER.ENGINE! rlink:
  G3D.RENDER.ENGINE? rsvr:
  SEQ
    rsvr, rlink := MOBILE G3D.RENDER.ENGINE
    FORK normal.network (rsvr?, width, height)
    new.link ! rlink
:
--}}}
--{{{  PROC glenz.network2 (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height)
--* Implements a basic "Glenz cube".
--
-- @param rlink.in Render link.
-- @param width Width of raster.
-- @param height Height of raster.
--
PROC glenz.network2 (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height)
  SEQ

    CHAN INT trigger:
    CHAN MOBILE []G3D.POINT3 gp1, gp2:
    CHAN MOBILE []G3D.POINT2.3 gc1:
    CHAN MOBILE []G3D.POLY pc1:
    CHAN MOBILE []G3D.POLY.SCAN ps1:
    CHAN G3D.GEN.CONTROL gen.ctl:
    CHAN G3D.ROT.CONTROL rot.ctl:
    CHAN G3D.PRJ.CONTROL prj.ctl:
    CHAN G3D.PGN.CONTROL pgn.ctl:
    CHAN G3D.PSC.CONTROL psc.ctl:
    CHAN G3D.RDR.CONTROL rdr.ctl:
    PAR
      cubepoints.generator (trigger?, gp1!, gen.ctl?)
      points3d.rotate (gp1?, gp2!, rot.ctl?)
      points.3d.to.2d3 (gp2?, gc1!, prj.ctl?, width, height)
      cubify.points (gc1?, pc1!, pgn.ctl?)
      poly.scanlines (pc1?, ps1!, psc.ctl?, width, height)
      render.polyscans.trigger (ps1?, rlink.in?, rdr.ctl?, trigger!, width, height)

      SEQ
        gen.ctl ! add.scale; [0.5, 0.5, 2.0]
        prj.ctl ! set.3dshift; [-4.0, 0.0, 6.0]
        rot.ctl ! add.increment; 0.05
        rot.ctl ! set.mode; G3D.ROTATE.MODE.Y \/ G3D.ROTATE.MODE.Z
        rdr.ctl ! set.mode; G3D.RENDER.MODE.GLENZ \/ G3D.RENDER.MODE.NORM
        pgn.ctl ! set.trimap; FALSE
        pgn.ctl ! set.backfaces; FALSE
        pgn.ctl ! set.face.colours; [#000000FF,#00000080,#0000FF00,#00008000,#00FF0000,#00800000,
                                     #0000FFFF,#00008080,#00FFFF00,#00808000,#00FF00FF,#00800080]
        -- rotate.orchestra1 (rot.ctl!)
        planar.path (prj.ctl!, 4.0, 4.0, 3.141, 0.0, 0, [0.0, 0.0, 2.0])
:
--}}}
--{{{  PROC glenz.network2.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!)
--* Dynamically spawns a new 'glenz.network2'.
--
-- @param width Raster width.
-- @param height Raster height.
-- @param new.link Channel to communicate new object link.
--
PROC glenz.network2.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!)
  G3D.RENDER.ENGINE! rlink:
  G3D.RENDER.ENGINE? rsvr:
  SEQ
    rsvr, rlink := MOBILE G3D.RENDER.ENGINE
    FORK glenz.network2 (rsvr?, width, height)
    new.link ! rlink
:
--}}}
--{{{  PROC normal.network2 (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height)
--* Implements a basic "Glenz cube".
--
-- @param rlink.in Render link.
-- @param width Width of raster.
-- @param height Height of raster.
--
PROC normal.network2 (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height)
  CHAN INT trigger:
  CHAN MOBILE []G3D.POINT3 gp1, gp2:
  CHAN MOBILE []G3D.POINT2.3 gc1:
  CHAN MOBILE []G3D.POLY pc1:
  CHAN MOBILE []G3D.POLY.SCAN ps1:
  CHAN G3D.GEN.CONTROL gen.ctl:
  CHAN G3D.ROT.CONTROL rot.ctl:
  CHAN G3D.PRJ.CONTROL prj.ctl:
  CHAN G3D.PGN.CONTROL pgn.ctl:
  CHAN G3D.PSC.CONTROL psc.ctl:
  CHAN G3D.RDR.CONTROL rdr.ctl:
  PAR
    cubepoints.generator (trigger?, gp1!, gen.ctl?) 
    points3d.rotate (gp1?, gp2!, rot.ctl?)
    points.3d.to.2d3 (gp2?, gc1!, prj.ctl?, width, height)
    cubify.points (gc1?, pc1!, pgn.ctl?)
    poly.scanlines (pc1?, ps1!, psc.ctl?, width, height)
    render.polyscans.trigger (ps1?, rlink.in?, rdr.ctl?, trigger!, width, height)

    SEQ
      gen.ctl ! add.scale; [0.5, 0.5, 2.0]
      prj.ctl ! set.3dshift; [-4.0, 0.0, 6.0]
      rot.ctl ! add.increment; 0.05
      rot.ctl ! set.mode; G3D.ROTATE.MODE.Y \/ G3D.ROTATE.MODE.Z
      rdr.ctl ! set.mode; G3D.RENDER.MODE.NORM
      pgn.ctl ! set.trimap; FALSE
      pgn.ctl ! set.backfaces; FALSE
      pgn.ctl ! set.face.colours; [#000000FF,#00000080,#0000FF00,#00008000,#00FF0000,#00800000,
                                   #0000FFFF,#00008080,#00FFFF00,#00808000,#00FF00FF,#00800080]
      -- rotate.orchestra1 (rot.ctl!)
      planar.path (prj.ctl!, 4.0, 4.0, 3.141, 0.0, 0, [0.0, 0.0, 2.0])
:
--}}}
--{{{  PROC normal.network2.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!)
--* Dynamically spawns a new 'normal.network2'.
--
-- @param width Raster width.
-- @param height Raster height.
-- @param new.link Channel to communicate new object link.
--
PROC normal.network2.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!)
  G3D.RENDER.ENGINE! rlink:
  G3D.RENDER.ENGINE? rsvr:
  SEQ
    rsvr, rlink := MOBILE G3D.RENDER.ENGINE
    FORK normal.network2 (rsvr?, width, height)
    new.link ! rlink
:
--}}}
--{{{  PROC screen.cube (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height)
--* Implements an on-screen cube showing the image boundary
--
-- @param rlink.in Render link.
-- @param width Width of raster.
-- @param height Height of raster.
--
PROC screen.cube (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height)
  CHAN INT trigger:
  CHAN MOBILE []G3D.POINT3 gp1:
  CHAN MOBILE []G3D.POINT2.3 gc1:
  CHAN MOBILE []G3D.POLY pc1:
  CHAN G3D.GEN.CONTROL gen.ctl:
  CHAN G3D.PRJ.CONTROL prj.ctl:
  CHAN G3D.PGN.CONTROL pgn.ctl:
  CHAN G3D.RDR.CONTROL rdr.ctl:
  PAR
    cubepoints.generator (trigger?, gp1!, gen.ctl?)
    points.3d.to.2d3 (gp1?, gc1!, prj.ctl?, width, height)
    cubify.points (gc1?, pc1!, pgn.ctl?)
    render.polyframe.trigger (pc1?, rlink.in?, rdr.ctl?, trigger!, width, height)

    SEQ
      gen.ctl ! add.scale; [5.0, 5.0, 5.0]
      gen.ctl ! add.trans; [0.0, 0.0, 3.0]
      pgn.ctl ! set.trimap; FALSE
      pgn.ctl ! set.backfaces; TRUE
      pgn.ctl ! set.face.colours; [#00FFFFFF, #00FFFFFF, #00FFFFFF, #00FFFFFF, #00FFFFFF, #00FFFFFF,
                                   #00FFFFFF, #00FFFFFF, #00FFFFFF, #00FFFFFF, #00FFFFFF, #00FFFFFF]
      rdr.ctl ! set.mode; G3D.RENDER.MODE.NONE

:
--}}}
--{{{  PROC screen.cube.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!)
--* Dynamically spawns a new 'screen.cube'.
--
-- @param width Raster width.
-- @param height Raster height.
-- @param new.link Channel to communicate new object link.
--
PROC screen.cube.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!)
  G3D.RENDER.ENGINE! rlink:
  G3D.RENDER.ENGINE? rsvr:
  SEQ
    rsvr, rlink := MOBILE G3D.RENDER.ENGINE
    FORK screen.cube (rsvr?, width, height)
    new.link ! rlink
:
--}}}
--{{{  PROC butterfly.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height)
--* Implements a butterfly that flaps around a particular path.
--
-- @param rlink.in Render link.
-- @param width Width of raster.
-- @param height Height of raster.
-- @param rpix Random initial placement.
--
PROC butterfly.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height, VAL BOOL rpix)
  CHAN INT trigger:
  CHAN MOBILE []G3D.POINT3 gp1, gp2:
  CHAN MOBILE []G3D.POINT2.3 gc1:
  CHAN MOBILE []G3D.POLY pc1:
  CHAN MOBILE []G3D.POLY.SCAN ps1:
  CHAN G3D.GEN.CONTROL gen.ctl:
  CHAN G3D.ROT.CONTROL rot.ctl:
  CHAN G3D.PRJ.CONTROL prj.ctl:
  CHAN G3D.PGN.CONTROL pgn.ctl:
  CHAN G3D.PSC.CONTROL psc.ctl:
  CHAN G3D.RDR.CONTROL rdr.ctl:
  CHAN BOOL l.trig:
  PAR
    SEQ
      BOOL any:
      l.trig ? any
      fbypoints.generator (trigger?, gp1!, gen.ctl?)

    points3d.rotate (gp1?, gp2!, rot.ctl?)
    points.3d.to.2d3 (gp2?, gc1!, prj.ctl?, width, height)
    flutterby.points (gc1?, pc1!, pgn.ctl?)
    render.polyframe.trigger (pc1?, rlink.in?, rdr.ctl?, trigger!, width, height)
    -- poly.scanlines (pc1?, ps1!, psc.ctl?)
    -- render.polyscans (ps1?, rlink, rdr.ctl?)

    REAL32 xrad, zrad, pangle:
    REAL32 iangle:
    REAL32 xoffs, yoffs, zoffs:
    INT islow:
    SEQ
      -- prj.ctl ! set.3dshift; [-5.0, 0.0, 6.0]
      rot.ctl ! add.increment; 0.04
      rot.ctl ! set.mode; G3D.ROTATE.MODE.DEMO
      l.trig ! TRUE
      rdr.ctl ! set.mode; G3D.RENDER.MODE.GLENZ

      IF
        rpix
          TIMER tim:
          INT seed, val:
          SEQ
            tim ? seed
            seed := (seed >> 2) + 1

            [4]BYTE pix RETYPES val:
            SEQ v = 0 FOR 3
              INT n:
              SEQ
                n, seed := random (127, seed)
                pix[v] := BYTE ((n + 100) /\ #FF)

            pgn.ctl ! set.face.colour; 0; val

            val, seed := random (200, seed)
            xrad := 2.0 + ((REAL32 ROUND val) / 100.0)
            
            val, seed := random (500, seed)
            xoffs := (REAL32 ROUND val) / 100.0
            xoffs := (-2.5) + xoffs

            val, seed := random (700, seed)
            yoffs := (-4.0) + ((REAL32 ROUND val) / 100.0)

            val, seed := random (100, seed)
            pangle := (-2.141) - ((REAL32 ROUND val) / 100.0)

            val, seed := random (300, seed)
            zrad := 2.0 + ((REAL32 ROUND val) / 100.0)

            val, seed := random (620, seed)
            iangle := ((REAL32 ROUND val) / 100.0)

            islow, seed := random (20000, seed)

            val, seed := random (1000, seed)
            zoffs := 2.0 + ((REAL32 ROUND val) / 100.0)
        TRUE
          SEQ
            xrad := 6.0
            zrad := 4.0
            pangle := -2.141
            iangle := 0.0

            xoffs := 0.0
            yoffs := 0.5
            zoffs := 2.0

            islow := 0

      planar.path (prj.ctl!, xrad, zrad, pangle, iangle, islow, [xoffs, yoffs, zoffs])
:
--}}}
--{{{  PROC butterfly.network.spawn (VAL INT width, height, VAL BOOL rpix, CHAN G3D.RENDER.ENGINE! new.link!)
--* Dynamically spawns a new 'butterfly.network'.
--
-- @param width Raster width.
-- @param height Raster height.
-- @param rpix Random initial placement.
-- @param new.link Channel to communicate new object link.
--
PROC butterfly.network.spawn (VAL INT width, height, VAL BOOL rpix, CHAN G3D.RENDER.ENGINE! new.link!)
  G3D.RENDER.ENGINE! rlink:
  G3D.RENDER.ENGINE? rsvr:
  SEQ
    rsvr, rlink := MOBILE G3D.RENDER.ENGINE
    FORK butterfly.network (rsvr?, width, height, rpix)
    new.link ! rlink
:
--}}}
--{{{  PROC glenz.cog.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height, nteeth, VAL REAL32 i.rad, o.rad, i.ang, o.ang)
--* Implements a basic "Glenz cog".
--
-- @param rlink.in Render link.
-- @param width Width of raster.
-- @param height Height of raster.
-- @param nteeth Number of teeth.
-- @param i.rad Inner radius.
-- @param o.rad Outer radius.
-- @param i.ang Inner angle.
-- @param o.ang Outer angle.
--
PROC glenz.cog.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height, nteeth, VAL REAL32 i.rad, o.rad, i.ang, o.ang)
  CHAN INT trigger:
  CHAN MOBILE []G3D.POINT3 gp1, gp2, gp3:
  CHAN MOBILE []G3D.POINT2.3 gc1:
  CHAN MOBILE []G3D.POLY pc1:
  CHAN MOBILE []G3D.POLY.SCAN ps1:
  CHAN G3D.GEN.CONTROL gen.ctl:
  CHAN G3D.ROT.CONTROL rot1.ctl, rot2.ctl:
  CHAN G3D.PRJ.CONTROL prj.ctl:
  CHAN G3D.PGN.CONTROL pgn.ctl:
  CHAN G3D.PSC.CONTROL psc.ctl:
  CHAN G3D.RDR.CONTROL rdr.ctl:
  PAR
    cogpoints.generator (trigger?, nteeth, i.rad, o.rad, i.ang, o.ang, gp1!, gen.ctl?)
    points3d.rotate (gp1?, gp2!, rot1.ctl?)
    points3d.rotate (gp2?, gp3!, rot2.ctl?)
    points.3d.to.2d3 (gp3?, gc1!, prj.ctl?, width, height)
    cogify.points (gc1?, nteeth, pc1!, pgn.ctl?)
    poly.scanlines (pc1?, ps1!, psc.ctl?, width, height)
    render.polyscans.trigger (ps1?, rlink.in?, rdr.ctl?, trigger!, width, height)

    SEQ
      prj.ctl ! set.3dshift; [0.0, 3.0, 0.0]
      rdr.ctl ! set.mode; G3D.RENDER.MODE.GLENZ
      pgn.ctl ! set.trimap; FALSE
      pgn.ctl ! set.backfaces; TRUE
      rot1.ctl ! set.mode; G3D.ROTATE.MODE.Y
      rot1.ctl ! add.increment; 0.06
      rot2.ctl ! set.mode; G3D.ROTATE.MODE.X
      rot2.ctl ! set.angle; -(PI / 6.0)
:
--}}}
--{{{  PROC glenz.cog.network.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!, VAL INT nteeth, VAL REAL32 i.rad, o.rad, i.ang, o.ang)
--* Dynamically spawns a new 'glenz.cog.network'.
--
-- @param width Raster width.
-- @param height Raster height.
-- @param new.link Channel to communicate new object link.
-- @param nteeth Number of teeth.
-- @param i.rad Inner radius.
-- @param o.rad Outer radius.
-- @param i.ang Inner angle.
-- @param o.ang Outer angle.
--
PROC glenz.cog.network.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!, VAL INT nteeth, VAL REAL32 i.rad, o.rad, i.ang, o.ang)
  G3D.RENDER.ENGINE! rlink:
  G3D.RENDER.ENGINE? rsvr:
  SEQ
    rsvr, rlink := MOBILE G3D.RENDER.ENGINE
    FORK glenz.cog.network (rsvr?, width, height, nteeth, i.rad, o.rad, i.ang, o.ang)
    new.link ! rlink
:
--}}}
--{{{  PROC glenz.flatpoly.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height, npoints, VAL REAL32 rad)
--* Implements a basic regular polygon (glenz style).
--
-- @param rlink.in Render link.
-- @param width Width of raster.
-- @param height Height of raster.
-- @param npoints Number of points.
-- @param rad Radius.
--
PROC glenz.flatpoly.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height, npoints, VAL REAL32 rad)
  CHAN INT trigger:
  CHAN MOBILE []G3D.POINT3 gp1, gp2, gp3:
  CHAN MOBILE []G3D.POINT2.3 gc1:
  CHAN MOBILE []G3D.POLY pc1:
  CHAN MOBILE []G3D.POLY.SCAN ps1:
  CHAN G3D.GEN.CONTROL gen.ctl:
  CHAN G3D.ROT.CONTROL rot1.ctl, rot2.ctl:
  CHAN G3D.PRJ.CONTROL prj.ctl:
  CHAN G3D.PGN.CONTROL pgn.ctl:
  CHAN G3D.PSC.CONTROL psc.ctl:
  CHAN G3D.RDR.CONTROL rdr.ctl:
  PAR
    flatpolypoints.generator (trigger?, npoints, rad, gp1!, gen.ctl?)
    points3d.rotate (gp1?, gp2!, rot1.ctl?)
    points3d.rotate (gp2?, gp3!, rot2.ctl?)
    points.3d.to.2d3 (gp3?, gc1!, prj.ctl?, width, height)
    flatpolify.points (gc1?, npoints, pc1!, pgn.ctl?)
    poly.scanlines (pc1?, ps1!, psc.ctl?, width, height)
    render.polyscans.trigger (ps1?, rlink.in?, rdr.ctl?, trigger!, width, height)

    SEQ
      prj.ctl ! set.3dshift; [0.0, -2.0, 0.0]
      rdr.ctl ! set.mode; G3D.RENDER.MODE.GLENZ
      pgn.ctl ! set.trimap; FALSE
      pgn.ctl ! set.backfaces; TRUE
      rot1.ctl ! set.mode; G3D.ROTATE.MODE.Y
      rot1.ctl ! add.increment; 0.06
      rot2.ctl ! set.mode; G3D.ROTATE.MODE.X
      rot2.ctl ! set.angle; -(PI / 6.0)
:
--}}}
--{{{  PROC glenz.flatpoly.network.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!, VAL INT npoints, VAL REAL32 rad)
--* Dynamically spawns a new 'glenz.flatpoly.network'.
--
-- @param width Raster width.
-- @param height Raster height.
-- @param new.link Channel to communicate new object link.
-- @param npoints Number of points
-- @param rad Radius.
--
PROC glenz.flatpoly.network.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!, VAL INT npoints, VAL REAL32 rad)
  G3D.RENDER.ENGINE! rlink:
  G3D.RENDER.ENGINE? rsvr:
  SEQ
    rsvr, rlink := MOBILE G3D.RENDER.ENGINE
    FORK glenz.flatpoly.network (rsvr?, width, height, npoints, rad)
    new.link ! rlink
:
--}}}
--{{{  PROC zdepth.flatpoly.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height, npoints, VAL REAL32 rad)
--* Implements a basic regular polygon (zdepth style).
--
-- @param rlink.in Render link.
-- @param width Width of raster.
-- @param height Height of raster.
-- @param npoints Number of points.
-- @param rad Radius.
--
PROC zdepth.flatpoly.network (G3D.RENDER.ENGINE? rlink.in, VAL INT width, height, npoints, VAL REAL32 rad)
  CHAN INT trigger:
  CHAN MOBILE []G3D.POINT3 gp1, gp2, gp3:
  CHAN MOBILE []G3D.POINT2.3 gc1:
  CHAN MOBILE []G3D.POLY pc1:
  CHAN MOBILE []G3D.POLY.SCAN ps1:
  CHAN G3D.GEN.CONTROL gen.ctl:
  CHAN G3D.ROT.CONTROL rot1.ctl, rot2.ctl:
  CHAN G3D.PRJ.CONTROL prj.ctl:
  CHAN G3D.PGN.CONTROL pgn.ctl:
  CHAN G3D.PSC.CONTROL psc.ctl:
  CHAN G3D.RDR.CONTROL rdr.ctl:
  PAR
    flatpolypoints.generator (trigger?, npoints, rad, gp1!, gen.ctl?)
    points3d.rotate (gp1?, gp2!, rot1.ctl?)
    points3d.rotate (gp2?, gp3!, rot2.ctl?)
    points.3d.to.2d3 (gp3?, gc1!, prj.ctl?, width, height)
    flatpolify.points (gc1?, npoints, pc1!, pgn.ctl?)
    poly.scanlines (pc1?, ps1!, psc.ctl?, width, height)
    render.polyscans.trigger (ps1?, rlink.in?, rdr.ctl?, trigger!, width, height)

    SEQ
      prj.ctl ! set.3dshift; [0.0, -2.0, 0.0]
      rdr.ctl ! set.mode; G3D.RENDER.MODE.NONE
      pgn.ctl ! set.trimap; FALSE
      pgn.ctl ! set.backfaces; FALSE
      psc.ctl ! set.zcolour; TRUE
      rot1.ctl ! set.mode; G3D.ROTATE.MODE.Y
      rot1.ctl ! add.increment; 0.06
      rot2.ctl ! set.mode; G3D.ROTATE.MODE.X
      rot2.ctl ! add.increment; 0.02
:
--}}}
--{{{  PROC zdepth.flatpoly.network.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!, VAL INT npoints, VAL REAL32 rad)
--* Dynamically spawns a new 'zdepth.flatpoly.network'.
--
-- @param width Raster width.
-- @param height Raster height.
-- @param new.link Channel to communicate new object link.
-- @param npoints Number of points
-- @param rad Radius.
--
PROC zdepth.flatpoly.network.spawn (VAL INT width, height, CHAN G3D.RENDER.ENGINE! new.link!, VAL INT npoints, VAL REAL32 rad)
  G3D.RENDER.ENGINE! rlink:
  G3D.RENDER.ENGINE? rsvr:
  SEQ
    rsvr, rlink := MOBILE G3D.RENDER.ENGINE
    FORK zdepth.flatpoly.network (rsvr?, width, height, npoints, rad)
    new.link ! rlink
:
--}}}


