DECLARE SUB WriteBottomLine ()
DECLARE FUNCTION TDLine! (X1!, Y1!, X2!, Y2!, LineColor!)
DECLARE FUNCTION DrawOneAngle! (OneAngle!)
DECLARE SUB WriteStats ()
DECLARE FUNCTION PosMod! (Number!, ModuledBy!)
DECLARE SUB CalculateBasePoints ()
DECLARE SUB CalculateSevens ()
DECLARE FUNCTION DrawSeven! (Frame!, DrawColor!, InvisibleColor!, Moment)
DECLARE FUNCTION Perspective! (Height!)
DECLARE FUNCTION Disappear! (Y!)
DECLARE FUNCTION SevenLine! (X1!, Y1!, X2!, Y2!, Frame!, Seven!, DrawColor!, InvisibleColor!)
DECLARE FUNCTION DrawPyramid (Frame, DrawColor, InvisibleColor)
DIM SHARED TDoffsetX, TDoffsetY, Former, Now, TopY, Rotation, FrameNr, Size
DIM SHARED DegToRad, RadToDeg, SevenDistance, SevenFloatHeight, SevenTopSize
DIM SHARED SevenHeight, SevenDashHeight, SevenBottomPos, SevenDashLeft
DIM SHARED SevenDashRight, Angle1, BottomLine$, BottomLineDelay, DoubleLines
DIM SHARED RotationSpeed, Toets$
SCREEN 12

DelayScreen = 500
FrameHistory = 30 'Remember 30 frames
DegToRad = (3.141592654# / 180)
RadToDeg = (180 / 3.141592654#)
RotationSpeed = -1
Verbose = 0

DIM SHARED B(FrameHistory + 1, 3, 6)'Frames for history
                          '3 base points
                          '3rd number: 0 = rotation in degrees
                          '            1 = x
                          '            2 = y
                          '            3 = z in 3d View
                          '            4 = visible, 0 inv, 1 vis
DIM SHARED S(FrameHistory + 1, 3, 25) ' Sevens
                          ' 0 Rotation around Pyramid
                          ' 1 X
                          ' 2 Y
                          ' 3 Z in 3D view
                          ' 0, Seven, 4 = Axis Rotation speed
                          ' 5 Axis Rotation
                          ' 10 = upper left x
                          ' 11 = upper left y
                          ' 12 = upper left z 3d view
                          ' 13 = upper right x
                          ' 14 = upper right y
                          ' 15 = upper right z 3d view
DIM SHARED RightAngle(FrameHistory + 1)
DIM SHARED LeftAngle(FrameHistory + 1)

Keys$ = "(?) Show Keys, (P)ause, (C)lear Screen, (-)Reverse, (D)ouble Lines, (<->) In/decrease speed"
BottomLineSpeed = 20
BottomLine$ = Keys$
BottomLineDelay = 80 * BottomLineSpeed

'Length of Center to B1 will be 1
Height = 1.4
Size = 50
TopY = Size * Height * -1

' Sevens:
SevenDistance = 1.1 * Size
SevenFloatHeight = -1.1 * Size
SevenTopSize = .4 * Size
SevenBottomPos = .3 * SevenTopSize
SevenHeight = .5 * Size
SevenDashHeight = .35 * SevenHeight
SevenDashLeft = .3 * SevenTopSize
SevenDashRight = -.4 * SevenTopSize
S(0, 0, 4) = 6 'rotation speed
S(0, 1, 4) = -6
S(0, 2, 4) = -9

'3D projection
TDoffsetX = 300
TDoffsetY = 250

DO
  Delay = 0
  DO
    Delay = Delay + 1
  LOOP WHILE Delay < DelayScreen
 
  FrameNr = FrameNr + 1
  Rotation = PosMod((Rotation + RotationSpeed), 360)
  EraseFrame = Now 'old frame
  Now = FrameNr MOD FrameHistory

  CalculateBasePoints
  CalculateSevens

  Blaa = DrawPyramid(EraseFrame, 0, 0)
  Blaa = DrawSeven(EraseFrame, 0, 0, -1)
  Blaa = DrawSeven(Now, 4, 8, 0)
  Blaa = DrawPyramid(Now, 2, 8)
  Blaa = DrawSeven(Now, 12, 8, 1)

  WriteBottomLine

  IF Verbose = 1 THEN
    CLS
    WriteStats
  END IF

  Toets$ = INKEY$
  IF Toets$ = "" THEN
    'nothing
  ELSEIF Toets$ = "p" OR Toets$ = "P" THEN
    BottomLine$ = "Pause"
    BottomLineDelay = 1
    WriteBottomLine
    DO
    LOOP UNTIL INKEY$ <> ""
  ELSEIF Toets$ = "-" THEN
    RotationSpeed = -RotationSpeed
    BottomLine$ = "Rotation Reversed"
    BottomLineDelay = 30 * BottomLineSpeed
  ELSEIF Toets$ = "V" OR Toets$ = "v" THEN
    Verbose = (Verbose + 1) MOD 2
  ELSEIF Toets$ = "c" OR Toets$ = "C" THEN
    CLS
    BottomLine$ = "Screen Cleared (refresh)"
    BottomLineDelay = 30 * BottomLineSpeed
  ELSEIF Toets$ = "<" OR Toets$ = "," THEN
    DelayScreen = DelayScreen - 100
    IF DelayScreen < 0 THEN DelayScreen = 0
    BottomLine$ = "Screen Delay is " + STR$(DelayScreen)
    BottomLineDelay = 40 * BottomLineSpeed
  ELSEIF Toets$ = ">" OR Toets$ = "." THEN
    DelayScreen = DelayScreen + 100
    BottomLine$ = "Screen Delay is " + STR$(DelayScreen)
    BottomLineDelay = 40 * BottomLineSpeed
  ELSEIF Toets$ = "?" OR Toets$ = "/" THEN
    BottomLine$ = Keys$
    BottomLineDelay = 120 * BottomLineSpeed
  ELSEIF Toets$ = "d" OR Toets$ = "D" THEN
    IF DoubleLines = 0 THEN
      DoubleLines = 1
      BottomLine$ = "Double Lines enabled (slower)"
      BottomLineDelay = 40 * BottomLineSpeed
    ELSE
      DoubleLines = 0
      BottomLine$ = "DoubleLines Disabled (faster)"
      BottomLineDelay = 40 * BottomLineSpeed
    END IF
  ELSE
    Toets$ = "Q"
  END IF

LOOP UNTIL Toets$ = "Q" OR Toets$ = "q"

SYSTEM

SUB CalculateBasePoints
 
  LeftAngle(Now) = 0
  RightAngle(Now) = 0
  FOR BasePoint = 0 TO 2
    B(Now, BasePoint, 0) = PosMod((Rotation + (120 * BasePoint)), 360) 'Rotation
    B(Now, BasePoint, 1) = SIN(B(Now, BasePoint, 0) * DegToRad) * Size 'X
    B(Now, BasePoint, 2) = COS(B(Now, BasePoint, 0) * DegToRad) * Size 'Y
    B(Now, BasePoint, 3) = B(Now, BasePoint, 2) * Perspective(0)       'real Y
 
    'Angle:
    'Delta X = B(Now, BasePoint, 1)
    'Delta Y = -TopY + B(Now, BasePoint, 3)
    B(Now, BasePoint, 6) = B(Now, BasePoint, 1) / (-TopY + B(Now, BasePoint, 3))

    IF B(Now, BasePoint, 6) < LeftAngle(Now) THEN
      LeftAngle(Now) = B(Now, BasePoint, 6)
    ELSEIF B(Now, BasePoint, 6) > RightAngle(Now) THEN
      RightAngle(Now) = B(Now, BasePoint, 6)
    END IF
  NEXT BasePoint
 
  FOR BasePoint = 0 TO 2 'Find Angles of pyramid
    BPRot = (B(Now, BasePoint, 0))
    BPAngle = (B(Now, BasePoint, 6))
    IF (BPRot > 90) AND (BPRot < 270) AND (BPAngle < RightAngle(Now)) AND (BPAngle > LeftAngle(Now)) THEN
      B(Now, BasePoint, 4) = 0 ' invisible
    ELSEIF (BPAngle = RightAngle(Now)) THEN
      B(Now, BasePoint, 4) = 1 ' visible, but no rib
    ELSE
      B(Now, BasePoint, 4) = 2 ' Visible + rib
    END IF
  NEXT BasePoint

END SUB

SUB CalculateSevens
  FOR Seven = 0 TO 2
    S(Now, Seven, 0) = PosMod((Rotation + 60 + 120 * Seven), 360)
    S(Now, Seven, 1) = SIN(S(Now, Seven, 0) * DegToRad) * SevenDistance
    S(Now, Seven, 2) = COS(S(Now, Seven, 0) * DegToRad) * SevenDistance
    S(Now, Seven, 3) = SevenFloatHeight + S(Now, Seven, 2) * Perspective(SevenFloatHeight)
    Y = S(Now, Seven, 2)
    DisApp = Disappear(Y)

    S(Now, Seven, 5) = PosMod((Rotation * S(0, Seven, 4)), 360)
 
    'upper left corner:
    S(Now, Seven, 10) = SIN(S(Now, Seven, 5) * DegToRad) * SevenTopSize * .5 * DisApp
    S(Now, Seven, 11) = COS(S(Now, Seven, 5) * DegToRad) * SevenTopSize * .5 * DisApp
    S(Now, Seven, 12) = (S(Now, Seven, 11) * Perspective(SevenFloatHeight))

    'upper right corner
    S(Now, Seven, 13) = SIN(S(Now, Seven, 5) * DegToRad) * SevenTopSize * -.5 * DisApp
    S(Now, Seven, 14) = COS(S(Now, Seven, 5) * DegToRad) * SevenTopSize * -.5 * DisApp
    S(Now, Seven, 15) = (S(Now, Seven, 14) * Perspective(SevenFloatHeight))

    'lower corner
    S(Now, Seven, 16) = SIN(S(Now, Seven, 5) * DegToRad) * SevenBottomPos * DisApp
    S(Now, Seven, 17) = COS(S(Now, Seven, 5) * DegToRad) * SevenBottomPos * DisApp
    S(Now, Seven, 18) = (S(Now, Seven, 17) * Perspective(SevenFloatHeight - SevenHeight)) + SevenHeight * DisApp

    'Left-side Dash
    S(Now, Seven, 19) = SIN(S(Now, Seven, 5) * DegToRad) * SevenDashLeft * DisApp
    S(Now, Seven, 20) = COS(S(Now, Seven, 5) * DegToRad) * SevenDashLeft * DisApp
    S(Now, Seven, 21) = (S(Now, Seven, 20) * Perspective(SevenFloatHeight - SevenDashHeight)) + SevenDashHeight * DisApp
   
    'Right-side Dash
    S(Now, Seven, 22) = SIN(S(Now, Seven, 5) * DegToRad) * SevenDashRight * DisApp
    S(Now, Seven, 23) = COS(S(Now, Seven, 5) * DegToRad) * SevenDashRight * DisApp
    S(Now, Seven, 24) = (S(Now, Seven, 23) * Perspective(SevenFloatHeight - SevenDashHeight)) + SevenDashHeight * DisApp
   

  NEXT Seven
END SUB

FUNCTION Disappear (Y)
  '+- 100 => 1
  ' +- -100 => .6
 
  Disappear = (300 + Y) / 400 * 1.2
END FUNCTION

FUNCTION DrawPyramid (Frame, DrawColor, InvisibleColor)
  FOR BasePoint = 0 TO 2
    NextBasePoint = (BasePoint + 1) MOD 3
     
    'Top to base-point
    X1 = B(Frame, BasePoint, 1)
    Y1 = B(Frame, BasePoint, 3)
    'Basepoint to Basepoint
   
    X2 = B(Frame, NextBasePoint, 1)
    Y2 = B(Frame, NextBasePoint, 3)
    IF B(Frame, BasePoint, 4) > 1 THEN
      Bla = TDLine(X1, Y1, X2, Y2, DrawColor)
    ELSE
      Bla = TDLine(X1, Y1, X2, Y2, InvisibleColor)
    END IF

    IF B(Frame, BasePoint, 4) > 0 THEN
      Bla = TDLine(X1, Y1, 0, TopY, DrawColor)
    ELSE
      Bla = TDLine(X1, Y1, 0, TopY, InvisibleColor)
    END IF

  NEXT BasePoint

END FUNCTION

FUNCTION DrawSeven (Frame, DrawColor, InvisibleColor, Moment)

  FOR Seven = 0 TO 2
    R = S(Frame, Seven, 0)
   
    'Moment = 0, 7s in the back
    'Moment = 1, 7s in the Front
    'Moment = -1 All 7s

    IF (R <= 270 AND R >= 90 AND Moment = 0) OR ((R > 270 OR R < 90) AND Moment = 1) OR (Moment = -1) THEN

      X = S(Frame, Seven, 1)
      Y = S(Frame, Seven, 3)

      X1 = X + S(Frame, Seven, 10)
      Y1 = Y + S(Frame, Seven, 12)
      X2 = X + S(Frame, Seven, 13)
      Y2 = Y + S(Frame, Seven, 15)
      Bl = SevenLine(X1, Y1, X2, Y2, Frame, Seven, DrawColor, InvisibleColor)

      X1 = X + S(Frame, Seven, 16)
      Y1 = Y + S(Frame, Seven, 18)
      Bla = SevenLine(X1, Y1, X2, Y2, Frame, Seven, DrawColor, InvisibleColor)

      X1 = X + S(Frame, Seven, 19)
      Y1 = Y + S(Frame, Seven, 21)
      X2 = X + S(Frame, Seven, 22)
      Y2 = Y + S(Frame, Seven, 24)
      Bla = SevenLine(X1, Y1, X2, Y2, Frame, Seven, DrawColor, InvisibleColor)
    END IF
  NEXT Seven
 
END FUNCTION

FUNCTION Perspective (Height)
  Perspective = (Height + 75) / 350
END FUNCTION

FUNCTION PosMod (Number, ModuledBy)
  DO WHILE Number < 0
    Number = Number + ModuledBy
  LOOP
  PosMod = Number MOD ModuledBy
END FUNCTION

FUNCTION SevenLine (X1, Y1, X2, Y2, Frame, Seven, DrawColor, InvisibleColor)
 
  IF (S(Frame, Seven, 0) < 90 OR S(Frame, Seven, 0) > 269) THEN
    ' Never behind pyramid
    Bla = TDLine(X1, Y1, X2, Y2, DrawColor)

  ELSEIF S(Frame, Seven, 0) > 89 AND S(Frame, Seven, 0) < 181 THEN
    ' May be behind right angle
    Angle1 = (X1) / (-TopY + Y1)
    Angle2 = (X2) / (-TopY + Y2)

    IF Angle1 < RightAngle(Frame) AND Angle2 < RightAngle(Frame) THEN
      ' Both coords are behind right side of pyramid
      Bla = TDLine(X1, Y1, X2, Y2, InvisibleColor)
   
    ELSEIF Angle1 > RightAngle(Frame) AND Angle2 > RightAngle(Frame) THEN
      ' Both coords above right side of pyramid
      Bla = TDLine(X1, Y1, X2, Y2, DrawColor)
   
    ELSE
      ' One dot behind Pyramid right side, find crossing
      Yprj1 = (X1 + TopY * RightAngle(Frame)) / RightAngle(Frame)
      Yprj2 = (X2 + TopY * RightAngle(Frame)) / RightAngle(Frame)

      DeltaY1 = Y1 - Yprj1
      DeltaY2 = -Y2 + Yprj2
      Ratio12 = DeltaY1 / (DeltaY2)
      XCross = X1 + ((X2 - X1) * Ratio12) / (1 + Ratio12)
      YCross = (XCross + TopY * RightAngle(Frame)) / RightAngle(Frame)

      IF Angle1 > RightAngle(Frame) THEN
        Bla = TDLine(XCross, YCross, X2, Y2, InvisibleColor)
        Bla = TDLine(XCross, YCross, X1, Y1, DrawColor)
      ELSE
        Bla = TDLine(XCross, YCross, X1, Y1, InvisibleColor)
        Bla = TDLine(XCross, YCross, X2, Y2, DrawColor)
      END IF
    END IF
 
  ELSEIF S(Frame, Seven, 0) > 180 AND S(Frame, Seven, 0) < 270 THEN
    ' May be behind left corner!
    Angle1 = (X1) / (-TopY + Y1)
    Angle2 = (X2) / (-TopY + Y2)

    IF Angle1 > LeftAngle(Frame) AND Angle2 > LeftAngle(Frame) THEN
      ' Both coords are behind Left side of pyramid
      Bla = TDLine(X1, Y1, X2, Y2, InvisibleColor)
  
    ELSEIF Angle1 < LeftAngle(Frame) AND Angle2 < LeftAngle(Frame) THEN
      ' Both coords above Left side of pyramid
      Bla = TDLine(X1, Y1, X2, Y2, DrawColor)
  
    ELSE
      ' One dot behind Pyramid right side, find crossing
      Yprj1 = (X1 + TopY * LeftAngle(Frame)) / LeftAngle(Frame)
      Yprj2 = (X2 + TopY * LeftAngle(Frame)) / LeftAngle(Frame)

      DeltaY1 = Y1 - Yprj1
      DeltaY2 = -Y2 + Yprj2
      Ratio12 = DeltaY1 / (DeltaY2)
      XCross = X1 + ((X2 - X1) * Ratio12) / (1 + Ratio12)
      YCross = (XCross + TopY * LeftAngle(Frame)) / LeftAngle(Frame)

      IF Angle1 < LeftAngle(Frame) THEN
        Bla = TDLine(XCross, YCross, X2, Y2, InvisibleColor)
        Bla = TDLine(XCross, YCross, X1, Y1, DrawColor)
      ELSE
        Bla = TDLine(XCross, YCross, X1, Y1, InvisibleColor)
        Bla = TDLine(XCross, YCross, X2, Y2, DrawColor)
      END IF
    END IF
 
 
  ELSE
    PRINT "Hier hoor je niet te komen!!", S(Frame, Seven, 0)
  END IF
END FUNCTION

FUNCTION TDLine (X1, Y1, X2, Y2, LineColor)
  LINE (X1 + TDoffsetX, Y1 + TDoffsetY)-(X2 + TDoffsetX, Y2 + TDoffsetY), LineColor
 
  IF DoubleLines = 1 THEN
    LINE (X1 + TDoffsetX + 1, Y1 + TDoffsetY + 1)-(X2 + TDoffsetX + 1, Y2 + TDoffsetY + 1), LineColor
    LINE (X1 + TDoffsetX + 1, Y1 + TDoffsetY)-(X2 + TDoffsetX, 1 + Y2 + TDoffsetY), LineColor
    LINE (X1 + TDoffsetX, Y1 + TDoffsetY + 1)-(X2 + TDoffsetX + 1, Y2 + TDoffsetY), LineColor
  END IF
END FUNCTION

SUB WriteBottomLine
  IF BottomLine$ <> "" THEN
    BottomLineMU$ = LEFT$(BottomLine$ + "                                                                                ", 79)
    BottomLine$ = ""
    LOCATE 30, 1: PRINT BottomLineMU$;
  ELSEIF BottomLineDelay = 1 THEN
    BottomLineDelay = BottomLineDelay - 1
    LOCATE 30, 1: PRINT "                                                                                ";
    BottomLineDelay = 0
  ELSEIF BottomLineDelay > 1 THEN
    BottomLineDelay = BottomLineDelay - 1
  END IF
END SUB

SUB WriteStats
 LOCATE 1, 1: PRINT "Rotation: ", Rotation
 LOCATE 2, 3: PRINT "Basepoint 1: "
 LOCATE 3, 4: PRINT "Rotation: ", B(Now, 0, 0)
 LOCATE 4, 3: PRINT "X: ", B(Now, 0, 1)
 LOCATE 5, 4: PRINT "Y: ", B(Now, 0, 2)
 LOCATE 6, 3: PRINT "Basepoint 2: "
 LOCATE 7, 4: PRINT "Rotation: ", B(Now, 1, 0)
 LOCATE 8, 3: PRINT "X: ", B(Now, 1, 1)
 LOCATE 9, 4: PRINT "Y: ", B(Now, 1, 2)
 LOCATE 10, 3: PRINT "Basepoint 3: "
 LOCATE 11, 4: PRINT "Rotation: ", B(Now, 2, 0)
 LOCATE 12, 3: PRINT "X: ", B(Now, 2, 1)
 LOCATE 13, 4: PRINT "Y: ", B(Now, 2, 2)

END SUB