home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 10 / 10.iso / l / l391 / 2.ddi / TORDRAW.BA$ / TORDRAW.bin
Encoding:
Text File  |  1992-08-19  |  30.2 KB  |  971 lines

  1. ' ------------------------------------------------------------------------
  2. ' Visual Basic for MS-DOS Torus Program Support Module
  3. '
  4. ' Provides routines for creating and drawing graphic
  5. ' Torus figure.
  6. '
  7. ' Copyright (C) 1982-1992 Microsoft Corporation
  8. '
  9. ' You have a royalty-free right to use, modify, reproduce
  10. ' and distribute the sample applications and toolkits provided with
  11. ' Visual Basic for MS-DOS (and/or any modified version)
  12. ' in any way you find useful, provided that you agree that
  13. ' Microsoft has no warranty, obligations or liability for
  14. ' any of the sample applications or toolkits.
  15. ' ------------------------------------------------------------------------
  16.  
  17. DEFINT A-Z
  18.  
  19. '$FORM frmTorus
  20.  
  21. DECLARE SUB CountTiles (T1%, T2%)
  22. DECLARE FUNCTION DegToRad! (Degrees%)
  23. DECLARE SUB Delay (Seconds!)
  24. DECLARE FUNCTION Inside% (T AS ANY)
  25. DECLARE FUNCTION Rotated% (Lower%, Upper%, Current%, Inc%)
  26. DECLARE SUB SetConfig (mode AS INTEGER)
  27. DECLARE SUB SetPalette ()
  28. DECLARE SUB TileDraw (T AS ANY)
  29. DECLARE SUB TorDraw ()
  30. DECLARE SUB TorusCalc (T() AS ANY)
  31. DECLARE SUB TorusColor (T() AS ANY)
  32. DECLARE SUB TorusDefine ()
  33. DECLARE SUB TorusDraw (T() AS ANY, Index() AS INTEGER)
  34. DECLARE SUB TorusRotate (First%)
  35. DECLARE SUB TorusSort (Low%, High%)
  36.  
  37. ' General purpose constants
  38. CONST PI = 3.14159
  39. CONST TRUE = -1, FALSE = 0
  40. CONST BACK = 0
  41. CONST BORD_YES = 1
  42.  
  43. ' Rotation flags
  44. CONST RNDM = -1
  45. CONST START = 0
  46. CONST CONTINUE = 1
  47.  
  48. ' Constants for best available screen mode
  49. CONST VGA = 12
  50. CONST MCGA = 13
  51. CONST EGA256 = 9
  52. CONST EGA64 = 8
  53. CONST MONO = 10
  54. CONST HERC = 3
  55. CONST CGA = 1
  56.  
  57.  
  58. ' User-defined type for tiles - an array of these make a torus
  59. TYPE tile
  60.    x1    AS SINGLE
  61.    x2    AS SINGLE
  62.    x3    AS SINGLE
  63.    x4    AS SINGLE
  64.    y1    AS SINGLE
  65.    y2    AS SINGLE
  66.    y3    AS SINGLE
  67.    y4    AS SINGLE
  68.    z1    AS SINGLE
  69.    xc    AS SINGLE
  70.    yc    AS SINGLE
  71.    TColor AS INTEGER
  72. END TYPE
  73.  
  74. ' User-defined type to hold information about the mode
  75. TYPE Config
  76.    Scrn     AS INTEGER
  77.    Colors   AS INTEGER
  78.    Atribs   AS INTEGER
  79.    XPix     AS INTEGER
  80.    YPix     AS INTEGER
  81.    TCOL     AS INTEGER
  82.    TROW     AS INTEGER
  83. END TYPE
  84.  
  85. ' User-defined type to hold information about current Torus
  86. TYPE Torus
  87.    Panel    AS INTEGER
  88.    Sect     AS INTEGER
  89.    Thick    AS SINGLE
  90.    XDegree  AS INTEGER
  91.    YDegree  AS INTEGER
  92.    Bord     AS STRING * 3
  93.    Delay    AS SINGLE
  94. END TYPE
  95.  
  96. ' Video configuration
  97. DIM SHARED VC AS Config
  98.  
  99. ' Torus to be drawn
  100. DIM SHARED Tor AS Torus
  101.  
  102. ' Number of pieces to draw
  103. DIM SHARED Max AS INTEGER
  104.  
  105. ' A palette of colors to paint with
  106. DIM SHARED Pal(0 TO 300) AS LONG
  107.  
  108. ' Array for indexes
  109. DIM SHARED Index() AS INTEGER
  110.  
  111. ' Array for tiles
  112. DIM SHARED T() AS tile
  113.  
  114. ' Best graphics screen mode.
  115. DIM SHARED BestMode AS INTEGER
  116.  
  117.  
  118.  
  119. ' ============================ CountTiles ==============================
  120. '   Displays number of the tiles currently being calculated or sorted.
  121. ' ======================================================================
  122. '
  123. STATIC SUB CountTiles (T1, T2)
  124.    ' If positive then display else erase
  125.    IF T1 > 0 AND T2 > 0 THEN
  126.       ' Show numbers inside form
  127.       frmTorus.lblCalc.Caption = FORMAT$(T1) + "  " + FORMAT$(T2)
  128.    ELSE
  129.       frmTorus.lblCalc.Caption = ""
  130.    END IF
  131. END SUB
  132.  
  133. ' ============================ DegToRad ================================
  134. '   Convert degrees to radians, since BASIC trigonometric functions
  135. '   require radians.
  136. ' ======================================================================
  137. '
  138. STATIC FUNCTION DegToRad! (Degrees)
  139.    DegToRad! = (Degrees * 2 * PI) / 360
  140. END FUNCTION
  141.  
  142. ' =============================== Delay ================================
  143. '   Delay based on time so that wait will be the same on any processor.
  144. '   Notice the check for negative numbers so that the delay won't
  145. '   freeze at midnight when the delay could become negative.
  146. ' ======================================================================
  147. '
  148. STATIC SUB Delay (Seconds!)
  149.  
  150.    Begin! = TIMER
  151.    DO UNTIL (TIMER - Begin! > Seconds!) OR (TIMER - Begin! < 0)
  152.    LOOP
  153.  
  154. END SUB
  155.  
  156. ' ============================ GetConfig ===============================
  157. '   Get the starting number of lines and the video adapter.
  158. ' ======================================================================
  159. '
  160. SUB GetConfig ()
  161.  
  162.    ' Assume best possible screen mode
  163.    BestMode = VGA
  164.    Available$ = "12789BCD"
  165.    
  166.    ON LOCAL ERROR GOTO VideoErr
  167.    ' Fall through error trap until a mode works
  168.    SCREEN BestMode
  169.    ' If EGA, then check pages to see whether more than 64K
  170.    ON LOCAL ERROR GOTO EGAErr
  171.    IF BestMode = EGA256 THEN SCREEN 8, , 1
  172.    
  173.    ON ERROR GOTO 0
  174.    
  175.    ' Reset text mode
  176.    SCREEN 0, , 0
  177.    WIDTH 80, 25
  178.  
  179.    FOR tmp% = 1 TO LEN(Available$)
  180.         ScrnVal = VAL("&H" + MID$(Available$, tmp%, 1))
  181.         frmTorus.CboScrn.ADDITEM FORMAT$(ScrnVal)
  182.         IF ScrnVal = BestMode THEN frmTorus.CboScrn.ListIndex = tmp% - 1
  183.    NEXT
  184.  
  185.    EXIT SUB
  186.  
  187. ' Error trap to make torus screen independent
  188. VideoErr:
  189.    SELECT CASE BestMode    ' Fall through until something works
  190.       CASE VGA
  191.          BestMode = MCGA
  192.          Available$ = "12BD"
  193.       CASE MCGA
  194.          BestMode = EGA256
  195.          Available$ = "12789"
  196.       CASE EGA256
  197.          BestMode = CGA
  198.          Available$ = "12"
  199.       CASE CGA
  200.          BestMode = MONO
  201.          Available$ = "A"
  202.       CASE MONO
  203.          BestMode = HERC
  204.          Available$ = "3"
  205.       CASE ELSE
  206.          PRINT "Graphics support not available.  Cannot run Torus sample program."
  207.          END
  208.    END SELECT
  209.    RESUME
  210.  
  211. ' Trap to detect 64K EGA
  212. EGAErr:
  213.    BestMode = EGA64
  214.    Available$ = "12789"
  215.    RESUME NEXT
  216.  
  217. END SUB
  218.  
  219. ' ============================== Inside ================================
  220. '   Finds a point, T.xc and T.yc, that is mathematically within a tile.
  221. '   Then check to see if the point is actually inside. Because of the
  222. '   jagged edges of tiles, the center point is often actually inside
  223. '   very thin tiles. Such tiles will not be painted, This causes
  224. '   imperfections that are often visible at the edge of the Torus.
  225. '
  226. '   Return FALSE if a center point is not found inside a tile.
  227. ' ======================================================================
  228. '
  229. STATIC FUNCTION Inside (T AS tile)
  230.    DIM Highest AS SINGLE, Lowest AS SINGLE
  231.  
  232.    Border = VC.Atribs - 1
  233.  
  234.    ' Find an inside point. Since some tiles are triangles, the
  235.    ' diagonal center isn't good enough. Instead find the center
  236.    ' by drawing a diagonal from the center of the outside to
  237.    ' a bottom corner.
  238.    T.xc = T.x2 + ((T.x3 + (T.x4 - T.x3) / 2 - T.x2) / 2)
  239.    T.yc = T.y2 + ((T.y3 + (T.y4 - T.y3) / 2 - T.y2) / 2)
  240.  
  241.    ' If we're on a border, no need to fill
  242.    IF POINT(T.xc, T.yc) = Border THEN
  243.       Inside = FALSE
  244.       EXIT FUNCTION
  245.    END IF
  246.  
  247.    ' Find highest and lowest Y on the tile
  248.    Highest = T.y1
  249.    Lowest = T.y1
  250.    IF T.y2 > Highest THEN Highest = T.y2
  251.    IF T.y2 < Lowest THEN Lowest = T.y2
  252.    IF T.y3 > Highest THEN Highest = T.y3
  253.    IF T.y3 < Lowest THEN Lowest = T.y3
  254.    IF T.y4 > Highest THEN Highest = T.y4
  255.    IF T.y4 < Lowest THEN Lowest = T.y4
  256.  
  257.    ' Convert coordinates to pixels
  258.    X = PMAP(T.xc, 0)
  259.    YU = PMAP(T.yc, 1)
  260.    YD = YU
  261.    H = PMAP(Highest, 1)
  262.    L = PMAP(Lowest, 1)
  263.  
  264.    ' Search for top and bottom tile borders until we either find them
  265.    ' both, or check beyond the highest and lowest points.
  266.  
  267.    IsUp = FALSE
  268.    IsDown = FALSE
  269.  
  270.    DO
  271.       YU = YU - 1
  272.       YD = YD + 1
  273.    
  274.       ' Search up
  275.       IF NOT IsUp THEN
  276.          IF POINT(T.xc, PMAP(YU, 3)) = Border THEN IsUp = TRUE
  277.       END IF
  278.   
  279.       ' Search down
  280.       IF NOT IsDown THEN
  281.          IF POINT(T.xc, PMAP(YD, 3)) = Border THEN IsDown = TRUE
  282.       END IF
  283.                                          
  284.       ' If top and bottom are found, we're inside
  285.       IF IsUp AND IsDown THEN
  286.          Inside = TRUE
  287.          EXIT FUNCTION
  288.       END IF
  289.  
  290.    LOOP UNTIL (YD > L) AND (YU < H)
  291.    Inside = FALSE
  292.  
  293. END FUNCTION
  294.  
  295. ' ============================ Rotated =================================
  296. '   Returns the Current value adjusted by Inc and rotated if necessary
  297. '   so that it falls within the range of Lower and Upper.
  298. ' ======================================================================
  299. '
  300. FUNCTION Rotated (Lower, Upper, Current, Inc)
  301.  
  302.    ' Calculate the next value
  303.    Current = Current + Inc
  304.   
  305.    ' Handle special cases of rotating off top or bottom
  306.    IF Current > Upper THEN Current = Lower
  307.    IF Current < Lower THEN Current = Upper
  308.    Rotated = Current
  309.  
  310. END FUNCTION
  311.  
  312. ' ============================ SetConfig ===============================
  313. '   Sets the correct values for each field of the VC variable. They
  314. '   vary depending on Mode and on the current configuration.
  315. ' ======================================================================
  316. '
  317. STATIC SUB SetConfig (mode AS INTEGER)
  318.    SELECT CASE mode
  319.       CASE 1   ' Four-color graphics for CGA, EGA, VGA, and MCGA
  320.          IF BestMode = CGA OR BestMode = MCGA THEN
  321.             VC.Colors = 0
  322.          ELSE
  323.             VC.Colors = 16
  324.          END IF
  325.          VC.Atribs = 4
  326.          VC.XPix = 319
  327.          VC.YPix = 199
  328.          VC.TCOL = 40
  329.          VC.TROW = 25
  330.       CASE 2   ' Two-color medium-res graphics for CGA, EGA, VGA, and MCGA
  331.          IF BestMode = CGA OR BestMode = MCGA THEN
  332.             VC.Colors = 0
  333.          ELSE
  334.             VC.Colors = 16
  335.          END IF
  336.          VC.Atribs = 2
  337.          VC.XPix = 639
  338.          VC.YPix = 199
  339.          VC.TCOL = 80
  340.          VC.TROW = 25
  341.       CASE 3   ' Two-color high-res graphics for Hercules
  342.          VC.Colors = 0
  343.          VC.Atribs = 2
  344.          VC.XPix = 720
  345.          VC.YPix = 348
  346.          VC.TCOL = 80
  347.          VC.TROW = 25
  348.       CASE 7   ' 16-color medium-res graphics for EGA and VGA
  349.          VC.Colors = 16
  350.          VC.Atribs = 16
  351.          VC.XPix = 319
  352.          VC.YPix = 199
  353.          VC.TCOL = 40
  354.          VC.TROW = 25
  355.       CASE 8   ' 16-color high-res graphics for EGA and VGA
  356.          VC.Colors = 16
  357.          VC.Atribs = 16
  358.          VC.XPix = 639
  359.          VC.YPix = 199
  360.          VC.TCOL = 80
  361.          VC.TROW = 25
  362.       CASE 9   ' 16- or 4-color very high-res graphics for EGA and VGA
  363.          VC.Colors = 64
  364.          IF BestMode = EGA64 THEN VC.Atribs = 4 ELSE VC.Atribs = 16
  365.          VC.XPix = 639
  366.          VC.YPix = 349
  367.          VC.TCOL = 80
  368.          VC.TROW = 25
  369.       CASE 10  ' Two-color high-res graphics for EGA or VGA monochrome
  370.          VC.Colors = 0
  371.          VC.Atribs = 2
  372.          VC.XPix = 319
  373.          VC.YPix = 199
  374.          VC.TCOL = 80
  375.          VC.TROW = 25
  376.       CASE 11  ' Two-color very high-res graphics for VGA and MCGA
  377.          ' Note that for VGA screens 11, 12, and 13, more colors are
  378.          ' available, depending on how the colors are mixed.
  379.          VC.Colors = 216
  380.          VC.Atribs = 2
  381.          VC.XPix = 639
  382.          VC.YPix = 479
  383.          VC.TCOL = 80
  384.          VC.TROW = 30
  385.       CASE 12  ' 16-color very high-res graphics for VGA
  386.          VC.Colors = 216
  387.          VC.Atribs = 16
  388.          VC.XPix = 639
  389.          VC.YPix = 479
  390.          VC.TCOL = 80
  391.          VC.TROW = 30
  392.       CASE 13  ' 256-color medium-res graphics for VGA and MCGA
  393.          VC.Colors = 216
  394.          VC.Atribs = 256
  395.          VC.XPix = 639
  396.          VC.YPix = 479
  397.          VC.TCOL = 40
  398.          VC.TROW = 25
  399.       CASE ELSE
  400.          VC.Colors = 16
  401.          VC.Atribs = 16
  402.          VC.XPix = 0
  403.          VC.YPix = 0
  404.          VC.TCOL = 80
  405.          VC.TROW = 25
  406.          VC.Scrn = 0
  407.          EXIT SUB
  408.    END SELECT
  409.    VC.Scrn = mode
  410.  
  411. END SUB
  412.  
  413. ' ============================ SetPalette ==============================
  414. '   Mixes palette colors in an array.
  415. ' ======================================================================
  416. '
  417. STATIC SUB SetPalette ()
  418.  
  419.    ' Mix only if the adapter supports color attributes
  420.    IF VC.Colors THEN
  421.       SELECT CASE VC.Scrn
  422.          CASE 1, 2, 7, 8
  423.             ' Red, green, blue, and intense in four bits of a byte
  424.             ' Bits: 0000irgb
  425.             ' Change the order of FOR loops to change color mix
  426.             Index = 0
  427.             FOR Bs = 0 TO 1
  428.                FOR Gs = 0 TO 1
  429.                   FOR Rs = 0 TO 1
  430.                      FOR Hs = 0 TO 1
  431.                         Pal(Index) = Hs * 8 + Rs * 4 + Gs * 2 + Bs
  432.                         Index = Index + 1
  433.                      NEXT
  434.                   NEXT
  435.                NEXT
  436.             NEXT
  437.          CASE 9
  438.             ' EGA red, green, and blue colors in 6 bits of a byte
  439.             ' Capital letters repesent intense, lowercase normal
  440.             ' Bits:  00rgbRGB
  441.             ' Change the order of FOR loops to change color mix
  442.             Index = 0
  443.             FOR Bs = 0 TO 1
  444.                FOR Gs = 0 TO 1
  445.                   FOR Rs = 0 TO 1
  446.                      FOR HRs = 0 TO 1
  447.                         FOR HGs = 0 TO 1
  448.                            FOR HBs = 0 TO 1
  449.                               Pal(Index) = Rs * 32 + Gs * 16 + Bs * 8 + HRs * 4 + HGs * 2 + HBs
  450.                               Index = Index + 1
  451.                            NEXT
  452.                         NEXT
  453.                      NEXT
  454.                   NEXT
  455.                NEXT
  456.             NEXT
  457.          CASE 11, 12, 13
  458.             ' VGA colors in 6 bits of 3 bytes of a long integer
  459.             ' Bits:  000000000 00bbbbbb 00gggggg 00rrrrrr
  460.             ' Change the order of FOR loops to change color mix
  461.             ' Decrease the STEP and increase VC.Colors to get more colors
  462.             Index = 0
  463.             FOR Rs = 0 TO 63 STEP 11
  464.                FOR Bs = 0 TO 63 STEP 11
  465.                   FOR Gs = 0 TO 63 STEP 11
  466.                      Pal(Index) = (65536 * Bs) + (256 * Gs) + Rs
  467.                      Index = Index + 1
  468.                   NEXT
  469.                NEXT
  470.             NEXT
  471.          CASE ELSE
  472.       END SELECT
  473.       ' Assign colors
  474.       IF VC.Atribs > 2 THEN TorusRotate RNDM
  475.    END IF
  476.  
  477. END SUB
  478.  
  479. ' ============================ TileDraw ================================
  480. '   Draw and optionally paint a tile. Tiles are painted if there are
  481. '   more than two atributes and if the inside of the tile can be found.
  482. ' ======================================================================
  483. '
  484. STATIC SUB TileDraw (T AS tile)
  485.  
  486.    'Set border
  487.    Border = VC.Atribs - 1
  488.  
  489.    IF VC.Atribs = 2 THEN
  490.       ' Draw and quit for two-color modes
  491.       LINE (T.x1, T.y1)-(T.x2, T.y2), T.TColor
  492.       LINE -(T.x3, T.y3), T.TColor
  493.       LINE -(T.x4, T.y4), T.TColor
  494.       LINE -(T.x1, T.y1), T.TColor
  495.       EXIT SUB
  496.    ELSE
  497.       ' For other modes, draw in the border color
  498.       ' (which must be different than any tile color)
  499.       LINE (T.x1, T.y1)-(T.x2, T.y2), Border
  500.       LINE -(T.x3, T.y3), Border
  501.       LINE -(T.x4, T.y4), Border
  502.       LINE -(T.x1, T.y1), Border
  503.    END IF
  504.  
  505.    ' See if tile is large enough to be painted
  506.    IF Inside(T) THEN
  507.       'Black out the center to make sure it isn't paint color
  508.       PRESET (T.xc, T.yc)
  509.       ' Paint tile black so colors of underlying tiles can't interfere
  510.       PAINT STEP(0, 0), BACK, Border
  511.       ' Fill with the final tile color.
  512.       PAINT STEP(0, 0), T.TColor, Border
  513.    END IF
  514.  
  515.    ' A border drawn with the background color looks like a border.
  516.    ' One drawn with the tile color doesn't look like a border.
  517.    IF Tor.Bord = "YES" THEN
  518.       Border = BACK
  519.    ELSE
  520.       Border = T.TColor
  521.    END IF
  522.  
  523.    ' Redraw with the final border
  524.    LINE (T.x1, T.y1)-(T.x2, T.y2), Border
  525.    LINE -(T.x3, T.y3), Border
  526.    LINE -(T.x4, T.y4), Border
  527.    LINE -(T.x1, T.y1), Border
  528.  
  529. END SUB
  530.  
  531. ' ============================ TorDraw ================================
  532. '   Draw and rotate torus while waiting for user input to continue.
  533. ' ======================================================================
  534. '
  535. SUB TorDraw ()
  536.  
  537.     ' Set the screen mode
  538.     SCREEN VC.Scrn
  539.  
  540.     ' Mix a palette of colors
  541.     SetPalette
  542.  
  543.     ' Set logical window with variable thickness
  544.     ' Center is 0, up and right are positive, down and left are negative
  545.     WINDOW (-(Tor.Thick + 1), -(Tor.Thick + 1))-(Tor.Thick + 1, Tor.Thick + 1)
  546.  
  547.     ' Draw and paint the tiles, the farthest first and nearest last
  548.     TorusDraw T(), Index()
  549.  
  550.     ' Show an exit message
  551.     LOCATE VC.TROW - 1, 1
  552.     PRINT "Press any key to continue";
  553.  
  554.     ' Rotate the torus by rotating the color palette
  555.     DO WHILE INKEY$ = ""
  556.        Delay (Tor.Delay)
  557.        TorusRotate CONTINUE
  558.     LOOP
  559.  
  560.     SCREEN 0
  561.     WIDTH 80
  562.  
  563. END SUB
  564.  
  565. ' ============================ TorMain ================================
  566. '   Create torus from user input then display it.
  567. ' ======================================================================
  568. '
  569. SUB TorMain ()
  570.  
  571.       ' Get Torus definition from user
  572.       TorusDefine
  573.  
  574.       ' Dynamically dimension arrays
  575.       DO
  576.          tmp = Tor.Panel
  577.          Max = Tor.Panel * Tor.Sect
  578.  
  579.          ' Array for indexes
  580.          REDIM Index(0 TO Max - 1) AS INTEGER
  581.          ' Turn on error trap for insufficient memory
  582.          ON LOCAL ERROR GOTO MemErr
  583.          ' Array for tiles
  584.          REDIM T(0 TO Max - 1) AS tile
  585.       LOOP UNTIL tmp = Tor.Panel
  586.  
  587.       ' Initialize array of indexes
  588.       FOR Til = 0 TO Max - 1
  589.          Index(Til) = Til
  590.       NEXT
  591.  
  592.       ' Calculate the points of each tile on the torus
  593.     frmTorus.lblCalcMsg.Caption = "Calculating..."
  594.     TorusCalc T()
  595.     frmTorus.lblCalcMsg.Caption = ""
  596.  
  597.     ' Color each tile in the torus.
  598.     TorusColor T()
  599.  
  600.     ' Sort the tiles by their "distance" from the screen
  601.     frmTorus.lblCalcMsg.Caption = "Sorting..."
  602.     TorusSort 0, Max - 1
  603.     frmTorus.lblCalcMsg.Caption = ""
  604.  
  605.     screen.HIDE                 ' Hide option form before displaying graphics.
  606.     CALL TorDraw                ' Display the torus.
  607.     screen.SHOW                 ' Show option form again.
  608.  
  609.     EXIT SUB
  610.  
  611. ' Trap to detect insufficient memory and other errors.
  612. MemErr:
  613.    MSGBOX ERROR$ + ".  Cannot create Torus." + CHR$(13) + "Try reducing number of sections and panels.", 0, "Torus"
  614.    EXIT SUB
  615. END SUB
  616.  
  617. DEFSNG A-Z
  618. ' =========================== TorusCalc ================================
  619. '   Calculates the x and y coordinates for each tile.
  620. ' ======================================================================
  621. '
  622. STATIC SUB TorusCalc (T() AS tile)
  623.    DIM XSect AS INTEGER, YPanel AS INTEGER
  624.   
  625.    ' Calculate sine and cosine of the angles of rotation
  626.    XRot = DegToRad(Tor.XDegree)
  627.    YRot = DegToRad(Tor.YDegree)
  628.    CXRot = COS(XRot)
  629.    SXRot = SIN(XRot)
  630.    CYRot = COS(YRot)
  631.    SYRot = SIN(YRot)
  632.  
  633.    ' Calculate the angle to increment between one tile and the next.
  634.    XInc = 2 * PI / Tor.Sect
  635.    YInc = 2 * PI / Tor.Panel
  636.   
  637.    ' First calculate the first point, which will be used as a reference
  638.    ' for future points. This point must be calculated separately because
  639.    ' it is both the beginning and the end of the center seam.
  640.    FirstY = (Tor.Thick + 1) * CYRot
  641.                                  
  642.    ' Starting point is x1 of 0 section, 0 panel     last     0
  643.    T(0).x1 = FirstY                             ' +------+------+
  644.    ' Also x2 of tile on last section, 0 panel   ' |      |      | last
  645.    T(Tor.Sect - 1).x2 = FirstY                  ' |    x3|x4    |
  646.    ' Also x3 of last section, last panel        ' +------+------+
  647.    T(Max - 1).x3 = FirstY                       ' |    x2|x1    |  0
  648.    ' Also x4 of 0 section, last panel           ' |      |      |
  649.    T(Max - Tor.Sect).x4 = FirstY                ' +------+------+
  650.    ' A similar pattern is used for assigning all points of Torus
  651.   
  652.    ' Starting Y point is 0 (center)
  653.    T(0).y1 = 0
  654.    T(Tor.Sect - 1).y2 = 0
  655.    T(Max - 1).y3 = 0
  656.    T(Max - Tor.Sect).y4 = 0
  657.                           
  658.    ' Only one z coordinate is used in sort, so other three can be ignored
  659.    T(0).z1 = -(Tor.Thick + 1) * SYRot
  660.   
  661.    ' Starting at first point, work around the center seam of the Torus.
  662.    ' Assign points for each section. The seam must be calculated separately
  663.    ' because it is both beginning and of each section.
  664.    FOR XSect = 1 TO Tor.Sect - 1
  665.        
  666.       ' X, Y, and Z elements of equation
  667.       sx = (Tor.Thick + 1) * COS(XSect * XInc)
  668.       sy = (Tor.Thick + 1) * SIN(XSect * XInc) * CXRot
  669.       sz = (Tor.Thick + 1) * SIN(XSect * XInc) * SXRot
  670.       ssx = (sz * SYRot) + (sx * CYRot)
  671.   
  672.       T(XSect).x1 = ssx
  673.       T(XSect - 1).x2 = ssx
  674.       T(Max - Tor.Sect + XSect - 1).x3 = ssx
  675.       T(Max - Tor.Sect + XSect).x4 = ssx
  676.                                          
  677.       T(XSect).y1 = sy
  678.       T(XSect - 1).y2 = sy
  679.       T(Max - Tor.Sect + XSect - 1).y3 = sy
  680.       T(Max - Tor.Sect + XSect).y4 = sy
  681.                                          
  682.       T(XSect).z1 = (sz * CYRot) - (sx * SYRot)
  683.    NEXT
  684.   
  685.    ' Now start at the first seam between panel and assign points for
  686.    ' each section of each panel. The outer loop assigns the initial
  687.    ' point for the panel. This point must be calculated separately
  688.    ' since it is both the beginning and the end of the seam of panels.
  689.    FOR YPanel = 1 TO Tor.Panel - 1
  690.         
  691.       ' X, Y, and Z elements of equation
  692.       sx = Tor.Thick + COS(YPanel * YInc)
  693.       sy = -SIN(YPanel * YInc) * SXRot
  694.       sz = SIN(YPanel * YInc) * CXRot
  695.       ssx = (sz * SYRot) + (sx * CYRot)
  696.        
  697.       ' Assign X points for each panel
  698.       ' Current ring, current side
  699.       T(Tor.Sect * YPanel).x1 = ssx
  700.       ' Current ring minus 1, next side
  701.       T(Tor.Sect * (YPanel + 1) - 1).x2 = ssx
  702.       ' Current ring minus 1, previous side
  703.       T(Tor.Sect * YPanel - 1).x3 = ssx
  704.       ' Current ring, previous side
  705.       T(Tor.Sect * (YPanel - 1)).x4 = ssx
  706.                                           
  707.       ' Assign Y points for each panel
  708.       T(Tor.Sect * YPanel).y1 = sy
  709.       T(Tor.Sect * (YPanel + 1) - 1).y2 = sy
  710.       T(Tor.Sect * YPanel - 1).y3 = sy
  711.       T(Tor.Sect * (YPanel - 1)).y4 = sy
  712.                                         
  713.       ' Z point for each panel
  714.       T(Tor.Sect * YPanel).z1 = (sz * CYRot) - (sx * SYRot)
  715.        
  716.       ' The inner loop assigns points for each ring (except the first)
  717.       ' on the current side.
  718.       FOR XSect = 1 TO Tor.Sect - 1
  719.                                                  
  720.          ' Display section and panel
  721.          CountTiles XSect, YPanel
  722.                                                             
  723.          ty = (Tor.Thick + COS(YPanel * YInc)) * SIN(XSect * XInc)
  724.          tz = SIN(YPanel * YInc)
  725.          sx = (Tor.Thick + COS(YPanel * YInc)) * COS(XSect * XInc)
  726.          sy = ty * CXRot - tz * SXRot
  727.          sz = ty * SXRot + tz * CXRot
  728.          ssx = (sz * SYRot) + (sx * CYRot)
  729.           
  730.          T(Tor.Sect * YPanel + XSect).x1 = ssx
  731.          T(Tor.Sect * YPanel + XSect - 1).x2 = ssx
  732.          T(Tor.Sect * (YPanel - 1) + XSect - 1).x3 = ssx
  733.          T(Tor.Sect * (YPanel - 1) + XSect).x4 = ssx
  734.                                                           
  735.          T(Tor.Sect * YPanel + XSect).y1 = sy
  736.          T(Tor.Sect * YPanel + XSect - 1).y2 = sy
  737.          T(Tor.Sect * (YPanel - 1) + XSect - 1).y3 = sy
  738.          T(Tor.Sect * (YPanel - 1) + XSect).y4 = sy
  739.                                                             
  740.          T(Tor.Sect * YPanel + XSect).z1 = (sz * CYRot) - (sx * SYRot)
  741.       NEXT
  742.    NEXT
  743.    ' Erase message
  744.    CountTiles -1, -1
  745.  
  746. END SUB
  747.  
  748. DEFINT A-Z
  749. ' =========================== TorusColor ===============================
  750. '   Assigns color atributes to each tile.
  751. ' ======================================================================
  752. '
  753. STATIC SUB TorusColor (T() AS tile)
  754.         
  755.    ' Skip first and last atributes
  756.    LastAtr = VC.Atribs - 2
  757.    Atr = 1
  758.  
  759.    ' Cycle through each attribute until all tiles are done
  760.    FOR Til = 0 TO Max - 1
  761.       IF (Atr >= LastAtr) THEN
  762.          Atr = 1
  763.       ELSE
  764.          Atr = Atr + 1
  765.       END IF
  766.       T(Til).TColor = Atr
  767.    NEXT
  768.  
  769. END SUB
  770.  
  771. ' ============================ TorusDefine =============================
  772. '   Define the attributes of a Torus based on information from the
  773. '   user, the video configuration, and the current screen mode.
  774. ' ======================================================================
  775. '
  776. STATIC SUB TorusDefine ()
  777.  
  778.    Tor.Thick = VAL(frmTorus.txtThick.Text)
  779.    IF frmTorus.chkBord.Value = BORD_YES THEN
  780.     Tor.Bord = "YES"
  781.    ELSE
  782.     Tor.Bord = "NO"
  783.    END IF
  784.    Tor.Panel = VAL(frmTorus.TxtPanel.Text)
  785.    Tor.Sect = VAL(frmTorus.TxtSection.Text)
  786.    Tor.XDegree = VAL(frmTorus.TxtXDegree.Text)
  787.    Tor.YDegree = VAL(frmTorus.TxtYDegree.Text)
  788.    VC.Scrn = VAL(frmTorus.CboScrn.Text)
  789.  
  790.    ' Set configuration data for graphics mode
  791.    SetConfig VC.Scrn
  792.  
  793.    ' Set different delays depending on mode
  794.    SELECT CASE VC.Scrn
  795.       CASE 1
  796.          Tor.Delay = .3
  797.       CASE 2, 3, 10, 11, 13
  798.          Tor.Delay = 0
  799.       CASE ELSE
  800.          Tor.Delay = .05
  801.    END SELECT
  802.  
  803.    ' Get new random seed for this torus
  804.    RANDOMIZE TIMER
  805.  
  806. END SUB
  807.  
  808. ' =========================== TorusDraw ================================
  809. '   Draws each tile of the torus starting with the farthest and working
  810. '   to the closest. Thus nearer tiles overwrite farther tiles to give
  811. '   a three-dimensional effect. Notice that the index of the tile being
  812. '   drawn is actually the index of an array of indexes. This is because
  813. '   the array of tiles is not sorted, but the parallel array of indexes
  814. '   is. See TorusSort for an explanation of how indexes are sorted.
  815. ' ======================================================================
  816. '
  817. SUB TorusDraw (T() AS tile, Index() AS INTEGER)
  818.     FOR Til = 0 TO Max - 1
  819.         TileDraw T(Index(Til))
  820.     NEXT
  821. END SUB
  822.  
  823. ' =========================== TorusRotate ==============================
  824. '   Rotates the Torus. This can be done more successfully in some modes
  825. '   than in others. There are three methods:
  826. '
  827. '     1. Rotate the palette colors assigned to each attribute
  828. '     2. Draw, erase, and redraw the torus (two-color modes)
  829. '     3. Rotate between two palettes (CGA and MCGA screen 1)
  830. '
  831. '   Note that for EGA and VGA screen 2, methods 1 and 2 are both used.
  832. ' ======================================================================
  833. '
  834. STATIC SUB TorusRotate (First)
  835.    DIM Temp AS LONG
  836.  
  837.    ' For EGA and higher rotate colors through palette
  838.    IF VC.Colors THEN
  839.  
  840.       ' Argument determines whether to start at next color, first color,
  841.       ' or random color
  842.       SELECT CASE First
  843.          CASE RNDM
  844.             FirstClr = INT(RND * VC.Colors)
  845.          CASE START
  846.             FirstClr = 0
  847.          CASE ELSE
  848.             FirstClr = FirstClr - 1
  849.       END SELECT
  850.        
  851.       ' Set last color to smaller of last possible color or last tile
  852.       IF VC.Colors > Max - 1 THEN
  853.          LastClr = Max - 1
  854.       ELSE
  855.          LastClr = VC.Colors - 1
  856.       END IF
  857.    
  858.       ' If color is too low, rotate to end
  859.       IF FirstClr < 0 OR FirstClr >= LastClr THEN FirstClr = LastClr
  860.  
  861.       ' Set last attribute
  862.       IF VC.Atribs = 2 THEN
  863.          ' Last for two-color modes
  864.          LastAtr = VC.Atribs - 1
  865.       ELSE
  866.          ' Smaller of last color or next-to-last attribute
  867.          IF LastClr < VC.Atribs - 2 THEN
  868.             LastAtr = LastClr
  869.          ELSE
  870.             LastAtr = VC.Atribs - 2
  871.          END IF
  872.       END IF
  873.  
  874.       ' Cycle through attributes, assigning colors
  875.       Work = FirstClr
  876.       FOR Atr = LastAtr TO 1 STEP -1
  877.          PALETTE Atr, Pal(Work)
  878.          Work = Work - 1
  879.          IF Work < 0 THEN Work = LastClr
  880.       NEXT
  881.  
  882.    END IF
  883.  
  884.    ' For two-color screens, the best we can do is erase and redraw the torus
  885.    IF VC.Atribs = 2 THEN
  886.   
  887.       ' Set all tiles to color
  888.       FOR I = 0 TO Max - 1
  889.          T(I).TColor = Toggle
  890.       NEXT
  891.       ' Draw Torus
  892.       TorusDraw T(), Index()
  893.       ' Toggle between color and background
  894.       Toggle = (Toggle + 1) MOD 2
  895.  
  896.    END IF
  897.  
  898.    ' For CGA or MCGA screen 1, toggle palettes using the COLOR statement
  899.    ' (these modes do not allow the PALETTE statement)
  900.    IF VC.Scrn = 1 AND (BestMode = CGA OR BestMode = MCGA) THEN
  901.       COLOR , Toggle
  902.       Toggle = (Toggle + 1) MOD 2
  903.       EXIT SUB
  904.    END IF
  905.        
  906. END SUB
  907.  
  908. ' =========================== TorusSort ==============================
  909. ' Sorts the tiles of the Torus according to their Z axis (distance
  910. ' from the "front" of the screen). When the tiles are drawn, the
  911. ' farthest will be drawn first, and nearer tiles will overwrite them
  912. ' to give a three-dimensional effect.
  913. '
  914. ' To make sorting as fast as possible, the Quick Sort algorithm is
  915. ' used. Also, the array of tiles is not actually sorted. Instead a
  916. ' parallel array of tile indexes is sorted. This complicates things,
  917. ' but makes the sort much faster, since two-byte integers are swapped
  918. ' instead of 46-byte Tile variables.
  919. ' ======================================================================
  920. '
  921. SUB TorusSort (Low, High)
  922.    DIM Partition AS SINGLE
  923.  
  924.    IF Low < High THEN
  925.       ' If only one, compare and swap if necessary
  926.       ' The SUB procedure only stops recursing when it reaches this point
  927.       IF High - Low = 1 THEN
  928.          IF T(Index(Low)).z1 > T(Index(High)).z1 THEN
  929.             CountTiles High, Low
  930.             SWAP Index(Low), Index(High)
  931.          END IF
  932.       ELSE
  933.       ' If more than one, separate into two random groups
  934.          RandIndex = INT(RND * (High - Low + 1)) + Low
  935.          CountTiles High, Low
  936.          SWAP Index(High), Index(RandIndex%)
  937.          Partition = T(Index(High)).z1
  938.          ' Sort one group
  939.          DO
  940.             I = Low: J = High
  941.             ' Find the largest
  942.             DO WHILE (I < J) AND (T(Index(I)).z1 <= Partition)
  943.                I = I + 1
  944.             LOOP
  945.             ' Find the smallest
  946.             DO WHILE (J > I) AND (T(Index(J)).z1 >= Partition)
  947.                J = J - 1
  948.             LOOP
  949.             ' Swap them if necessary
  950.             IF I < J THEN
  951.                CountTiles High, Low
  952.                SWAP Index(I), Index(J)
  953.             END IF
  954.          LOOP WHILE I < J
  955.        
  956.          ' Now get the other group and recursively sort it
  957.          CountTiles High, Low
  958.          SWAP Index(I), Index(High)
  959.          IF (I - Low) < (High - I) THEN
  960.             TorusSort Low, I - 1
  961.             TorusSort I + 1, High
  962.          ELSE
  963.             TorusSort I + 1, High
  964.             TorusSort Low, I - 1
  965.          END IF
  966.       END IF
  967.    END IF
  968.    CountTiles -1, -1
  969. END SUB
  970.  
  971.