;
; 3D-rotation made easy. Copyright (C) Peter Thor 2002
; pettho-0@student.luth.se
;

  WBStartup
  NoCli
  DEFTYPE .q

  NEWTYPE .xyz
    x.w
    y.w
    z.w
  End NEWTYPE

  NEWTYPE .world
    xang.q                            ; x- y- and z-angle world is rotated
    yang.q
    zang.q

    xx.q
    xy.q
    xz.q
    yx.q
    yy.q
    yz.q
    zx.q
    zy.q
    zz.q
  End NEWTYPE

  Dim Object.xyz(8-1)                 ; unmodified object
  Dim RotatedObject.xyz(8-1)          ; object after rotation

  For n.w = 0 To 8-1                  ; read in the points of the object
    Read Object(n)\x
    Read Object(n)\y
    Read Object(n)\z
  Next n

  Dim Axis_Active.b(3-1)              ; what axis to rotate about
  Axis_Active(0) = False              ; x-axis
  Axis_Active(1) = False              ; y-axis
  Axis_Active(2) = False              ; z-axis

  win_width.w  = 100                  ; width and height of window
  win_height.w = 100

  Dim XY_Origin.b(2-1)                ; x- and y-coordinate for "center of view"
  XY_Origin(0)   = win_width / 2
  XY_Origin(1)   = win_height / 2
  
  perspectivedepth.w = 320

;--

Statement UpdateWorld {}

  SHARED World.world

;--

  World\xx = Cos(World\yang)*Cos(World\xang)
  World\xy = Cos(World\yang)*Sin(World\xang)
  World\xz = Sin(World\yang)
  World\yx = Cos(World\zang)*Sin(World\xang)+Sin(World\zang)*Sin(World\yang)*Cos(World\xang)
  World\yy = -Cos(World\zang)*Cos(World\xang)+Sin(World\zang)*Sin(World\yang)*Sin(World\xang)
  World\yz = -Sin(World\zang)*Cos(World\yang)
  World\zx = Sin(World\zang)*Sin(World\xang)-Cos(World\zang)*Sin(World\yang)*Cos(World\xang)
  World\zy = -Sin(World\zang)*Cos(World\xang)-Cos(World\zang)*Sin(World\yang)*Sin(World\xang)
  World\zz = Cos(World\zang)*Cos(World\yang)

End Statement

;--

Statement UpdateObject {xorigin.w, yorigin.w}

  SHARED World.world, Object(), RotatedObject()

  ;--

  For n.w = 0 To 8-1
    nx.w = xorigin + World\xx * Object(n)\x + World\xy * Object(n)\y + World\xz * Object(n)\z
    ny.w = yorigin + World\yx * Object(n)\x + World\yy * Object(n)\y + World\yz * Object(n)\z
    nz.w =           World\zx * Object(n)\x + World\zy * Object(n)\y + World\zz * Object(n)\z

    RotatedObject(n)\x = nx
    RotatedObject(n)\y = ny
    RotatedObject(n)\z = nz
  Next n

End Statement

;--

Statement UpdatePerspective  {perspectivedepth.w}

  SHARED RotatedObject()

  ;--

  ; if perspectivedepth > 320 the object will be closer to the viewer
  ;                     < 320 further away
  For n.w = 0 To 8-1
    RotatedObject(n)\x = (RotatedObject(n)\x*perspectivedepth)/(RotatedObject(n)\z + 320)
    RotatedObject(n)\y = (RotatedObject(n)\y*perspectivedepth)/(RotatedObject(n)\z + 320)
  Next n

End Statement


Statement DrawObject {}

  SHARED RotatedObject()

  ;--

  For n.w = 0 To 8-1
    If n < 3
      Wline RotatedObject(n)\x,RotatedObject(n)\y,RotatedObject(n+1)\x,RotatedObject(n+1)\y,1
    Else
      Wline RotatedObject(0)\x,RotatedObject(0)\y,RotatedObject(3)\x,RotatedObject(3)\y,1
    EndIf
  Next n

  For n = 4 To 8-1
    If n < 7
      Wline RotatedObject(n)\x,RotatedObject(n)\y,RotatedObject(n+1)\x,RotatedObject(n+1)\y,1
    Else
      Wline RotatedObject(4)\x,RotatedObject(4)\y,RotatedObject(7)\x,RotatedObject(7)\y,1
    EndIf
  Next n

  Wline RotatedObject(0)\x,RotatedObject(0)\y,RotatedObject(6)\x,RotatedObject(6)\y,2
  Wline RotatedObject(1)\x,RotatedObject(1)\y,RotatedObject(7)\x,RotatedObject(7)\y,2
  Wline RotatedObject(2)\x,RotatedObject(2)\y,RotatedObject(4)\x,RotatedObject(4)\y,2
  Wline RotatedObject(3)\x,RotatedObject(3)\y,RotatedObject(5)\x,RotatedObject(5)\y,2

End Statement

;************************************************************************************

  WBenchToFront_
  FindScreen 0

  Window 0,10,10,100,80,$2|$8,"",0,1
  GTCheckBox 0,0,0, 0,30,10,"x",$2
  GTCheckBox 0,1,0,11,30,10,"y",$2
  GTCheckBox 0,2,0,22,30,10,"z",$2
  GTSlider   0,3,0,33,30,10,"Depth",$2,0,320,320
  GTSlider   0,4,0,44,30,10,"x-pos",$2,0,win_width,win_width/2
  GTSlider   0,5,0,55,30,10,"y-pos",$2,0,win_height,win_height/2
  AttachGTList 0,0

  Window 1,110,10,win_width,win_height,$400,"",0,1

Repeat

  a.l = Event
  Select a
    Case #IDCMP_CLOSEWINDOW
      QUIT.b = True

    Case #IDCMP_GADGETUP
      gadget.b = GadgetHit
      code.w = EventCode
      If gadget < 3                       ; x/y/z-rotation yes/no
        Axis_Active(gadget) = code
      Else
        If gadget = 3                     ; perspective value
          perspectivedepth = code
        Else
          XY_Origin(gadget-4) = code        ; x-y-origin
        EndIf
      EndIf

  End Select

  If Axis_Active(0) Then World\xang + 0.05
  If Axis_Active(1) Then World\yang + 0.05
  If Axis_Active(2) Then World\zang + 0.05

  UpdateWorld  {}
  UpdateObject {XY_Origin(0), XY_Origin(1)}
  UpdatePerspective {perspectivedepth}

  WCls
  DrawObject   {}

Until QUIT = True

End

;*******************************************

cube:
  Data.w     35, 35,-35
  Data.w    -35, 35,-35
  Data.w    -35,-35,-35
  Data.w     35,-35,-35
  Data.w    -35,-35, 35
  Data.w     35,-35, 35
  Data.w     35, 35, 35
  Data.w    -35, 35, 35

