home *** CD-ROM | disk | FTP | other *** search
/ Brotikasten / BROTCD01.iso / texte / cbmhack9.txt < prev    next >
Text File  |  1995-08-20  |  205KB  |  4,828 lines

  1.                    ########
  2.              ##################
  3.          ######            ######
  4.       #####
  5.     #####  ####  ####      ##      #####   ####  ####  ####  ####  ####   #####
  6.   #####    ##    ##      ####    ##   ##   ##  ###     ##    ####  ##   ##   ##
  7.  #####    ########     ##  ##   ##        #####       ##    ## ## ##   ##
  8. #####    ##    ##    ########  ##   ##   ##  ###     ##    ##  ####   ##   ##
  9. #####  ####  ####  ####  ####  #####   ####  ####  ####  ####  ####   ######
  10. #####                                                                     ##
  11.  ######            ######           Issue #9
  12.    ##################            Jan. 24, 1995
  13.        ########
  14.  
  15. ---------------------------------------------------------------------(v1.1)---
  16. Editor's Notes
  17. by Craig Taylor
  18.  
  19. And *drum beat please* here's another issue of Commodore Hacking!! We've
  20. lasted longer and had more issues put out than some other magazines I won't
  21. discuss (*wondering where issue 39 of that mag is*).
  22.  
  23. Not many Commodore notes this time - things have gotten a little bit more
  24. montatenous(sp - it's late) on the Commodore front.
  25.  
  26. I was unable to get an article by Craig Bruce in time but I got the next
  27. best thing: An interview with him!! Users of his software may find this
  28. interview interesting in how he looks at programming.
  29.  
  30. Right now I'm entertaining the thought of dropping C= Hacking after I
  31. graduate which will be sometime around July 1st of this year. I'm interested
  32. in somebody who would "carry the reign" so to speak, and take over my job of
  33. nagging, bugging people etc :-) to write articles. I've got my system fairly
  34. automated in handling requests here - if that person has a VAX account then
  35. I could set them up with a mailserver, if a UNIX account then there's oodles
  36. of them floating on the net that could be used. _PLEASE_ write to me and
  37. lemme know if you're interested. I'm going to try to get one more issue of
  38. Commodore Hacking out before July 1st.
  39.  
  40. ===========================================================================
  41.  
  42. Please note that this issue and prior ones are available via anonymous FTP
  43. from ccosun.caltech.edu (amongunders) under /pub/cbm/hacking.mag and via a
  44. mailserver which documentation can be obtained by sending mail to
  45. "duck@pembvax1.pembroke.edu" with a subject line of "mailserver" and the
  46. lines of "help" and "catalog" in the body of the message.
  47.  
  48. ===========================================================================
  49. Legal Mumbo-Jumbo
  50.  
  51. Permission is granted to re-distribut3e this "net-magazine", in whole,
  52. freely for non-profit use. However, please contact individual authors for
  53. permission to publish or re-distribute articles seperately. A charge of no
  54. greater than 5 US dollars or equivlent may be charged for library service /
  55. diskettte costs for this "net-magazine".
  56.  
  57. ===========================================================================
  58. In This Issue:
  59.  
  60. Commodore Trivia Corner
  61.  
  62. This edition of Commodore Trivia Corner contains the answers to the July
  63. edition of trivia ($070 - $07F), the questions and answers for August ($080 -
  64. $08F), September ($090 - $09F), October ($0A0 - $0AF), November ($0B0 - $0BF),
  65. and the questions for the December edition ($0C0 - $0CF).  Enjoy them!
  66.  
  67. A Different Perspective, part II
  68.  
  69. This month George and Steve continue their series on 3D graphics on the C-64
  70. with a look at hidden faces and filled faces.  In addition to adding these
  71. features into last month's program some other improvements to the old program
  72. will be discussed, such as fast multiplication (around 24 cycles) and various
  73. bug fixes -- for instance, the program now works on older C-64's which
  74. initialize color RAM to the background color when the screen is cleared (sorry
  75. about that ;-).  A very primitive form of texture mapping is also included. As
  76. usual, full source and executables are included.  The native C64 files are in a
  77. Lynx archive, so you will obviously need Lynx to get at them -- check your
  78. favorite BBS or FTP site.
  79.  
  80. 2D Graphics Toolbox: Circles
  81.  
  82. To augment three-dimensional algorithms this series will focus on
  83. two-dimensional drawing algortihms.  Circles are the subject this
  84. time around (heh -- get it?), and a very fast algorithm for drawing
  85. them on your C64 is presented, with examples in assembly and BASIC7.0.
  86. How fast is fast?  How does 11 cycles per pixel without the use of
  87. tables grab ya?
  88.  
  89. AFLI=specs v1.0
  90.  
  91. In AFLI we can get 120 colors in theory (counted like this
  92. 16!/(2!*14!)=120). When we put red and blue hires pixels close to
  93. each other we get a vision of purple - thanks the television. This article
  94. details what AFLI is, how it's used and done.
  95.  
  96. Coding Tricks
  97.  
  98. Included are a series of postings to comp.sys.cbm about neat coding tricks (in
  99. machine language) that are interesting and useful.
  100.  
  101. C.S.Bruce Interview
  102.  
  103. An interview with the author of Zed, the ACE os and many other numerous
  104. utilities for the Commodore 64/128.
  105.  
  106. Aligning 1541 Drives
  107.  
  108. A discussion regarding Commodore 1541 disk drive alignment procedures, with
  109. suggestions.
  110. ===========================================================================
  111. Commodore Trivia Corner
  112. by Jim Brain (brain@mail.msen.com)
  113.  
  114. Well, it is a new year, and I am sending up a new collection of the
  115. Commodore rivia for all to enjoy.  If you haven't seen this already, the
  116. following is a collection of trivia questions that I post to various
  117. networks every month.  I have collected Trivia Edition #8-13 in this
  118. article.  As you may know, these questions form part of a contest in which
  119. the monthly winner gets a prize (Thanks to my various prize donators).
  120. The whole thing is mainly just for fun, so please enjoy.
  121.  
  122. As the new year rolls in, I am happy to report the following:
  123.  
  124. 1) As I have gained access to FIDONet, the trivia is now posted to both
  125.    the USENET newsgroup COMP.SYS.CBM on the Internet AND the FIDONet echo
  126.    CBM every month.
  127.  
  128. 2) A number of publications have started publishing the trivia, including
  129.    Commodore World, and a variety of club newsletters.
  130.  
  131. 3) I have moved into my new house (See new address at bottom).  While this
  132.    may not seem important, the extra room I now have means I can now bring
  133.    all of my old CBM machine to the new house and work with them.  Working
  134.    with them gives me fodder for more trivia.
  135.  
  136. As always, I welcome any questions (with answers), and encourage people
  137. to enter their responses to the trivia, now at #13.  Be sure you get the
  138. responses to me by January 12th at noon.
  139.  
  140.  
  141. Jim.
  142.  
  143.  
  144. The following article contains the answers to the July edition of trivia
  145. ($070 - $07F), the questions and answers for August ($080 - $08F), September
  146. ($090 - $09F), October ($0A0 - $0AF), November ($0B0 - $0BF), and the
  147. questions for the December edition ($0C0 - $0CF).  Enjoy them!
  148.  
  149.  
  150. Here are the answers to Commodore Trivia Edition #8 for July, 1994
  151.  
  152. Q $070) On a PET series computer, what visual power-on indication will tell
  153.         the user whether the computer has Revision 2 or Revision 3 ROMs?
  154.  
  155. A $070) Revision Level 2 ROMS (the ones with more bugs) power up with:
  156.         *** COMMODORE BASIC ***, with '*' in place of the more familiar
  157.         '#' character.
  158.  
  159. Q $071) The IEEE-488 interface is sometimes called the GPIB interface.
  160.         What does GPIB stand for?
  161.  
  162. A $071) General Purpose Interface Bus.  Another name is Hewlett Packard
  163.         Interface Bus (HPIB), since HP developed this standard for its
  164.         istrumentation device networking.
  165.  
  166. Q $072) Commodore manufactured at least two hard drives with IEEE-488
  167.         interfaces.  Can you name them?
  168.  
  169. A $072) The Commodore D9060 and D9090. From the cbmmodel.txt file:
  170.  
  171.         * CBM D9060  5 MB Hard Drive, DOS3.0, Off-White, IEEE-488.       GP
  172.         * CBM D9090  7.5 MB Hard Drive, DOS3.0, Off-White, IEEE-488.     GP
  173.  
  174.         The following model has been said to be in existence, though no one
  175.         has one on hand to prove it:
  176.  
  177.         * CBM D9065  7.5 MB Hard Drive
  178.  
  179.         And this model may never have made it past the prototype stage:
  180.  
  181.           CBM D9062  Dual D9065.
  182.  
  183. Q $073) Why didn't buyers like the original PET-64?
  184.  
  185. A $073) It looked just like a old-style C-64.  It had a "home" computer
  186.         look that the schools didn't care for.  They liked the "business"
  187.         look of the PET series, so Commodore put refurbished and new 64
  188.         motherboards in PET cases and sold them as PET 64s.  The repackaging
  189.         suited the schools.
  190.  
  191. Q $074) On a PET Revision 2 ROM, what was the largest single array size that
  192.         BASIC could handle?
  193.  
  194. A $074) An array can have a cumulative total of 256 elements.  For single
  195.         dimension arrays, that means D(0) to D(255), but a 2D array can only
  196.         go from DD(0,0) to DD(1,127) etc.  All types of arrays had this
  197.         limitation.
  198.  
  199. Q $075) On the stock 1541, data is transmitted one bit at a time.  How many
  200.         bits are transferred at a time on the Commodore 1551 disk drive?
  201.  
  202. A $075) 3 bits were transmitted at a time.  I assume that each byte had a
  203.         parity bit tacked on for error detection, so it would have taken
  204.         3 transfers to transmit a byte of information from the drives.
  205.  
  206. Q $076) On all Commodore floppy disk drives, how fast does the disk spin?
  207.  
  208. A $076) 300 RPM.
  209.  
  210. Q $077) Upon first reading the Commodore 1541 Error channel after turning
  211.         on the disk drive, what error number and text is returned?
  212.  
  213. A $077) 73, CBM DOS V2.6 1541, 0, 0
  214.  
  215. Q $078) What error number and text is returned on a 1551?
  216.  
  217. A $078) 73, CBM DOS V2.6TDISK, 0, 0   Notice that the new text JUST fits!
  218.  
  219. Q $079) Commodore printers are normally assigned to device #4, but they
  220.         can be also used as device #?
  221.  
  222. A $079) #5.  The Commodore 1525 has a switch to do this, but not all printers
  223.         have such a switch.
  224.  
  225. Q $07A) What microprocessor is used in the Commodore 1551 disk drive?
  226.  
  227. A $07A) the 6510T.  It is a slight variant on the 6510 microprocessor used
  228.         on the C64.  Some say it runs at 2 MHz, but the specs drives spec
  229.         sheet doesn't say.
  230.  
  231. Q $07B) When the VIC-20 was designed, the serial port throughput was roughly
  232.         equivalent to the throughput of the IEEE-488 bus?  Why isn't it
  233.         very fast in production VICs?
  234.  
  235. A $07B) Let's go back to question $04F:
  236.  
  237.         <begin insert>
  238.         Q $04F) What was the primary reason Commodore went to a serial bus
  239.                 with the introduction of the VIC-20?
  240.  
  241.         A $04F) Jim Butterfield supplied me with this one:
  242.  
  243.                 As you know, the first Commodore computers used the IEEE bus
  244.                 to connect to peripherals such as disk and printer.  I
  245.                 understand that these were available only from one source:
  246.                 Belden cables.  A couple of years into Commodore's computer
  247.                 career, Belden went out of stock on such cables (military
  248.                 contract? who knows?).  In any case, Commodore were in quite
  249.                 a fix:  they made computers and disk drives, but couldn't
  250.                 hook 'em together! So Tramiel issued the order:  "On our next
  251.                 computer, get off that bus.  Make it a cable anyone can
  252.                 manufacture".  And so, starting with the VIC-20 the serial
  253.                 bus was born.  It was intended to be just as fast as the
  254.                 IEEE-488 it replaced.
  255.         <end insert>
  256.  
  257.         And here is what Jim Butterfield followed up with:
  258.  
  259.         "Technically, the idea was sound:  the 6522 VIA chip has a "shift
  260.         register" circuit that, if tickled with the right signals (data and
  261.         clock) will cheerfully collect 8 bits of data without any help from
  262.         the CPU.  At that time, it would signal that it had a byte to be
  263.         collected, and the processor would do so, using an automatic
  264.         handshake built into the 6522 to trigger the next incoming byte.
  265.         Things worked in a similar way outgoing from the computer, too.
  266.         We early PET/CBM freaks knew, from playing music, that there was
  267.         something wrong with the 6522's shift register:  it interfered with
  268.         other functions.  The rule was:  turn off the music before you start
  269.         the tape!  (The shift register was a popular sound generator).  But
  270.         the Commodore engineers, who only made the chip, didn't know this.
  271.         Until they got into final checkout of the VIC-20.
  272.  
  273.         By this time, the VIC-20 board was in manufacture.  A new chip could
  274.         be designed in a few months (yes, the silicon guys had application
  275.         notes about the problem, long since), but it was TOO LATE!
  276.  
  277.         A major software rewrite had to take place that changed the VIC-20
  278.         into a "bit-catcher" rather than a "character-catcher".  It called for
  279.         eight times as much work on the part of the CPU; and unlike the shift
  280.         register plan, there was no timing/handshake slack time.  The whole
  281.         thing slowed down by a factor of approximately 5 to 6.
  282.  
  283.         When the 64 came out, the problem VIA 6522 chip had been
  284.         replaced by the CIA 6526.  This did not have the shift register
  285.         problem which had caused trouble on the VIC-20, and at that time it
  286.         would have been possible to restore plan 1, a fast serial bus.  Note
  287.         that this would have called for a redesign of the 1540 disk drive,
  288.         which also used a VIA.  As best I can estimate - and an article in
  289.         the IEEE Spectrum magazine supports this - the matter was discussed
  290.         within Commodore, and it was decided that VIC-20 compatibility was
  291.         more important than disk speed.  Perhaps the prospect of a 1541
  292.         redesign was an important part of the decision, since current
  293.         inventories needed to be taken into account.  But to keep the
  294.         Commodore 64 as a "bit-banger", a new problem arose.
  295.  
  296.         The higher-resolution screen of the 64 (as compared to the VIC-20)
  297.         could not be supported without stopping the CPU every once in a while.
  298.         To be exact:  Every 8 screen raster lines (each line of text), the CPU
  299.         had to be put into a WAIT condition for 42 microseconds, so as to
  300.         allow the next line of screen text and color nybbles to be swept into
  301.         the chip.(More time would be needed if sprites were being used).
  302.         But the bits were coming in on the serial bus faster than that:
  303.         a bit would come in about every 20 microseconds!  So the poor CPU,
  304.         frozen for longer than that, would miss some serial bits completely!
  305.         Commodore's solution was to slow down the serial bus even more.
  306.         That's why the VIC-20 has a faster serial bus than the 64, even though
  307.         the 64 was capable, technically, of running many times faster.
  308.  
  309.         Fast disk finally came into its own with the Commodore 128."
  310.  
  311.                                  --Jim
  312.  
  313. Q $07C) On Commodore computers, how much RAM is set aside as a tape buffer?
  314.  
  315. A $07C) 192 bytes is used as a tape buffer.  Blocks of data on tape are 192
  316.         bytes long.
  317.  
  318. Q $07D) On Commodore computers, most every peripheral has a device number.
  319.         What is the device number of the screen?
  320.  
  321. A $07D) #3
  322.  
  323. Q $07E) What is the device number of the keyboard?
  324.  
  325. A $07E) #0
  326.  
  327. Q $07F) Commodore computers use 2's-complement notation to represent integers.
  328.         What is the 2's-complement hex representation of the signle byte -1?
  329.  
  330. A $07F) (This was not a Commodore specific question)  Commodore computers
  331.         use this notation to represent integer quantities.  In 2's complement
  332.         notation, a -1 looks like 11111111(binary) or $FF(hex).
  333.  
  334.  
  335. Here are the answers to Commodore Trivia Edition #9 for August, 1994
  336.  
  337. Q $080) During the days of the Commodore 64 and the VIC-20, Commodore
  338.         produced at least two Commodore magazines.  What were their names?
  339.  
  340. A $080) The magazines were originally called "Commodore Microcomputers" and
  341.         "Power/Play: Commodore Home Computing". They never did seem to nail
  342.         down the name of the latter as I see "Power/Play" and
  343.         "Commodore: Power/Play" used as the original names as well. Anyway,
  344.         Commodore Microcomputers started its life in 1979, whereas
  345.         "Power/Play" started in 1981.  Both magazines were published until
  346.         around 1987, when they were merged to form "Commodore Magazine".
  347.         Then, around 1990, the magazine was sold to IDG Communications and
  348.         was merged into RUN.  RUN was continued for a while, but was finally
  349.         pulled out of circulation.  Creative Micro Designs purchased the
  350.         rights to the magazine, and now Commodore World is being produced by
  351.         CMD.  I am not sure how strong (if any) a link there is between
  352.         RUN and CW, but some of the same authors write for the new
  353.         publication.  Just for added info, here are the ISSN numbers:
  354.  
  355.         Commodore Microcomputers (Commodore Magazine)   0744-8724
  356.         Power/Play:Commodore Home Computing             0739-8018
  357.         RUN (Commodore/RUN)                             0741-4285
  358.  
  359.         "The Transactor" is also a correct answer, and info on it is below.
  360.  
  361. Q $081) Back in the PET heyday, another magazine was produced by Commodore
  362.         Canada.  This magazine was later sold and showed up as a hardware
  363.         journal.  Name the magazine.
  364.  
  365. A $081) The infamous "Tarnsactor".  One of the noted C64 hardware-hacking
  366.         magazines, it was originally published by Commodore Canada, before
  367.         being sold to an individual named Mr. Hilden.  Its ISSN number is
  368.         0838-0163.  As far as I can tell, this magazine, died many deaths,
  369.         but ceased to exist in 1989-90.  Its first issue is dated April 30,
  370.         1978.
  371.  
  372. Q $082) The Commodore 128 has a VIC-II compatible chip inside it.  Can this
  373.         chips be switched for a VIC-II from a Commodore 64?
  374.  
  375. A $082) No!  The newer 128 compatible chip (VIC-IIe) has 8 extra pins to
  376.         perform timing functions specific for the 128.  In addition, some of
  377.         the registers have extra functions.  However, a suitable card
  378.         to make it compatible can be made.
  379.  
  380. Q $083) What does the video encoding standard PAL expand to?
  381.  
  382. A $083) Phase Alternating Line is the answer I was looking for, which
  383.         describes the video encoding used in Europe, but Programmable Array
  384.         Logic is also correct, which describes the family of chips used as
  385.         "glue" logic for the C64 I/O and processing chips.
  386.  
  387. Q $084) How many buttons were present on the earliest of Commodore tape decks?
  388.  
  389. A $084) 5: Play, Rewind, Fast-Forward, Record, and Stop/Eject.  Later models
  390.         separated the stop and eject functions into two buttons.
  391.  
  392. Q $085) Earlier SID chips had a distinctive "clicking" sound that some demo
  393.         coders used to an advantage.  Commodore subsequently removed the
  394.         click, and then later reintroduced it.  When does the telltale click
  395.         occur?
  396.  
  397. A $085) When you change the volume of a voice.  The voice need not be
  398.         outputting anything.
  399.  
  400. Q $086) What does CP/M stand for?
  401.  
  402. A $086) Take your pick:
  403.  
  404.         Control Program/Monitor
  405.         Control Program for Microprocessors
  406.         Control Program for Microcomputers.
  407.  
  408.         The last one is considered by many to be most correct.
  409.  
  410. Q $087) What is the highest line number allowed for a program line in
  411.         Commodore BASIC V2?
  412.  
  413. A $087) Normally, the user cannot enter a line number higher than 63999.
  414.         If you want to be tricky, however, the numbers can be made to go up
  415.         to 65535.
  416.  
  417. Q $088) What symbol, clearly printed on the front of a key on the Commodore
  418.         VIC, 64, and 128 keyboard, is not available when the lower case
  419.         character set is switched in?
  420.  
  421. A $088) The PI symbol.  It is [SHFT-UPARROW] in uppercase mode, but becomes
  422.         a checkerboard-like character when in lower-case mode.  Unlike the
  423.         graphics characters printed on the fronts of the keys, this one is
  424.         positioned in the middle of the keycap, and should probably be
  425.         accessible in both character sets.
  426.  
  427. Q $089) How do you get the "checkmark" character ?
  428.  
  429. A $089) In lowercase mode, type a shift-@
  430.  
  431. Q $08A) On the PET computers, what memory location holds the Kernal ROM
  432.         version?
  433.  
  434. A $08A) It is different from the 64/128.  It is 50003.  0 here indicates old
  435.         ROMs, while 1 indicates new ROMs.
  436.  
  437. Q $08B) The Commodore computers have 2 interrupts, called IRQ and NMI.
  438.         What does IRQ stand for?
  439.  
  440. A $08B) Interrupt ReQuest.  This interrupt is used for things that should
  441.         usually be allowed to interrupt the processor.  This interrupt can
  442.         be masked off by the SEI instruction.
  443.  
  444. Q $08C) What does NMI stand for?
  445.  
  446. A $08C) Non-Maskable Interrupt.  Unlike the IRQ, this interrupt cannot be
  447.         masked by an instruction.  However, some tricks can be used to
  448.         mask it.
  449.  
  450. Q $08D) The 6502 line of microprocessors has a number of flags that can be
  451.         used to test for certain conditions.  One of then is the N flag.
  452.         What does it stand for?
  453.  
  454. A $08D) 'N' stands for Negative.  On instructions that change this flag, it
  455.         is set to be equal to bit 7 of the result of the instruction.
  456.  
  457. Q $08E) How about the D flag?
  458.  
  459. A $08E) It stands for decimal mode.  This mode causes certain instructions
  460.         to treat a byte as 2 4 bit BCD-coded nybbles.
  461.  
  462. Q $08F) The shorthand for the BASIC keyword PRINT is '?'.  What is the
  463.         shorthand equivalent for PRINT#?
  464.  
  465. A $08F) pR is the way to abbreviate PRINT#.  Note that ?# will fail.
  466.  
  467.  
  468. Here are the answers to Commodore Trivia Edition #10 for September, 1994
  469.  
  470. Q $090) The 6502 has a rich history.  It is modeled after another 8-bit
  471.         microprocessor.  Name the processor.
  472.  
  473. A $090) The 65XX series of processors was modeled after the Motorola 6800.
  474.         Motorola hampered the design groups' efforts to pursue product
  475.         developments using the 6800.  A core group of 8 designers left Motorola
  476.         and went to MOS Technologies, which was the largest producer of
  477.         calculator chips at the time.  MOS decided it was time to go into
  478.         the CPU business.
  479.  
  480. Q $091) The 6502 has a older brother that was never produced.  Name its
  481.         number designation and why it was not produced.
  482.  
  483. A $091) The older brother to the 6502 was the 6501.  The 6501 was
  484.         pin-compatible with the 6800, which prompted a suit by Motorola.
  485.         Eventually, MOS reached an agreement where they scrapped the 6501
  486.         marketing, but were free to market the 6502.
  487.  
  488. Q $092) How many different opcodes are considered valid and "legal" on the
  489.         MOS NMOS 6502 line?
  490.  
  491. A $092) 151 opcodes are documented in the NMOS 6502 data book.  The remaining
  492.         105 opcodes were not implemented, and exist as "don't care" states
  493.         in the opcode matrix.  That means that some seemingly invalid
  494.         opcodes will actually perform pieces of two or more valid opcodes.
  495.         Newer CPU systems trap all non-implemented opcode usages, but not
  496.         the 6502.
  497.  
  498. Q $093) Every instruction takes at least __ cycles to complete.  Fill in
  499.         the missing number.
  500.  
  501. A $093) 2.  The architecture assumes that each opcode has two bytes in it and
  502.         one byte can be fetched per cycle.  For instructions that use only
  503.         1 byte, the extra fetched byte (actually the next opcode), is thrown
  504.         away.
  505.  
  506. Q $094) Which instructions take more time than necessary as a result of the
  507.         answer to Q $093?
  508.  
  509. A $094) Although this is a subjective answer, One could nominate NOP on the
  510.         basis that NOP is generally believed to waste one execution cycle on
  511.         a particular processor, namely one cycle on the 65XX line.  However,
  512.         one can argue that NOP simply means no operation, and has no ties to
  513.         length of execution.  You be the judge.
  514.  
  515.         All other instructions must take at least two cycles: one for opcode
  516.         fetch, one for operation.
  517.  
  518. Q $095) What did MOS Technologies manufacture befor introducing the 650X line
  519.         of microprocessors?
  520.  
  521. A $095) As stated above, it was calculator chips.
  522.  
  523. Q $096) Three companies manufactured the 6502 under a cross-licensing
  524.         agreement.  Name them.
  525.  
  526. A $096) Rockwell, MOS Technologies, and Synertek.
  527.  
  528. Q $097) In NTSC-land, how fast does the 1MHz 6510 in the C64 actually run?
  529.  
  530. A $097) 1.022727143 MHz.  It is derived by taking the main clock frequency
  531.         (14.31818MHz) and diving it by 14.
  532.  
  533. Q $098) What about in PAL-land?
  534.  
  535. A $098) 985.248449 kHz.  It is derived by taking the main clock frequency
  536.         (17.734472MHz) and dividing it by 18.  Thus the PAL 64 actually runs
  537.         slower than the NTSC one.
  538.  
  539. Q $099) Data is latched into the 650X microprocessor on the (rising/falling)
  540.         edge?
  541.  
  542. A $099) Data is latched in to the 65XX on the falling edge of Phi0 (Phi1).
  543.         The timing diagram in some books (64 PRG is one) is incorrect.
  544.  
  545. Q $09A) Through the years, the 650X line has changed family numbers, yet
  546.         the part has not been changed.  (A family number is the upper 2
  547.         digits in this case)  Name the other family numbers used by MOS to
  548.         denote the 650X line.
  549.  
  550. A $09A) the 75XX line used in the 264 series (Plus/4 and C16), and the 85XX
  551.         series used in the C64C and C128 series.
  552.  
  553. Q $09B) Consider the following code:
  554.  
  555.         ldx #10
  556.         lda $ff,x
  557.  
  558.         what location does the accumulator get loaded with?
  559.  
  560. A $09B) The answer is location $ff+10 mod 256 = $09.
  561.         The answer involves explaining a (mis)features of the NMOS 65XX CPU
  562.         line.  The above code instructs the 65XX CPU to use zero-page
  563.         addressing mode to load the accumulator.  In zero-page addressing, the
  564.         address need only be one byte wide ($ff in this case), because the
  565.         high byte is considered to be $00.  Now, as humans, we would expect
  566.         the CPU would add 10 to 255 ($ff), giving 265 ($109) as the address
  567.         to load the accumulator from.  However, the CPU designers decided
  568.         that zero-page addressing means that the high byte will be $00 all the
  569.         time, no exceptions.  If a situation like the above occurs, the
  570.         low byte of the addition will be used as the low byte of the address
  571.         (9 in this case), but the high-byte will be ZERO.  All zero page
  572.         addressing modes work this way.  Note that the CMOS versions of the
  573.         6502 do perform the high byte "fix-up", so this behavior is only seen
  574.         on the NMOS parts.
  575.  
  576. Q $09C) What about the following?
  577.  
  578.           ldx #10
  579.           lda ($ff),x
  580.  
  581. A $09C) This was a trick.  The code is trying to use INDIRECT INDEXED indexing
  582.         mode using the x register, but that addressing mode can only be used
  583.         with the y register.  If the code is changed to the following, legal
  584.         code:
  585.  
  586.           ldx #10
  587.           lda ($ff),y
  588.  
  589.         Then, the above discussion for zero-page addressing holds true here
  590.         as well.  The effective address would have been (hi:lo) $100:$0ff, but
  591.         is instead (hi:lo) $000:$0ff.  The simple rule is:  zero page means
  592.         exactly that.  There is no way to address outside of zero-page with
  593.         zero-page addressing.
  594.  
  595. Q $09D) How many CPU clock signal lines does the 650X require to run?
  596.  
  597. A $09D) 1.  The 6501 used two, as the 6800 used two, but the 6502 and
  598.         successors only required Phi0 (Phi1).  Phi2 was generated on the CPU.
  599.  
  600. Q $09E) Where does the 650X line fetch its first byte from after reset?
  601.  
  602. A $09E) $fffc.  The address formed by reading $fffd and $fffc is stuffed into
  603.         the IP, and the code is read starting there.  $fffc is read first,
  604.         since the 65XX line stores addresses in low byte, high byte format.
  605.  
  606. Q $09F) One of the original designers on the NMOS 6502 CPU now heads up
  607.         Western Design Center in Arizona, and makes the 65C02 and 65C816
  608.         CPU chips.  Name him.  Hint: it is not Chuck Peddle!
  609.  
  610. A $09F) Bill Mensch.  He hand-designed these newer parts in the 65XX line
  611.         in the same manner he and Chuck Peddle and others hand-designed the
  612.         6501 and 6502.
  613.  
  614.  
  615. Here are the answers to Commodore Trivia Edition #11 for October, 1994
  616.  
  617. Q $0A0) In the mid 1980's, Commodore introduced RAM Expansion Units for the
  618.         Commodore 64, 64C, 128, and 128D.  There were three of them.  Give
  619.         their model numbers, and what was different among them.
  620.  
  621. A $0A0) The 1700 (128kB), the 1764 (256kB), and the 1750 (512kB).  The
  622.         1700 and the 1750 were marketed for the 128, while the 1764 was
  623.         marketed from the 64 line.
  624.  
  625. Q $0A1) Some of the CIA integrated circuits used on the C64 and C128
  626.         computers have a hardware defect.  What is the result of this
  627.         defect, and when does it occur? (May be more than one, but I need
  628.         only one)
  629.  
  630. A $0A1) The only one I have documented in front of me is the timer B
  631.         interrupt bug, which is explained in the "Toward 2400" article
  632.         by George Hug in Transactor 9.3. (1)  However, I had many people
  633.         relate other bugs (2 and 3), which I haven't been able to test, so I
  634.         add them as possibilities. (I encourage readers to confirm/deny the
  635.         latter 2.)
  636.  
  637.         1) If timer B of the 6526 CIA times out at about the same time as a
  638.            read of the interrupt register, the timer B flag may not be set at
  639.            all, and no interrupt will occur if timer B interrupts were
  640.            turned on.
  641.  
  642.         2) When the hour on the TOD clock is 12, the AM/PM must be reversed
  643.            from its normal setting to set/reset the AM/PM flag.
  644.  
  645.         3) The TOD clock sometimes generates double interrupts for alarm
  646.            trigger.
  647.  
  648.  
  649. Q $0A2) Name the Commodore machine(s) on which a Intel 8088 was an OPTIONAL
  650.         coprocessor.  (Hint, not the IBM clones)
  651.  
  652. A $0A2) I was looking for the B series computers, which contains the B
  653.         computers (B128, B256), as well as the 600 series and the 700
  654.         series.  These computers could be fitted with an optional 8088
  655.         processor on a separate card.  However, another correct answer is
  656.         the Amiga, which can have a 8088 attached via an expansion card or a
  657.         SideCar(tm) unit.
  658.  
  659. Q $0A3) On Commodore computers beside the Plus/4 series, there are three
  660.         frequencies used to record the data on the tape.  Name the
  661.         frequencies used.
  662.  
  663. A $0A3) 1953.125Hz, 2840.909Hz, and 1488.095Hz.  These correspond to
  664.         waveforms with periods: 512us, 352us, and 672us, respectively.
  665.  
  666. Q $0A4) Commodore Plus/4 series computers can not read any cassettes
  667.         recorded on other Commodore computers.  Why?  (Hint: It has
  668.         nothing to do with the nonstandard connecotr on the Plus/4)
  669.  
  670. A $0A4) The tones recorded on the Plus/4-C16 are exactly one-half the
  671.         frequencies shown above.  This suggests to many that the Plus/4
  672.         and C16 were supposed to run at twice its present frequency,
  673.         but were downgraded at the last-minute, and the code to generate
  674.         the tones was not updated to reflect the change.  This is just
  675.         heresay, so you decide for yourself.
  676.  
  677. Q $0A5) During power-up, the Commodore 64 checks to see if it running
  678.         in PAL-land or NTSC-land.  How does it determine its location?
  679.  
  680. A $0A5) It sets the raster compare interrupt to go off at scan line 311.
  681.         If the interrupt occurs, we are on a PAL system, since NTSC will
  682.         never get to line 311 (NTSC only has 262.5 lines per frame, every
  683.         other frame shifted down a bit to create 525 lines).
  684.  
  685. Q $0A6) What is the 65XX ML opcode for BRK?
  686.  
  687. A $0A6) $00, or 00
  688.  
  689. Q $0A7) On the 65XX CPU, what gets pushed onto the stack when an interrupt
  690.         occurs?
  691.  
  692. A $0A7) The program counter gets saved high byte first, then the processor
  693.         status flags get saved.
  694.  
  695. Q $0A8) Speaking of the stack, where is the stack located in the 65XX address
  696.         map?
  697.  
  698. A $0A8) $0100 to $01FF
  699.  
  700. Q $0A9) On the 65XX CPU line, it is possible to set and clear a number of
  701.         processor status flags.  Examples include SEC and CLC to set and
  702.         clear the carry flag.  What flag has a clear opcode, but no set
  703.         opcode?
  704.  
  705. A $0A9) The overflow flag: V.  However, the V flag can be set via an external
  706.         pin on some members of the 65XX line.  The 1541 uses this as an
  707.         ingenious synchronization tool.
  708.  
  709. Q $0AA) When saving a text file to tape, the computer records 192 bytes of
  710.         data, an inter-record gap, and then the same 192 bytes of data
  711.         again.  How wide is this inter-record gap, and why is it there?
  712.  
  713. A $0AA) Some terminology:  "inter" means "between".  Most everyone knows
  714.         that a tape block is recorded twice on the tape, but Commodore
  715.         considers the two copies and the gap between them a single
  716.         "record".  Thus, this question is referring to the gap in between
  717.         two dissimilar records.  With that in mind,
  718.         the interrecord gap is nominally 2 seconds long, (or 223.2 byte
  719.         lengths, although the gap contains no data).  It is there to allow
  720.         the tape motors to get up to speed before the next data comes under
  721.         the read/write head.  The tape motors may need to stop between
  722.         records if the program is not requesting any more data from the
  723.         tape data file at this time.  If the program subsequently asks
  724.         for data from the tape, the drive must get up to speed before the
  725.         read can occur.  Note: on the first version of PET BASIC, the
  726.         gap was too small, so programmers had problems retrieving data
  727.         files.
  728.  
  729.         For completeness, the "intra-record" gap (The one between the two
  730.         copies of the data) consists of 50+ short pulses, each of which is
  731.         352us in length, giving a timing of .0176s+.  This time was used to
  732.         copy important data to safe locations, reset pointers, and do error
  733.         logging.  The entire "record" is recorded in 5.7 seconds.
  734.  
  735. Q $0AB) On an unexpanded VIC-20, where does the screen memory start?
  736.  
  737. A $0AB) $1e00, or 7680
  738.  
  739. Q $0AC) In Commodore BASIC, what is the abbreviated form of the "Load"
  740.         command?
  741.  
  742. A $0AC) lO (L SHIFT-O)
  743.  
  744. Q $0AD) In Commodore BASIC, what is the abbreviated form of the "List"
  745.         command?
  746.  
  747. A $0AD) lI (L SHIFT-I)
  748.  
  749. Q $0AE) On the Commodore 64, there is section of 4 kilobytes of RAM that
  750.         cannot be used for BASIC programs.  It is the favorite hiding
  751.         places for many ML programs, however.  What is its address in
  752.         memory?
  753.  
  754. A $0AE) $c000, or 49152
  755.  
  756. Q $0AF) What is stored at locations $A004-$A00B, and why is it strange?
  757.  
  758. A $0AF) The text "CBMBASIC" is stored there.  It is strange because this
  759.         text is not referenced by any routine.  It can also be called
  760.         strange because the code is Microsoft's. Doesn't it make you wonder?
  761.  
  762.  
  763. Here are the answers to Commodore Trivia Edition #12 for November, 1994
  764.  
  765. Q $0B0) What will happen if you type ?""+-0 into the CBM BASIC interpreter
  766.         on the PET series, the 64 series, or the 128 series?
  767.  
  768. A $0B0) The BASIC interpreter has a bug in it that shows up while interpreting
  769.         the above statement.  The interpreter leaves two bytes on the CPU
  770.         stack prior to returning from a subroutines call.  At least on the
  771.         C64, the two bytes are both zeros.  Since subroutines put the return
  772.         address on the stack, the return retrieves the two bytes left on the
  773.         stack and attempts to se that as the return address.  So, depending on
  774.         what code it executes after the return, it can do a number of things.
  775.  
  776.         Most of the time after the bug occurs, the interpreter limps along
  777.         for a while until it hits a BRK instruction, $00.  Then, that
  778.         instruction causes the system to execute an interrupt.  On the C64,
  779.         the system vectors through $316-$317 (BRK vector) and does a warm
  780.         start.  On the C128 and PETs with Monitors, the system dumps into the
  781.         internal machine language monitor.  If the machine under use did not
  782.         do something with the BRK vector, the machine will hang.
  783.  
  784.         Now, note that the above is not the only result.  Since the
  785.         interpreter is executing code from the wrong location, any result
  786.         from no effect to hung machine is possible.
  787.  
  788.         Note that this is NOT normal behavior.  The system should report an
  789.         error while interpreting the above statement.
  790.  
  791. Q $0B1) In the first CBM 64 units, what color was the screen color RAM
  792.         changed to when you cleared the screen?
  793.  
  794. A $0B1) The screen color RAM was changed to value 1 when the screen was
  795.         cleared.  Thus, when a byte was poked into screen RAM, the resulting
  796.         character was white on the screen.  The white contrasted nicely
  797.         with the normal blue background.
  798.  
  799. Q $0B2) Why was it changed in later versions of the 64?
  800.  
  801. A $0B2) Commodore found that this practice sometimes caused "light flashes"
  802.         during screen scrolls.  I was going to leave this for another time,
  803.         but ... The change was to make the color RAM equal to background
  804.         color register #0.  Well, this got rid of the "light flashes", but
  805.         then poking values to screen RAM  caused invisible characters, since
  806.         the foreground color of the character was the same as the background
  807.         color of the screen.
  808.  
  809.         Well, this broke a number of older programs that did not
  810.         properly initialize the color RAM. Also, Commodore fixed the problem
  811.         with the VIC-II that had caused these "light flashes" So, Commodore
  812.         changed the KERNAL a third time.  Since the above change caused
  813.         invisible characters, Commodore made a third revision that changed
  814.         the color RAM to the value in location 646 (the current cursor
  815.         foreground color).
  816.  
  817. Q $0B3) What is "special" about the text that displays the "illegal quantity
  818.         error" in CBM BASIC?
  819.  
  820. A $0B3) The text is actually "?ILLEGAL QUANTITY  ERROR".  Notice the two
  821.         spaces between "QUANTITY" and "ERROR".  John West supplies the
  822.         expanantion:
  823.  
  824.         "The vector at $0300 points to a routine at $A43A, which is the
  825.         general error message printing routine.  Load .X with the number of
  826.         the error, and it prints it.  it looks up the address of the error
  827.         text from a table, then prints the text, which does not have any
  828.         trailing spaces.  It then prints '  ERROR', with *2* spaces.  It
  829.         does this for all errors."
  830.  
  831.         Historically, this effect is caused by the VIC-20, which only had 22
  832.         columns.  When the VIC-20 BASIC was being ported from the PET BASIC
  833.         code, someone noticed that the some of the error strings would
  834.         span two VIC-20 lines.  So, the BASIC error messages were changed
  835.         a little, so that they all printed neatly on two lines:  The PET
  836.         error string:
  837.            ?ILLEGAL QUANTITY ERROR (one space) became:
  838.            ?ILLEGAL QUANTITY
  839.             ERROR                  (carriage return plus one space).
  840.         When the C64 BASIC was being ported from the VIC-20, the carriage
  841.         return was replaced with a space character.
  842.  
  843.         I admit this caught me by surprise.  I have used Commodore computers
  844.         for years, and never noticed that "?SYNTAX  ERROR" had 2 spaces in it.
  845.  
  846. Q $0B4) On what Commodore machine was the operating system OS/9 available?
  847.  
  848. A $0B4) Since OS/9 was a real-time operating system for the 6809
  849.         microprocessor, it was available on only one Commodore machine, which
  850.         had two different names:  The Commodore SuperPET.  The machine was
  851.         sold as the "MMF (Micro MainFrame) 9000 in Germany, and its model
  852.         number was SP9000.
  853.  
  854. Q $0B5) Which Commodore machine(s) does not have a user port?
  855.  
  856. A $0B5) There were a number of answers to this question, and there may be
  857.         more:
  858.  
  859.         The Commodore C16.  Commodore decided to cut out telecommunications,
  860.         and thus designed the user port out of the computer, as the modem is
  861.         the only use Commodore ever made of the user port.  This also
  862.         includes the C116, a version of the C16 with a chicklet keyboard.
  863.  
  864.         The Commodore Ultimax/MAX machine.  This was the ill-fated game
  865.         console produced in the early 80s.  It was basically a stripped down
  866.         Commodore 64.
  867.  
  868.         The 64 GS (Game System).  This machine was another flop produced
  869.         in the late 80s.
  870.  
  871. Q $0B6) How many pins are there in a Commodore Serial Connector?
  872.  
  873. A $0B6) 6.
  874.  
  875. Q $0B7) There are 13 addressing modes available on the 6502. Name them.
  876.  
  877. A $0B7) No# Name                 Description
  878.         --- ------------         -----------
  879.         01) accumulator          asl a
  880.         02) immediate            lda #$00
  881.         03) zero page            lda $00
  882.         04) zero page,X          lda $00,X
  883.         05) zero page,Y          lda $00,Y
  884.         06) absolute             lda $1000
  885.         07) absolute,X           lda $1000,X
  886.         08) absolute,Y           lda $1000,Y
  887.         09) implied              clc
  888.         10) relative             bne
  889.         11) (indirect,X)         lda ($00,X)
  890.         12) (indirect),Y         lda ($00),Y
  891.         13) (absolute indirect)  jmp ($1000)
  892.  
  893. Q $0B8) If you were to put one large sequential file onto an 8050 disk drive,
  894.         how big could that file be?
  895.  
  896. A $0B8) According to the 8050 User Manual, a sequential file could be
  897.         521208 bytes in size.
  898.  
  899. Q $0B9) How many characters can be present in a standard Commodore DOS
  900.         filename?
  901.  
  902. A $0B9) 16 characters.
  903.  
  904. Q $0BA) How many pins does a 6502 IC have on it?
  905.  
  906. A $0BA) 40 pins.
  907.  
  908. Q $0BB) How many pins does the standard IEEE-488 connector have on it?
  909.  
  910. A $0BB) 24 pins.
  911.  
  912. Q $0BC) On the IEEE-488 bus, what does the acronym for pin 7, NRFD, stand for?
  913.  
  914. A $0BC) Not Ready For Data.
  915.  
  916. Q $0BD) On the NMOS 6502, what is the ML opcode for SED, and what does this
  917.         opcode do?
  918.  
  919. A $0BD) $f8, SEt Decimal mode.  Sets the D flag in the status flags byte.
  920.         Although used rarely, this opcode switches on Binary Coded Decimal
  921.         mode.  In BCD mode, the byte $10 is treated as 10, not 16.  The add
  922.         and subtract instructions are the only legal ones affected by this
  923.         mode, although some undocumented/illegal opcodes are also affected.
  924.         For example, in this mode, adding the byte $15 (21) to the byte $25
  925.         (37) yields $40 (64) not $3a (58).  emember that, in this mode,
  926.         $40 = 40, not 64.
  927.  
  928. Q $0BE) Assuming a PET computer and a non-PET computer have access to a
  929.         common disk drive or tape drive, there are two ways to load a PET
  930.         BASIC program on the non PET CBM computer. Name them.
  931.  
  932. A $0BE) Most differing series of Commodore computers had different places
  933.         for the start of BASIC programs.  For instance, on the C64, $0801
  934.         (2049) is the start of BASIC memory, but most PET computers start
  935.         BASIC memory at $0401 (1025).  This wouldn't matter, except that
  936.         BASIC programs are stored on tape and disk with the start address,
  937.         and the line links in a BASIC program have absolute addresses in them.
  938.         To fix these problems, the Commodore VIC-20 and newer computers came
  939.         out with a "relocatable load".  So, here are the two choices:
  940.  
  941.         1)  Save the program on the PET like so: save "name",X (X is device).
  942.             Then, you could load the program into the non-PET machine
  943.             by using a relocatable load: load "name",X.  This would load the
  944.             program in at start of BASIC memory and refigure the line links.
  945.  
  946.         2)  Redefine start of BASIC memory on non-PET machine.  A couple
  947.             of pokes to relevant BASIC pointers, and the start of BASIC
  948.             was moved. Then, load the program non-relocatable.
  949.  
  950.         Now, from the above discussion, it looks like option 1 is the
  951.         simplest route.  Well, it would be, exept for one small detail:
  952.         Earlier PET computers saved the BASIC program from $0400, not
  953.         $0401 as is expected.  The effect:  loading relocatable on a non-PET
  954.         would have a zero byte as the first byte of the program.  The quick
  955.         fix:  change BASIC pointer to itself-1, load PET program, reset
  956.         BASIC pointer.  Commodore didn't make it easy!
  957.  
  958. Q $0BF) Only one of the ways detailed in $0BE works the other way around.
  959.         Which one?
  960.  
  961. A $0BF) Since the earlier PET computers did not have a "relocatable load",
  962.         the only way to load a program from, say, a C64 into an 2001 was to
  963.         use option #2 above and move the start of BASIC memory to $0801
  964.         (2049).
  965.  
  966.  
  967. Commodore Trivia Edition #13
  968.  
  969. Q $0C0) The early 1541 drives used a mechanism developed by ______.  Name
  970.         the company.
  971.  
  972. Q $0C1) On later models, Commodore subsequently changed manufacturers
  973.         for the 1541 drive mechanism.  Name the new manufacturer.
  974.  
  975. Q $0C2) What is the most obvious difference(s).  (Only one difference is
  976.         necessary)
  977.  
  978. Q $0C3) On Commodore BASIC V2.0, what answer does the following give:
  979.         PRINT (SQR(9)=3)
  980.  
  981. Q $0C4) In Commodore BASIC (Any version) what does B equal after the following
  982.         runs: C=0:B=C=0
  983.  
  984. Q $0C5) The first PET cassette decks were actually _______ brand cassette
  985.         players, modified for the PET computers.  Name the comapny.
  986.  
  987. Q $0C6) In Commodore BASIC (Any version), what happens if the following
  988.         program is run:
  989.  
  990.         10 J=0
  991.         20 IF J=0 GO TO 40
  992.         30 PRINT "J<>0"
  993.         40 PRINT "J=0"
  994.  
  995. Q $0C7) In question $068, we learned how Jack Tramiel first happened upon the
  996.         name "COMMODORE".  According to the story, though, in what country
  997.         was he in when he first saw it?
  998.  
  999. Q $0C8) On the Commodore user port connector, how many edge contacts are
  1000.         there?
  1001.  
  1002. Q $0C9) On most Commodore computers, a logical BASIC line can contain up to
  1003.         80 characters.  On what Commodore computer(s) is this not true?
  1004.  
  1005. Q $0CA) If a file is saved to a Commodore Disk Drive with the following
  1006.         characters: chr$(65);chr$(160);chr$(66), what will the directory
  1007.         entry look like?
  1008.  
  1009. Q $0CB) What is the maximum length (in characters) of a CBM datasette
  1010.         filename?
  1011.  
  1012. Q $0CC) How many keys are on a stock Commodore 64 keyboard?
  1013.  
  1014. Q $0CD) Commodore BASIC uses keyword "tokens" to save program space.  Token
  1015.         129 becomes "FOR".  What two tokens expand to include a left
  1016.         parenthesis as well as a BASIC keyword?
  1017.  
  1018. Q $0CE) There are 6 wires in the Commodore serial bus.  Name the 6 wires.
  1019.  
  1020. Q $0CF) On the Commodore datasette connector, how many logical connections are
  1021.         there?
  1022.  
  1023. Some are easy, some are hard, try your hand at:
  1024.  
  1025.       Commodore Trivia Edition #13!
  1026.  
  1027. Jim Brain
  1028. brain@mail.msen.com
  1029. 602 North Lemen (New address)
  1030. Fenton, MI  48430
  1031. (810) 737-7300 x8528
  1032.  
  1033. ==============================================================================
  1034. A Different Perspective, part II
  1035. by George Taylor (aa601@cfn.cs.dal.ca) and Stephen Judd (sjudd@nwu.edu).
  1036.  
  1037. We... are... VR Troopers!  Okay Troopers, once again we need to make an
  1038. excursion out of the three dimensional world and into our own little virtual
  1039. world inside the C64.  So sit back in your virtual chair, put on your virtual
  1040. thinking helmet, maybe grab a virtual beer, and prepare for a virtually
  1041. useful experience with another virtually humongous article.
  1042.  
  1043. Last time we laid down the foundations of 3D graphics: rotations and
  1044. projections.  In this article we will build upon this foundation with a look
  1045. at hidden surfaces as well as filled surfaces.  In addition we will snaz up
  1046. the old program so that it is a little more efficient by for instance
  1047. introducing a much faster multiplication routine and moving all variables
  1048. into zero-page.
  1049.  
  1050. To get us in the mood let's review from last time.  We are in a
  1051. three-dimensional space; in particular, a right-handed three-dimensional
  1052. space, so that the x-axis comes towards you, the y-axis increases to the
  1053. right, and the z-axis increases "up".  Now we have some object, centered at
  1054. the origin.
  1055.  
  1056. To rotate the object we derived a 3x3 matrix for each axis which describes a
  1057. rotation about that axis.  After rotating we translate the object along the
  1058. z-axis and then project it through the origin onto a plane z=constant.
  1059.  
  1060. As you recall the projection of a point is done by drawing a line from the
  1061. point through the origin, and then figuring out where this line intersects
  1062. our plane z=constant.  You can think of this line as a ray of light bouncing
  1063. off the object and through our little pinhole camera lens.
  1064.  
  1065. Clearly for any solid object some parts of the object will remain hidden,
  1066. though, i.e. when you look at your monitor you can't see the back of it, and
  1067. you probably can't see the sides.  How do we capture this behavior
  1068. mathematically?
  1069.  
  1070.  
  1071. Hidden Surfaces
  1072. ---------------
  1073.  
  1074. Imagine our object with some light shining on it -- when will a part of the
  1075. object be hidden?  Clearly it is hidden when the light reflected off of it
  1076. never reaches our eyes, which happens whenever a part of the object is
  1077. "turned away" from us.  How do we express this mathematically? Consider a
  1078. flat plate, like your hand (you also might think of a cube).  Now imagine a
  1079. rod sticking out of the plate, exactly perpendicular to the plate (take your
  1080. index finger from your other hand, and touch it to your palm at a
  1081. ninety-degree angle).  Now rotate the plate around, and imagine the light
  1082. bouncing off and heading towards your eyes.
  1083.  
  1084. No matter where you place your hand in space, the very last point at which it
  1085. is visible is when it is exactly parallel to the light rays coming from it to
  1086. your eyes; or, to put it another way, when the light rays are exactly
  1087. perpendicular to a normal vector to the surface (in the above case this
  1088. vector is either a rod or your finger).  If the angle between the normal and
  1089. a light ray is less than ninety degrees, then the surface is visible.  If
  1090. greater, then the surface is invisible.
  1091.  
  1092. At this point you may be wondering how to figure out the angle between two
  1093. vectors.  It turns out we really don't have to calculate it at all: instead
  1094. we use a very important tool in our mathematical toolbox, the dot product.
  1095.  
  1096. If we have two vectors v1=(x1,y1,z1) and v2=(x2,y2,z2) then the dot product
  1097. is defined to be
  1098.  
  1099.         v1 dot v2 = x1*y1 + x2*y2 + x3*y3
  1100.  
  1101. note that this is a _scalar_ (i.e. a number), and not a vector.  You can also
  1102. show that
  1103.  
  1104.         v1 dot v2 = |v1|*|v2|*cos(theta)
  1105.  
  1106. where | | denotes length and theta is the angle between the two vectors.
  1107. Since cos(theta) is positive or negative depending on whether or not theta is
  1108. less than or greater than ninety degrees, all we have to do is take the dot
  1109. product and look at the sign.
  1110.  
  1111. But we need to understand something about the dot-product.  theta is the
  1112. angle between two vectors joined at their base; mathematically the way we are
  1113. going to draw the light ray is to draw a line FROM the origin TO a point on
  1114. the surface.  In our model above, we are going to draw a line from your eyes
  1115. to the palm of your hand and then slide the normal vector down this line
  1116. until the base of the normal vector touches your eye.
  1117.  
  1118. The whole point of this is that when we look at the dot product we need to
  1119. keep in mind that if the dot product is negative, the face is visible.
  1120.  
  1121. All that remains is to write down an equation: let's say that we've rotated
  1122. the surface and know a point P=(x,y,z) on the rotated surface, and we have a
  1123. normal vector to the surface vn=(vx,vy,vz).  First we need to translate down
  1124. the z-axis so that P -> (x,y,z-z0) = P - (0,0,z0).  If we then take the dot
  1125. product we find that
  1126.  
  1127.     P' dot vn = (P dot vn) - z0*vz
  1128.  
  1129. But (P dot vn) is simply a constant: because these are rigid rotations the
  1130. length of P never changes, presumably the length of vn never changes, and the
  1131. angle between the two never changes.  So introduce a constant K where
  1132.  
  1133.     K = (P dot vn)/z0
  1134.  
  1135. so that all we need to do is subtract the z-component of the normal vector
  1136. from K and check if it is positive or negative: if negative, the face is
  1137. visible.  Note that if we translate by an amount P + (0,0,z0) (instead of -
  1138. (0,0,z0)) we simply add the two together.
  1139.  
  1140. We seem to have left something out here: how do we calculate the normal
  1141. vector vn?  One way to do it is by using another vector operator, the
  1142. cross-product.  The dot product of two vectors is just a scalar, but the
  1143. cross product of two vectors is another vector, perpendicular to the first
  1144. two.
  1145.  
  1146. The most common way to visualize the cross-product is by using your right
  1147. hand: imagine two vectors in space, and place your right hand along one of
  1148. them, with your thumb sticking out.  Now curl your fingers towards the other
  1149. vector.  Your thumb points in the direction of the vector formed from the
  1150. cross-product of the first two.  You can easily convince yourself then that
  1151. (A x B) = -(B x A), that is, if you reverse the order of the cross product,
  1152. you get a vector pointing in the opposite direction.
  1153.  
  1154. Therefore, if we take any two vectors in the face (in particular, we know the
  1155. edge of the face), and then take their cross-product, we have a normal
  1156. vector.
  1157.  
  1158. But because we are dealing with a cube, we have an even easier method!  We
  1159. can use the fact that the faces on a cube are perpendicular to each other: if
  1160. we take two points and subtract them we get a vector going between the two
  1161. points.  On a cube, this will give us a normal vector if we use two
  1162. "opposite" points.  Therefore all we need to do is rotate the cube, subtract
  1163. two z-coordinates, add to K, and check if it is positive or negative.
  1164.  
  1165. This is how the program does it, and the specifics will be explained later.
  1166. Right now I want to show you a second method of hidden surface detection.
  1167. Instead of using the three-dimensional rotate vectors, what if we use the
  1168. two-dimensional _projected_ vectors?  If we take the cross-product of two of
  1169. these vectors we get a vector which either points into the screen or out of
  1170. it, which corresponds to a positive or a negative result.
  1171.  
  1172. The cross-product is usually done by taking the determinant of a matrix.  I
  1173. am not going to explain that here -- you can look in any decent calculus book
  1174. for the full cross-product.  All we really care about is the z-coordinate of
  1175. the vector, and the z-coordinate of v1 x v2 is:
  1176.  
  1177.     v1x*v2y - v1y*v2x
  1178.  
  1179. Whether or not the face is visible depends on how you define v1 and v2!
  1180. Always remember that (v1 x v2) = -(v2 x v1).
  1181.  
  1182. What is this quantity anyways?  Consider a parallelogram made up of our two
  1183. vectors v1 and v2.  The magnitude of the cross-product just happens to be
  1184.  
  1185.     |v1|*|v2|*sin(theta)
  1186.  
  1187. which you can easily see is the area of a parallelogram with sides v1 and v2.
  1188. For this reason the second method apparently goes by the name SAM -- Signed
  1189. Area Method.  (Now you need to think about the interpretation of the dot
  1190. product in a similar way).
  1191.  
  1192. Note that the second method is quite general, while the first method only
  1193. works for objects which have perpendicular surfaces (at least, in it's
  1194. current form presented here).  On the other hand, the first method is
  1195. significantly faster.
  1196.  
  1197. Now that we've hidden the faces, it's time to fill them:
  1198.  
  1199.  
  1200. Filled Faces
  1201. ------------
  1202.  
  1203.     Q: How do you make a statue of an elephant?
  1204.     A: Start with a block of granite and carve away everything
  1205.        that doesn't look like elephant!
  1206.  
  1207. The first method of filling faces is very simple in concept.  Let's say we
  1208. want a cube with white faces and black edges.  Before, the program would make
  1209. the buffer black and then draw in the white edges.  The idea here is to make
  1210. the entire buffer white, draw the edges in black, and then make everything
  1211. outside of the edges black.  Quite simply, we start with a solid block and
  1212. then take away everything that doesn't look like a cube!  You can also think
  1213. of it like a cookie cutter: we press our cube-shaped cutter down and remove
  1214. all the dough outside of the cutter.
  1215.  
  1216. This simplistic method actually has some advantages.  If the object is very
  1217. large, we spend very little time doing the actual un-filling. We don't care
  1218. about how complicated the object is, because we just trace out the edge.
  1219. Finally, this gives us an extremely easy way of implementing a rudimentary
  1220. texture-mapping in multicolor mode.  For instance, instead of coloring the
  1221. block white, what if we used a changing pattern of colors?  As long as the
  1222. edge is a specific color, the pattern can be any combination of the other
  1223. three colors.  An example program which does just this is included -- note
  1224. that the inititalization program needs to be changed slightly to run this
  1225. program.
  1226.  
  1227. In other words, we roll the dough, draw a pattern into it, press our cutter
  1228. down and remove the outside dough.  We are left with a cube with patterns all
  1229. over it.
  1230.  
  1231. On the downside it's not quite so easy to do things like have each face a
  1232. separate color (but who wants wimpy separate colors when you can have
  1233. evolving texture patterns, eh? :).
  1234.  
  1235. The program makes a few refinements to this technique.  For instance, instead
  1236. of coloring the entire buffer white, it calculates ahead of time the minimum
  1237. and maximum values for y, and only colors that part of the drawing area
  1238. white.
  1239.  
  1240. For the sake of completeness, here is another method of filling:
  1241. exclusive-or. A clever way of filling faces is to use some EOR magic.  Let's
  1242. say we want to fill everything between two points A and B.  We want to start
  1243. filling at point A and stop at point B, and since EOR is a bit flipper this
  1244. gives us a means of filling.  Consider the following situation in memory:
  1245.  
  1246.     00010000  <-- Point A
  1247.     00000000
  1248.     00000000
  1249.     00010000  <-- Point B
  1250.  
  1251. Now consider the following little piece of code:
  1252.  
  1253.     LDA #00
  1254.     EOR A
  1255.     STA A
  1256.     EOR A+1
  1257.     STA A+1
  1258.     EOR A+2
  1259.     STA A+2
  1260.     EOR A+3      ;point B
  1261.  
  1262. The result is:
  1263.  
  1264.     00010000
  1265.     00010000
  1266.     00010000
  1267.     00010000
  1268.  
  1269. This is the conceptual idea behind an EOR-buffer.  Pretty neat, eh?  But we
  1270. can't just implement this as-is.  In fact we have a whole slew of things to
  1271. worry about now.  Try EORing a vertical line.  What about when two lines
  1272. share a single pixel at their intersection?  What happens in color?
  1273.  
  1274. Ah reckon y'all will just have to wait until next time tuh see :).
  1275.  
  1276.  
  1277. Da Program
  1278. ----------
  1279.  
  1280. Let's review the code.  We check to see if we should increase or decrease the
  1281. rotation rate (or quit), and then update the angles. Next we calculate the
  1282. rotation matrix using a table of sines and cosines. Then we rotate and
  1283. project the points by using a table of d/(z/64-z0) values. Somewhere in there
  1284. we clear a working buffer, draw all of the lines, swap the buffers, pass Go,
  1285. collect $200 (actually, considering where the buffers are located we either
  1286. collect $300 or $380 :), and go around the loop again.
  1287.  
  1288. First, some bugs.  There were two places in the line drawing routine where an
  1289. SBC was performed with the carry clear when it should have been set, so we
  1290. need to add some SECs in there.  Somewhere there is a strange bug related to
  1291. y-rotations, but I didn't track it down.
  1292.  
  1293. Although not a bug, there is something to think about.  On the computer, x
  1294. increases to the right, and y-increases downwards, with z coming out of the
  1295. screen.  But this is a left-handed coordinate system, and all our
  1296. calculations were performed in a right-handed coordinate system.  What this
  1297. means is that one of our coordinates is actually a mirror-image of what it
  1298. should be, while the other coordinate is where it is supposed to be.
  1299. Remember that a projection generates a negative mirror-image of the object --
  1300. the computer coordinate system mirrors a single axis of the image again!
  1301.  
  1302. Because of the symmetry of a cube, this makes no difference. A smart way to
  1303. fix this is to translate the object in _front_ of the projection plane, i.e.
  1304. to use the translation z=z+c instead of the currently used z=z-c, but still
  1305. project through the origin and into the plane z=1.  Since I am not
  1306. particularly smart though, not to mention lazy and unmotivated, I didn't
  1307. bother to fix this.
  1308.     
  1309. Before we start adding the new stuff like hidden surfaces into the code, why
  1310. don't we think about doing some simple optimizations to the old code?  One
  1311. really easy thing to fix is in the projection routine.  You will recall that
  1312. the earlier program rotated z and then added 128 to it to use as an index.
  1313. Why bother to add 128 at all?  I dunno -- sometimes things seem like a good
  1314. idea at the time.  So that's something to fix. It's not that it's a big waste
  1315. of time, it's just one of those annoying things that there's no reason for.
  1316.  
  1317. How about the variables?  They're all just sitting at the end of the program
  1318. -- why not move them all into zero page?  Sounds good to me!  We just need to
  1319. make sure we don't use any sensitive locations in zero page that will hose
  1320. the whole computer.  So now that's fixed.
  1321.  
  1322. On the C64 an interrupt is performed every 60th of a second which scans the
  1323. keyboard and things like that -- why in the world do we want that running in
  1324. the middle of all our calculations?  I dunno -- let's turn it off (but turn
  1325. it back on before checking to see if F1 etc. was pressed!).
  1326.  
  1327. A footnote observation: when the rotation matrix is calculated, two macros
  1328. are used (MUL2 and DIV2) which multiply and divide a signed number by two.
  1329. It never ceases to amaze me what happens when you simply sit down and think
  1330. about something, and in this case these two macros can be made much simpler:
  1331.  
  1332.     MUL2    ASL     ;That's all, folks
  1333.  
  1334.     DIV2    CLC
  1335.         BPL :POS
  1336.         SEC
  1337.     :POS    ROR
  1338.  
  1339. These two routines will multiply/divide a signed 2's complement number
  1340. by two (note that the source included with this article uses the old method).
  1341.     
  1342. There's the easy stuff to fix.  What about the calculations themselves? The
  1343. rotation is pretty straightforward -- nah, skip that.  The line drawing
  1344. routine takes up an awful lot of time -- maybe we can speed that up?  That's
  1345. for a future article :).  Clearing the buffer takes a lot of time, but now
  1346. that we're going to have filled faces there isn't too much we can do about
  1347. that.  In fact, so much more time is spent in those two areas than is spent
  1348. in other parts of the code that any other optimizations we make really aren't
  1349. going to make a very big difference... BUT...
  1350.  
  1351. How about multiplications?
  1352.  
  1353.  
  1354. Fast Signed Multiply
  1355. --------------------
  1356.  
  1357. Ah, now here is something we can fix.  Consider the following function:
  1358.  
  1359.     f(x) = x*x/4
  1360.  
  1361. Now notice that
  1362.  
  1363.     f(a+b) - f(a-b) = a*b
  1364.  
  1365. Wowsers!  All we need to do is have a table of squares, and we can do a
  1366. multiplication in no time!
  1367.  
  1368. Whoa there, wait a minute, all of our calculations are using signed numbers.
  1369. Won't that make a difference?  Well, the above calculation is completely
  1370. general -- I never said what the sign of a and b are.  The fact that we are
  1371. using two's complement notation makes this even simpler!
  1372.  
  1373. Recall that our multiplication is
  1374.  
  1375.     x -> x * [d/(z0-z/64)]
  1376.  
  1377. where x is a signed floating point number multiplied by 64 (that is,  instead
  1378. of going from -1 to 1 x would go from -64 to 64).  Previously we made d
  1379. large, so that the table of d/(z-z0) would be more accurate. Then we
  1380. multiplied the numbers together and divided by 64, a procedure which took
  1381. between 150 and 180 cycles, leaving us with a signed, 8-bit result.
  1382.  
  1383. Well, that's easy to duplicate.  From our first equation above, we see that
  1384.  
  1385.     (a*b)/64 = [ f(a+b) - f(a-b) ]/64
  1386.          = g(a+b) - g(a-b)
  1387. where
  1388.     g(x) = x*x/256.
  1389.  
  1390. In other words, if we modify our table slightly, we get exactly the result we
  1391. want.  So here is the code to multiply two numbers together:
  1392.  
  1393. * A*Y -> A  Signed, 8-bit result
  1394.  
  1395.     STA ZP1        ;ZP1 -- zero page pointer to table of g(x)
  1396.     EOR #$FF
  1397.     CLC
  1398.     ADC #$01
  1399.     STA ZP2        ;ZP2 also points to g(x)
  1400.     LDA (ZP1),Y    ;g(Y+A)
  1401.     SEC
  1402.     SBC (ZP2),Y    ;g(Y-A)
  1403.  
  1404. And that's it -- we're done.  The above takes 24-26 cycles to execute -- not
  1405. bad at all!  Yes, with another table we could make it even faster, but this
  1406. is good enough for us.
  1407.  
  1408. At the moment we don't do very many multiplications, but in the future, when
  1409. we write a generalized routine to rotate and project an arbitrary object,
  1410. this will give us a humongous time savings.
  1411.  
  1412. Astute readers may be thinking ahead here: in the program, for each
  1413. projection we have two multiplications, x=x*c and y=y*c, where c is the same
  1414. in both cases.  So if we store c in ZP1 and ZP2, we can make the
  1415. multiplication even more efficient, right?  The answer is yes, but only by
  1416. being extremely careful, for reasons that will be detailed in exactly two
  1417. paragraphs.
  1418.     
  1419. BUT WAIT!  We have to think about a few things here.  What happens when we
  1420. multiply, say, -1 * -1.  In two's complement notation -1 is equal to 255.  So
  1421. our above algorithm adds 255 to 255 to get an index into the table and
  1422. gets... oops!  Our table needs to be larger than 256 bytes!  In fact this is
  1423. very easy to fix, because of the way two's complement works.  All we need to
  1424. do is put an exact copy of the 256 byte table on top of itself, and the table
  1425. will work fine.  (If you look at the initialization program you will notice
  1426. that the statement is: q%=s*s:poke bm+j,q%:poke bm+j+256,q%).
  1427.  
  1428. BUT WAIT!!!  What kinds of numbers are we multiplying together here? Our
  1429. vertices start out at the points (+/-1,+/-1,+/-1).  Our rotations correspond
  1430. to moving these points around on a sphere, so it is easy to see that the
  1431. largest rotated value we can have is sqr(3), the radius of this sphere.
  1432. Since we are multiplying these numbers by 64, the largest value we can have
  1433. for these numbers is 64*sqr(3) = 111.  Okay, no big whoop, what are the
  1434. values for d/(z0-z/64) anyways?  Well, for z0=5 and d=150 say we get values
  1435. like 28...
  1436.  
  1437. ACK!  When we go to multiply we are going to add 111 to 28 and get 137, but
  1438. in two's complement notation this is equal to -119.
  1439.  
  1440. Example:
  1441.     a=28
  1442.     b=111
  1443.     f(b+a) = f(137) = f(-119) in two's-complement notation
  1444.     f(b-a) = f(83)
  1445.  
  1446. In our table lookup we really want 137*137 but we are going to get -119*-119!
  1447. One option is to never choose d very large so that we don't have this
  1448. problem, but the solution turns out to be much simpler, again due to the way
  1449. two's complementing works.
  1450.  
  1451. We can see that we can get numbers larger than 127 when we add the two
  1452. multiplicands together.  What is the _smallest_ number we will come up with?
  1453. Certainly the smallest x is going to get is -111. Ahhh... d/(z0-z/64) is
  1454. always positive, so when we add them together we will get something larger
  1455. than -111, which in two's complement notation is 145.  This means that we can
  1456. treat the table entries between 127 and at least 145 as positive numbers
  1457. instead of two's complement negative numbers, and everything will work out
  1458. great.
  1459.  
  1460. Incidentally, fudging this table provides an easy way to add pretty cool
  1461. special effects.  The initialization program sets up the math table using the
  1462. following line:
  1463.  
  1464.         [for j=0 to 255]
  1465.     290 S=J:IF S>150 THEN S=256-S
  1466.         [poke bm+j,S*S]
  1467.  
  1468. Try changing the inequality from S>150 to S>120 (or S>127, where it would be
  1469. for a two's complement table), and see what happens!
  1470.  
  1471. And this is why we can't store d/(z0-z) in the pointers ZP1 and ZP2 -- if we
  1472. did, then for a given multiplication we could get numbers larger than 127 and
  1473. smaller than -128, and our clever table would no longer work right.  We can
  1474. still get around this -- all we need is two clever tables, one for the
  1475. positive d/(z0-z) and one for negative d/(z0-z).  For the first table, we
  1476. have the situation outlined above: no numbers smaller than -90 or so, and
  1477. numbers possible larger than 127.  For the second table we have the reverse
  1478. situation: no numbers larger than 90 or so, but possible numbers less than
  1479. -128. Since we are using two pointers anyways (ZP1 and ZP2), this is not
  1480. difficult to implement.
  1481.  
  1482. The end result is that you can do the entire projection in around 36 cycles
  1483. if you so desire.  36 cycles?  Note that for the second table the code does
  1484. something like EOR #$FF; CLC; ADC #$01. Well, if we set up the second table
  1485. as f(x)=(x+1)^2/4 then we have included the CLC and ADC #$01 into the table,
  1486. so the instructions can be removed.  The entire projection routine is then:
  1487.  
  1488.     ... (rotate z)
  1489.     STA ZP1
  1490.     EOR #$FF
  1491.     STA ZP2
  1492.     ... (rotate x)
  1493.     TAY
  1494.     LDA (ZP1),Y
  1495.     SEC
  1496.     SBC (ZP2),Y    ;Now A contains projected X
  1497.     ... (rotate y)
  1498.     TAY
  1499.     LDA (ZP1),Y
  1500.     SEC
  1501.     SBC (ZP2),Y
  1502.  
  1503. Looks like 36-40 cycles to me!  The program doesn't implement this -- it only
  1504. uses a single table, and repeats the STA ZP1 stuff at each step.  A few
  1505. cycles wasted won't kill us (there are plenty of cycles wasted in the code),
  1506. and it is probably tricky enough to follow as it is.
  1507.  
  1508. You might be asking, what is the true minimum value for a given z0 and d?
  1509. Well, I tried writing down a set of equations and minimizing according to
  1510. some constraints, and I ended up with a sixth-order polynomial which I had to
  1511. write little newton-iteration solver for.  In other words, I don't think you
  1512. can write down a simple function of d and z0 to give the table boundaries.  I
  1513. found 150 to be a perfectly reasonable number to use.
  1514.  
  1515. Incidentally, this is why the projection was not changed to z=z+c -- I didn't
  1516. want to go fiddling around with it again.  Maybe next time :).
  1517.  
  1518. ONE MORE THING!!!  This is very important.  The math table MUST be on an even
  1519. boundary for the above algorithm to work correctly.  This one is easy to get
  1520. bit by.
  1521.  
  1522. Logarithmic Multiplication
  1523. --------------------------
  1524.  
  1525. As long as we're talking about fast multiplication here, it is worthwhile to
  1526. mention another method for multiplying two numbers together.  To understand
  1527. it you need to understand two important properties of logarithms:
  1528.  
  1529.     log(x*y) = log(x) + log(y)
  1530.     log_b(x) = y  <=>  b^y = x
  1531.  
  1532. These are a reflection of the fact that logarithms are inverses of
  1533. exponentiation.  So you can see that another way to multiply two numbers
  1534. together is to take their logs, add, and then exponentiate the result.  So
  1535. you could have a table of log_2 (base 2 logarithms) and another table of 2^x,
  1536. and do a multiplication very quickly. (Actually, you'd want a table of
  1537. 32*log_2(x), since log_2(256)=8). Why wasn't this method used?
  1538.  
  1539. First, dealing with signed numbers is much trickier -- the logarithm of a
  1540. negative number is a complex (i.e. real+imaginary) number, complete with
  1541. branch cuts.  You can get around this by setting up the tables in a special
  1542. way (for instance by letting log(-x)=-log(x)) and putting in some special
  1543. handling, but it isn't as efficient as the algorithm used in the program.
  1544.  
  1545. Second, accuracy decreases significantly as x and y get large, so that for an
  1546. eight-bit table of logarithms you will often get an answer that is off by one
  1547. or more.  You can in fact get around this problem by using some sneaky
  1548. manipulation -- if you are interested in seeing this, contact us!
  1549.  
  1550. But it is worthwhile to keep this method in mind if you need a really fast
  1551. multiplication and you aren't too worried about accuracy.
  1552.  
  1553. Christopher Jam (phillips@ee.uwa.edu.au) has come up with an interesting
  1554. variation on this method.  It calculates 64+64*x/z and uses a slightly
  1555. different structure for the signed numbers, and runs almost as fast as the
  1556. method used by the program -- contact him for more information if you're
  1557. interested.
  1558.  
  1559.  
  1560. Hidden Surfaces
  1561. ---------------
  1562.  
  1563. The remainder of this follows right from the discussion section. In the
  1564. program the cube vertices are labeled as
  1565.  
  1566.     P1 = 1,1,1
  1567.     P2 = 1,-1,1
  1568.     P3 = -1,-1,1
  1569.     P4 = -1,1,1
  1570.     P5 = 1,1,-1
  1571.     P6 = 1,-1,-1
  1572.     P7 = -1,-1,-1
  1573.     P8 = -1,1,-1
  1574.  
  1575. and the faces are chosen to be
  1576.  
  1577.     Face 1: P1 P2 P3 P4
  1578.          6: P5 P6 P7 P8
  1579.     Face 2: P1 P2 P5 P6
  1580.          5: P3 P4 P7 P8
  1581.     Face 3: P1 P4 P8 P5
  1582.          4: P2 P3 P6 P7
  1583.  
  1584. (think of it as a six-sided dice, with six opposite of one, etc.).  The normal
  1585. vectors are then
  1586.  
  1587.     Face 1: P1-P5
  1588.     Face 2: P1-P4
  1589.     Face 3: P1-P2
  1590.  
  1591. This means that we need to store the z-coordinates for points 1,2,4, and 5.
  1592. Note that the opposite faces have exactly opposite normal vectors, so that
  1593. for instance the normal vector for face 6 is P5-P1, the negative of face 1.
  1594.  
  1595. Here is something to consider: when one face is visible, the opposite face
  1596. cannot be visible!  Because of the way projections work, though, the converse
  1597. is not true; it is entirely possible to have two opposite faces invisible.
  1598. To prove this to yourself just look at your favorite box, like your monitor,
  1599. straight-on, and notice that you can't see the sides!
  1600.  
  1601. All that the program does is subtract z-coordinates and add them to the
  1602. constant K, and check the sign.  Unfortunately we can have a positive
  1603. overflow while adding stuff together (since these are signed numbers), and if
  1604. we don't catch the positive overflow we will calculate a negative result when
  1605. the result is actually positive!  This will of course wreck the hidden
  1606. surface removal.
  1607.  
  1608.  
  1609. Filled Faces
  1610. ------------
  1611.  
  1612. The program currently uses the first algorithm to fill faces, i.e. the
  1613. cookie-cutter elephant-carving method.  During the projections the program
  1614. checks each value of y to find the minimum and maximum values for this plot,
  1615. ymin and ymax.  The program then clears the buffer up to and including ymin,
  1616. fills the buffer from ymin+1 to ymax-1, and then clears the rest of the
  1617. buffer.  Why does it clear ymin and ymax?  Because the only thing that can
  1618. happen on those lines is an edge -- there is no point in filling these lines
  1619. and then clearing them, since they will always be clear.  By only filling the
  1620. buffer between ymin and ymax, we save some time in removing the junk from the
  1621. edges of the cube.
  1622.  
  1623. Next, the cube is drawn.  The background is black and the faces are white,
  1624. i.e. our fill color is white.  Clearly then we want to draw our lines in
  1625. black.  I could have reversed background and foreground colors and left the
  1626. line routine as-is, but of course being the lazy programmer I am I decided
  1627. instead to change the table BITP.  You may recall that the earlier table had
  1628. entries like %10000000 %01000000 etc. Now it has entries like %01111111
  1629. %10111111 etc., and instead of ORAing the values into the buffer, they are
  1630. ANDed into the buffer.  This then draws lines of zeroes into our buffer which
  1631. is solid ones.
  1632.  
  1633. Finally, to un-fill the outside of the cube the program simply goes through
  1634. the buffer from ymin to ymax, coloring everything black until it hits a zero,
  1635. i.e. an edge.  At this point it calculates the appropriate pattern to clear
  1636. up to the edge, and then does the same thing starting from the right hand
  1637. side of the buffer.  In other words it runs along a specific y-value coloring
  1638. everything black until it hits the edge of the cube, and does this for all
  1639. the relevant y-values.
  1640.  
  1641.  
  1642. Texture Mapping
  1643. ---------------
  1644.  
  1645. More of a fill-pattern really.  The program cube3d2.1.o does all of the above
  1646. but in multicolor mode.  Now instead of using a solid color to fill the
  1647. buffer the program uses a series of colored lines -- really a very simple
  1648. pattern.  A much neater thing would be to have a pattern drawn out in a
  1649. pattern buffer, and to copy that into the drawing buffer.  Other things to
  1650. try are colored squares which shift around.  cube3d2.1.o is just a really
  1651. quick hack, but at least it demonstrates the concept.
  1652.  
  1653. MAKE SURE that you change the value of D from 170 to 85 if you try this
  1654. program!  Pixels are doubled now, so that resolution is cut in half.  This is
  1655. located at line 240 in INIT3D2.0
  1656.  
  1657.  
  1658. Memory Map
  1659. ----------
  1660.  
  1661. The main program is located at $8000=32768 and is 3200 bytes long.
  1662.  
  1663.     $8000-$8C00     - Program
  1664.     $8C00-$8C80    - Bit position table
  1665.     $8C80-$8D00    - Table of sines
  1666.     $8D00-$8D80    - Table of cosines.
  1667.     $8D80-$8E80    - Table of d/(z0-z/64)
  1668.     $8F00-$9100    - Two 256-byte tables of g(x)=x*x/256
  1669.  
  1670.     $3000        - First drawing buffer
  1671.     $3800        - Second drawing buffer
  1672.  
  1673. INIT3D is a simple basic program to set up the tables.  For INIT3D2.x the
  1674. important setup routines are:
  1675.  
  1676.     lines 100-150    - Set up the trigonometric tables
  1677.     lines 233-310    - Set up the projection and mult tables
  1678.         240    - Location of constants D and Z0
  1679.         290    - Set table boundary for multiplication
  1680.  
  1681.  
  1682. That's all -- until next time...
  1683.  
  1684. Steve Judd    George Taylor    12/2/95
  1685.  
  1686. This document is Copyright 1995 by Stephen Judd and George Taylor. Much like
  1687. the previous one.  It is also freely distributable.
  1688.  
  1689. And here is the source code:
  1690.  
  1691.  
  1692. ********************************
  1693. *                              *
  1694. * Stephen Judd                 *
  1695. * George Taylor                *
  1696. * Started: 7/11/94             *
  1697. * Finished: 7/19/94            *
  1698. * v2.0 Completed: 12/17/94     *
  1699. *                              *
  1700. * Well, if all goes well this  *
  1701. * program will rotate a cube.  *
  1702. *                              *
  1703. * v2.0 + New and Improved!     *
  1704. * Now with faster routines,    *
  1705. * hidden surfaces, filled      *
  1706. * faces, and extra top secret  *
  1707. * text messages!               *
  1708. *                              *
  1709. * This program is intended to  *
  1710. * accompany the article in     *
  1711. * C=Hacking, Jan. 95 issue.    *
  1712. * For details on this program, *
  1713. * read the article!            *
  1714. *                              *
  1715. * Write to us!                 *
  1716. *                              *
  1717. * Myself when young did        *
  1718. * eagerly frequent             *
  1719. * Doctor and Saint, and heard  *
  1720. * great Argument               *
  1721. *  About it and about: but     *
  1722. *  evermore                    *
  1723. * Came out by the same Door    *
  1724. * as in I went.                *
  1725. *    - Rubaiyat                *
  1726. *                              *
  1727. * Though I speak with the      *
  1728. * tongues of men and of angles *
  1729. * and have not love, I am      *
  1730. * become as sounding brass, or *
  1731. * a tinkling cymbal.           *
  1732. *    - 1 Corinthians 13        *
  1733. *                              *
  1734. * P.S. This was written using  *
  1735. *      Merlin 128.             *
  1736. ********************************
  1737.  
  1738.          ORG $8000
  1739.  
  1740. * Constants
  1741.  
  1742. BUFF1    EQU $3000        ;First character set
  1743. BUFF2    EQU $3800        ;Second character set
  1744. BUFFER   EQU $A3          ;Presumably the tape won't be running
  1745. X1       EQU $FB          ;Points for drawing a line
  1746. Y1       EQU $FC          ;These zero page addresses
  1747. X2       EQU $FD          ;don't conflict with BASIC
  1748. Y2       EQU $FE
  1749. DX       EQU $F9
  1750. DY       EQU $FA
  1751. TEMP1    EQU $FB          ;Of course, could conflict with x1
  1752. TEMP2    EQU $FC          ;Temporary variables
  1753. ZTEMP    EQU $02          ;Used for buffer swap.  Don't touch.
  1754. Z1       EQU $22          ;Used by math routine
  1755. Z2       EQU $24          ;Don't touch these either!
  1756. K        EQU $B6          ;Constant used for hidden
  1757.                           ;surface detection - don't touch
  1758. FACES    EQU $B5          ;Used in hidden surfaces.
  1759. YMIN     EQU $F7          ;Used in filled faces -- as
  1760. YMAX     EQU $F8          ;usual, don't touch
  1761. ANGMAX   EQU 120          ;There are 2*pi/angmax angles
  1762.  
  1763. * VIC
  1764.  
  1765. VMCSB    EQU $D018
  1766. BKGND    EQU $D020
  1767. BORDER   EQU $D021
  1768. SSTART   EQU 1344         ;row 9 in screen memory at 1024
  1769.  
  1770.  
  1771. * Kernal
  1772.  
  1773. CHROUT   EQU $FFD2
  1774. GETIN    EQU $FFE4
  1775.  
  1776. * Some variables
  1777.  
  1778. TX1      = $3F
  1779. TY1      = $40
  1780. TX2      = $41
  1781. TY2      = $42
  1782. P1X      = $92            ;These are temporary storage
  1783. P1Y      = $93            ;Used in plotting the projection
  1784. P2X      = $94
  1785. P2Y      = $95            ;They are here so that we
  1786. P3X      = $96            ;don't have to recalculate them.
  1787. P3Y      = $AE
  1788. P4X      = $AF            ;They make life easy.
  1789. P4Y      = $B0
  1790. P5X      = $B1            ;Why are you looking at me like that?
  1791. P5Y      = $B2            ;Don't you trust me?
  1792. P6X      = $B3
  1793. P6Y      = $B4            ;Having another child wasn't my idea.
  1794. P7X      = $71
  1795. P7Y      = $50
  1796. P8X      = $51
  1797. P8Y      = $52
  1798. P1Z      = $57            ;These are z-coordinates
  1799. P2Z      = $58            ;We only need these four to check
  1800. P4Z      = $59            ;for hidden faces
  1801. P5Z      = $60
  1802. DSX      = $61            ;DSX is the increment for
  1803.                           ;rotating around x
  1804. DSY      = $62            ;Similar for DSY, DSZ
  1805. DSZ      = $63
  1806. SX       = $64            ;These are the actual angles in x y and z
  1807. SY       = $65
  1808. SZ       = $66
  1809. T1       = $67            ;These are used in the rotation
  1810. T2       = $68
  1811. T3       = $69            ;See the article for more details
  1812. T4       = $6A
  1813. T5       = $6B
  1814. T6       = $6C
  1815. T7       = $6D
  1816. T8       = $6E
  1817. T9       = $6F
  1818. T10      = $70
  1819. A11      = $A5            ;These are the elements of the rotation matrix
  1820. B12      = $A6            ;XYZ
  1821. C13      = $A7
  1822. D21      = $A8            ;The number denotes (row,column)
  1823. E22      = $A9
  1824. F23      = $AA
  1825. G31      = $AB
  1826. H32      = $AC
  1827. I33      = $AD
  1828.  
  1829.  
  1830. *** Macros
  1831.  
  1832. MOVE     MAC
  1833.          LDA ]1
  1834.          STA ]2
  1835.          <<<
  1836.  
  1837. GETKEY   MAC              ;Wait for a keypress
  1838. WAIT     JSR GETIN
  1839.          CMP #00
  1840.          BEQ WAIT
  1841.          <<<
  1842.  
  1843. *-------------------------------
  1844.  
  1845.          LDA #$00
  1846.          STA BKGND
  1847.          STA BORDER
  1848.          LDA VMCSB
  1849.          AND #%00001111   ;Screen memory to 1024
  1850.          ORA #%00010000
  1851.          STA VMCSB
  1852.  
  1853.          LDY #00
  1854.          LDA #<TTEXT
  1855.          STA TEMP1
  1856.          LDA #>TTEXT
  1857.          STA TEMP2
  1858.          JMP TITLE
  1859. TTEXT    HEX 9305111111   ;clear screen, white, crsr dn
  1860.          TXT '             cube3d v2.0',0d,0d
  1861.          TXT '                  by',0d
  1862.          HEX 9F           ;cyan
  1863.          TXT '    stephen judd'
  1864.          HEX 99
  1865.          TXT '    george taylor',0d,0d
  1866.          HEX 9B
  1867.          TXT '  check out the jan. 95 issue of',0d
  1868.          HEX 96
  1869.          TXT '  c=hacking'
  1870.          HEX 9B
  1871.          TXT ' for more details!',0d
  1872.          HEX 0D1D1D9E12
  1873.          TXT 'f1/f2',92
  1874.          TXT ' - inc/dec x-rotation',0d
  1875.          HEX 1D1D12
  1876.          TXT 'f3/f4',92
  1877.          TXT ' - inc/dec y-rotation',0d
  1878.          HEX 1D1D12
  1879.          TXT 'f5/f6',92
  1880.          TXT ' - inc/dec z-rotation',0d
  1881.          HEX 1D1D12
  1882.          TXT 'f7',92
  1883.          TXT ' resets',0d
  1884.          TXT '  press q to quit',0d
  1885.          HEX 0D05
  1886.          TXT '      press any key to begin',0d
  1887.          HEX 00
  1888. TITLE    LDA (TEMP1),Y
  1889.          BEQ :CONT
  1890.          JSR CHROUT
  1891.          INY
  1892.          BNE TITLE
  1893.          INC TEMP2
  1894.          JMP TITLE
  1895.          TXT 'This is a secret text message!'
  1896. :CONT    >>> GETKEY
  1897.  
  1898. **** Set up tables(?)
  1899.  
  1900. * Tables are currently set up in BASIC
  1901. * and by the assembler.
  1902.  
  1903. TABLES   LDA #>TMATH
  1904.          STA Z1+1
  1905.          STA Z2+1
  1906.  
  1907. **** Clear screen and set up "bitmap"
  1908. SETUP    LDA #$01         ;White
  1909.          STA $D021        ;This is done so that older
  1910.          LDA #147         ;machines will set up
  1911.          JSR CHROUT
  1912.          LDA #$00         ;correctly
  1913.          STA $D021
  1914.          LDA #<SSTART
  1915.          ADC #12          ;The goal is to center the graphics
  1916.          STA TEMP1        ;Column 12
  1917.          LDA #>SSTART     ;Row 9
  1918.          STA TEMP1+1      ;SSTART points to row 9
  1919.          LDA #00
  1920.          LDY #00
  1921.          LDX #00          ;x will count 16 rows for us
  1922.          CLC
  1923.  
  1924. :LOOP    STA (TEMP1),Y
  1925.          INY
  1926.          ADC #16
  1927.          BCC :LOOP
  1928.          CLC
  1929.          LDA TEMP1
  1930.          ADC #40          ;Need to add 40 to the base pointer
  1931.          STA TEMP1        ;To jump to the next row
  1932.          LDA TEMP1+1
  1933.          ADC #00          ;Take care of carries
  1934.          STA TEMP1+1
  1935.          LDY #00
  1936.          INX
  1937.          TXA              ;X is also an index into the character number
  1938.          CPX #16
  1939.          BNE :LOOP        ;Need to do it 16 times
  1940.  
  1941. **** Set up buffers
  1942.  
  1943.          LDA #<BUFF1
  1944.          STA BUFFER
  1945.          LDA #>BUFF1
  1946.          STA BUFFER+1
  1947.          STA ZTEMP        ;ztemp will make life simple for us
  1948.          LDA VMCSB
  1949.          AND #%11110001   ;Start here so that swap buffers will work right
  1950.          ORA #%00001110
  1951.          STA VMCSB
  1952.  
  1953. **** Set up initial values
  1954.  
  1955. INIT     LDA #00
  1956.          STA DSX
  1957.          STA DSY
  1958.          STA DSZ
  1959.          STA SX
  1960.          STA SY
  1961.          STA SZ
  1962.  
  1963. *-------------------------------
  1964. * Main loop
  1965.  
  1966. **** Get keypress
  1967.  
  1968. MAIN
  1969.          CLI
  1970. KPRESS   JSR GETIN
  1971.          CMP #133         ;F1?
  1972.          BNE :F2
  1973.          LDA DSX
  1974.          CMP #ANGMAX/2    ;No more than pi
  1975.          BEQ :CONT
  1976.          INC DSX          ;otherwise increase x-rotation
  1977.          JMP :CONT
  1978. :F2      CMP #137         ;F2?
  1979.          BNE :F3
  1980.          LDA DSX
  1981.          BEQ :CONT
  1982.          DEC DSX
  1983.          JMP :CONT
  1984. :F3      CMP #134
  1985.          BNE :F4
  1986.          LDA DSY
  1987.          CMP #ANGMAX/2
  1988.          BEQ :CONT
  1989.          INC DSY          ;Increase y-rotation
  1990.          JMP :CONT
  1991. :F4      CMP #138
  1992.          BNE :F5
  1993.          LDA DSY
  1994.          BEQ :CONT
  1995.          DEC DSY
  1996.          JMP :CONT
  1997. :F5      CMP #135
  1998.          BNE :F6
  1999.          LDA DSZ
  2000.          CMP #ANGMAX/2
  2001.          BEQ :CONT
  2002.          INC DSZ          ;z-rotation
  2003.          JMP :CONT
  2004. :F6      CMP #139
  2005.          BNE :F7
  2006.          LDA DSZ
  2007.          BEQ :CONT
  2008.          DEC DSZ
  2009.          JMP :CONT
  2010. :F7      CMP #136
  2011.          BNE :Q
  2012.          JMP INIT
  2013. :Q       CMP #'q'         ;q quits
  2014.          BNE :CONT
  2015.          JMP CLEANUP
  2016.  
  2017. :CONT    SEI              ;Speed things up a bit
  2018.  
  2019. **** Update angles
  2020.  
  2021. UPDATE   CLC
  2022.          LDA SX
  2023.          ADC DSX
  2024.          CMP #ANGMAX      ;Are we >= maximum angle?
  2025.          BCC :CONT1
  2026.          SBC #ANGMAX :If so, reset
  2027. :CONT1   STA SX
  2028.          CLC
  2029.          LDA SY
  2030.          ADC DSY
  2031.          CMP #ANGMAX
  2032.          BCC :CONT2
  2033.          SBC #ANGMAX      ;Same deal
  2034. :CONT2   STA SY
  2035.          CLC
  2036.          LDA SZ
  2037.          ADC DSZ
  2038.          CMP #ANGMAX
  2039.          BCC :CONT3
  2040.          SBC #ANGMAX
  2041. :CONT3   STA SZ
  2042.  
  2043. **** Rotate coordinates
  2044.  
  2045. ROTATE
  2046.  
  2047. *** First, calculate t1,t2,...,t10
  2048.  
  2049. ** Two macros to simplify our life
  2050. ADDA     MAC              ;Add two angles together
  2051.          CLC
  2052.          LDA ]1
  2053.          ADC ]2
  2054. * Use two trig tables to remove the below CMP etc. code
  2055.          CMP #ANGMAX      ;Is the sum > 2*pi?
  2056.          BCC DONE
  2057.          SBC #ANGMAX      ;If so, subtract 2*pi
  2058. DONE     <<<
  2059.  
  2060. SUBA     MAC              ;Subtract two angles
  2061.          SEC
  2062.          LDA ]1
  2063.          SBC ]2
  2064.          BCS DONE
  2065.          ADC #ANGMAX      ;Oops, we need to add 2*pi
  2066. DONE     <<<
  2067.  
  2068. ** Now calculate t1,t2,etc.
  2069.  
  2070.          >>> SUBA,SY      ;SZ
  2071.          STA T1           ;t1=sy-sz
  2072.          >>> ADDA,SY      ;SZ
  2073.          STA T2           ;t2=sy+sz
  2074.          >>> ADDA,SX      ;SZ
  2075.          STA T3           ;t3=sx+sz
  2076.          >>> SUBA,SX      ;SZ
  2077.          STA T4           ;t4=sx-sz
  2078.          >>> ADDA,SX      ;T2
  2079.          STA T5           ;t5=sx+t2
  2080.          >>> SUBA,SX      ;T1
  2081.          STA T6           ;t6=sx-t1
  2082.          >>> ADDA,SX      ;T1
  2083.          STA T7           ;t7=sx+t1
  2084.          >>> SUBA,T2      ;SX
  2085.          STA T8           ;t8=t2-sx
  2086.          >>> SUBA,SY      ;SX
  2087.          STA T9           ;t9=sy-sx
  2088.          >>> ADDA,SX      ;SY
  2089.          STA T10          ;t10=sx+sy
  2090.  
  2091. * Et voila!
  2092.  
  2093. *** Next, calculate A,B,C,...,I
  2094.  
  2095. ** Another useful little macro
  2096. DIV2     MAC              ;Divide a signed number by 2
  2097.                           ;It is assumed that the number
  2098.          BPL POS          ;is in the accumulator
  2099.          CLC
  2100.          EOR #$FF         ;We need to un-negative the number
  2101.          ADC #01          ;by taking it's complement
  2102.          LSR              ;divide by two
  2103.          CLC
  2104.          EOR #$FF
  2105.          ADC #01          ;Make it negative again
  2106.          JMP DONEDIV
  2107. POS      LSR              ;Number is positive
  2108. DONEDIV  <<<
  2109.  
  2110. MUL2     MAC              ;Multiply a signed number by 2
  2111.          BPL POSM
  2112.          CLC
  2113.          EOR #$FF
  2114.          ADC #$01
  2115.          ASL
  2116.          CLC
  2117.          EOR #$FF
  2118.          ADC #$01
  2119.          JMP DONEMUL
  2120. POSM     ASL
  2121. DONEMUL  <<<
  2122.  
  2123. ** Note that we are currently making a minor leap
  2124. ** of faith that no overflows will occur.
  2125.  
  2126. :CALCA   CLC
  2127.          LDX T1
  2128.          LDA COS,X
  2129.          LDX T2
  2130.          ADC COS,X
  2131.          STA A11          ;A=(cos(t1)+cos(t2))/2
  2132. :CALCB   LDX T1
  2133.          LDA SIN,X
  2134.          SEC
  2135.          LDX T2
  2136.          SBC SIN,X
  2137.          STA B12          ;B=(sin(t1)-sin(t2))/2
  2138. :CALCC   LDX SY
  2139.          LDA SIN,X
  2140.          >>> MUL2
  2141.          STA C13          ;C=sin(sy)
  2142. :CALCD   SEC
  2143.          LDX T8
  2144.          LDA COS,X
  2145.          LDX T7
  2146.          SBC COS,X
  2147.          SEC
  2148.          LDX T5
  2149.          SBC COS,X
  2150.          CLC
  2151.          LDX T6
  2152.          ADC COS,X        ;Di=(cos(t8)-cos(t7)+cos(t6)-cos(t5))/2
  2153.          >>> DIV2
  2154.          CLC
  2155.          LDX T3
  2156.          ADC SIN,X
  2157.          SEC
  2158.          LDX T4
  2159.          SBC SIN,X
  2160.          STA D21          ;D=(sin(t3)-sin(t4)+Di)/2
  2161. :CALCE   SEC
  2162.          LDX T5
  2163.          LDA SIN,X
  2164.          LDX T6
  2165.          SBC SIN,X
  2166.          SEC
  2167.          LDX T7
  2168.          SBC SIN,X
  2169.          SEC
  2170.          LDX T8
  2171.          SBC SIN,X        ;Ei=(sin(t5)-sin(t6)-sin(t7)-sin(t8))/2
  2172.          >>> DIV2
  2173.          CLC
  2174.          LDX T3
  2175.          ADC COS,X
  2176.          CLC
  2177.          LDX T4
  2178.          ADC COS,X
  2179.          STA E22          ;E=(cos(t3)+cos(t4)+Ei)/2
  2180. :CALCF   LDX T9
  2181.          LDA SIN,X
  2182.          SEC
  2183.          LDX T10
  2184.          SBC SIN,X
  2185.          STA F23          ;F=(sin(t9)-sin(t10))/2
  2186. :CALCG   LDX T6
  2187.          LDA SIN,X
  2188.          SEC
  2189.          LDX T8
  2190.          SBC SIN,X
  2191.          SEC
  2192.          LDX T7
  2193.          SBC SIN,X
  2194.          SEC
  2195.          LDX T5
  2196.          SBC SIN,X        ;Gi=(sin(t6)-sin(t8)-sin(t7)-sin(t5))/2
  2197.          >>> DIV2
  2198.          CLC
  2199.          LDX T4
  2200.          ADC COS,X
  2201.          SEC
  2202.          LDX T3
  2203.          SBC COS,X
  2204.          STA G31          ;G=(cos(t4)-cos(t3)+Gi)/2
  2205. :CALCH   CLC
  2206.          LDX T6
  2207.          LDA COS,X
  2208.          LDX T7
  2209.          ADC COS,X
  2210.          SEC
  2211.          LDX T5
  2212.          SBC COS,X
  2213.          SEC
  2214.          LDX T8
  2215.          SBC COS,X        ;Hi=(cos(t6)+cos(t7)-cos(t5)-cos(t8))/2
  2216.          >>> DIV2
  2217.          CLC
  2218.          LDX T3
  2219.          ADC SIN,X
  2220.          CLC
  2221.          LDX T4
  2222.          ADC SIN,X
  2223.          STA H32          ;H=(sin(t3)+sin(t4)+Hi)/2
  2224. :WHEW    CLC
  2225.          LDX T9
  2226.          LDA COS,X
  2227.          LDX T10
  2228.          ADC COS,X
  2229.          STA I33          ;I=(cos(t9)+cos(t10))/2
  2230.  
  2231. ** It's all downhill from here.
  2232.          JMP DOWNHILL
  2233.          TXT 'Gee Brain, what do you want to do '
  2234.          TXT 'tonight?'
  2235.  
  2236. ** Rotate, project, and store the points
  2237. DOWNHILL
  2238.  
  2239. * A neat macro
  2240. NEG      MAC              ;Change the sign of a two's complement
  2241.          CLC
  2242.          LDA ]1           ;number.
  2243.          EOR #$FF
  2244.          ADC #$01
  2245.          <<<
  2246.  
  2247. *-------------------------------
  2248. * These macros replace the previous projection
  2249. * subroutine.
  2250.  
  2251. SMULT    MAC              ;Multiply two signed 8-bit
  2252.                           ;numbers: A*Y/64 -> A
  2253.          STA Z1
  2254.          CLC
  2255.          EOR #$FF
  2256.          ADC #$01
  2257.          STA Z2
  2258.          LDA (Z1),Y
  2259.          SEC
  2260.          SBC (Z2),Y
  2261.          <<<              ;All done :)
  2262.  
  2263.  
  2264. ADDSUB   MAC              ;Add or subtract two numbers
  2265.                           ;depending on first input
  2266.          IF -=]1          ;If subtract
  2267.          SEC              ;then use this code
  2268.          SBC ]2
  2269.          ELSE             ;otherwise use this code
  2270.          CLC
  2271.          ADC ]2
  2272.          FIN
  2273.          <<<
  2274.  
  2275.  
  2276. PROJECT  MAC              ;The actual projection routine
  2277.                           ;two inputs are used (x,y)
  2278.                           ;corresponding to (+/-1,+/-1)
  2279.                           ;The third input is used to
  2280.                           ;determine if the rotated
  2281.                           ;z-coordinate should be
  2282.                           ;stored, and if so where.
  2283.                           ;The calling routine handles
  2284.                           ;changing the sign of z.
  2285.  
  2286.          LDA I33          ;Calculate rotated z:
  2287.          >>> ADDSUB,]1    ;G31 ;Add or subtract x
  2288.          >>> ADDSUB,]2    ;H32 ;Add or subtract y
  2289.          IF P,]3          ;Do we need to store the point?
  2290.          STA ]3           ;Then do so!
  2291.          FIN
  2292. * EOR #128 ;We are going to take 128+z
  2293.          TAX              ;Now it is ready for indexing
  2294.          LDA ZDIV,X       ;Table of d/(z+z0)
  2295.          TAY              ;Y now contains projection
  2296.  
  2297.          LDA C13          ;Now calculate rotated x
  2298.          >>> ADDSUB,]1    ;A11
  2299.          >>> ADDSUB,]2    ;B12
  2300.          >>> SMULT        ;Signed multiply A*Y/64->A
  2301.          CLC
  2302.          ADC #64          ;Offset the coordinate
  2303.          TAX              ;Now X is rotated x!
  2304.  
  2305.          LDA F23          ;Now it's y's turn
  2306.          >>> ADDSUB,]1    ;D21
  2307.          >>> ADDSUB,]2    ;E22
  2308.          >>> SMULT
  2309.          CLC
  2310.          ADC #64          ;Offset
  2311.          CMP YMIN         ;Figure out if it is a
  2312.          BCS NOTMIN       ;min or max value for y
  2313.          STA YMIN
  2314.          BCC NOTMAX       ;This is used in calculating
  2315. NOTMIN   CMP YMAX         ;the filled faces
  2316.          BCC NOTMAX
  2317.          STA YMAX
  2318. NOTMAX   TAY              ;Not really necessary
  2319.  
  2320.          <<<              ;All done
  2321.  
  2322.  
  2323.          LDA #64          ;Reset Ymin and Ymax
  2324.          STA YMIN
  2325.          STA YMAX
  2326.  
  2327. * P1=[1 1 1]
  2328.          >>> PROJECT,1;1;P1Z ;Rotated z stored in P1Z
  2329.          STX P1X
  2330.          STY P1Y
  2331. * P2=[1 -1 1]
  2332.          >>> PROJECT,1    ;-1;P2Z
  2333.          STX P2X
  2334.          STY P2Y
  2335. * P3=[-1 -1 1]
  2336.          >>> PROJECT,-1;-1;NOPE ;Don't store z-value
  2337.          STX P3X
  2338.          STY P3Y
  2339. * P4=[-1 1 1]
  2340.          >>> PROJECT,-1;1;P4Z
  2341.          STX P4X
  2342.          STY P4Y
  2343. * P8=[-1 1 -1]
  2344.          >>> NEG,C13
  2345.          STA C13
  2346.          >>> NEG,F23
  2347.          STA F23
  2348.          >>> NEG,I33
  2349.          STA I33
  2350.          >>> PROJECT,-1;1;NOPE
  2351.          STX P8X
  2352.          STY P8Y
  2353. * P7=[-1 -1 -1]
  2354.          >>> PROJECT,-1;-1;NOPE
  2355.          STX P7X
  2356.          STY P7Y
  2357. * P6=[1 -1 -1]
  2358.          >>> PROJECT,1;-1;NOPE
  2359.          STX P6X
  2360.          STY P6Y
  2361. * P5=[1 1 -1]
  2362.          >>> PROJECT,1;1;P5Z
  2363.          STX P5X
  2364.          STY P5Y
  2365.  
  2366. * A little macro
  2367.  
  2368. SETBUF   MAC              ;Put buffers where they can be hurt
  2369.          LDA #00
  2370.          STA BUFFER
  2371.          LDA ZTEMP        ;ztemp contains the high byte here
  2372.          STA BUFFER+1
  2373.          <<<
  2374.  
  2375. **** Clear buffer
  2376.  
  2377. * >>> SETBUF
  2378. *CLRBUF LDA #$00 ;Pretty straightforward,
  2379. * LDX #$08 ;I think
  2380. * LDY #$00
  2381. *:LOOP STA (BUFFER),Y
  2382. * INY
  2383. * BNE :LOOP
  2384. * INC BUFFER+1
  2385. * DEX
  2386. * BNE :LOOP
  2387.  
  2388. * This is the new and improved buffer clear
  2389. * routine for filled faces
  2390.  
  2391.          >>> SETBUF
  2392.          STA TEMP1+1      ;buffer2 will point to
  2393.          LDA #$80         ;buffer+128
  2394.          STA TEMP1        ;Makes life faster for us
  2395. FILCLR   LDA #00
  2396.          LDX #$08         ;We'll do it two at a time
  2397.          LDY #$00
  2398. :LOOP1   STA (BUFFER),Y
  2399.          STA (TEMP1),Y
  2400.          INY
  2401.          CPY YMIN
  2402.          BNE :LOOP1
  2403.          LDA #$FF         ;Now load with fills
  2404. :LOOP2   STA (BUFFER),Y
  2405.          STA (TEMP1),Y
  2406.          INY
  2407.          CPY YMAX
  2408.          BCC :LOOP2
  2409.          LDA #$00         ;Black out the rest
  2410. :LOOP3   STA (BUFFER),Y
  2411.          STA (TEMP1),Y
  2412.          INY
  2413.          BPL :LOOP3       ;Until Y=128
  2414.          LDY #00
  2415.          INC BUFFER+1
  2416.          INC TEMP1+1
  2417.          DEX
  2418.          BNE :LOOP1       ;Go all the way around
  2419.  
  2420. **** Now draw the lines.
  2421. **** But first check for hidden faces!
  2422. **** Remember: P1=[1 1 1] P2=[1 -1 1] P3=[-1 -1 1]
  2423. **** P4=[-1 1 1] P5=[1 1 -1] P6=[1 -1 -1] P7=[-1 -1 -1]
  2424. **** P8=[-1 1 -1]
  2425.  
  2426. LINES    LDA #00
  2427.          STA FACES        ;Hidden face counter
  2428. :FACE1   LDA K
  2429.          SEC
  2430.          SBC P1Z
  2431.          BVS :FACE6       ;Overflow already?
  2432.          CLC
  2433.          ADC P5Z          ;Is k-v1z < 0?
  2434.                           ;If not, face is invisible
  2435.          BVC :DRAW1       ;But we might have overflow
  2436.          LDA P5Z          ;Was overflow pos or neg?
  2437. :DRAW1   BPL :FACE6       ;If pos then k-v1z > 0
  2438.  
  2439.          LDA #$01         ;Otherwise, draw the
  2440.          STA FACES        ;face!
  2441.  
  2442.          LDA P1X
  2443.          STA TX1
  2444.          LDA P1Y
  2445.          STA TY1
  2446.          LDA P2X
  2447.          STA TX2
  2448.          LDA P2Y
  2449.          STA TY2
  2450.          JSR DRAW         ;P1-P2
  2451.  
  2452.          LDA P3X
  2453.          STA TX1
  2454.          LDA P3Y
  2455.          STA TY1
  2456.          JSR DRAW         ;P2-P3
  2457.  
  2458.          LDA P4X
  2459.          STA TX2
  2460.          LDA P4Y
  2461.          STA TY2
  2462.          JSR DRAW         ;P3-P4
  2463.  
  2464.          LDA P1X
  2465.          STA TX1
  2466.          LDA P1Y
  2467.          STA TY1
  2468.          JSR DRAW         ;P4-P1  Face 1 done.
  2469.          JMP :FACE2       ;If one is visible, the other
  2470.                           ;isn't.
  2471. :FACE6   LDA K
  2472.          SEC
  2473.          SBC P5Z
  2474.          BVS :FACE2
  2475.          CLC
  2476.          ADC P1Z          ;Now check if K-v6z < 0
  2477.          BVC :DRAW6       ;Love that overflow
  2478.          LDA P1Z
  2479. :DRAW6   BPL :FACE2       ;If not, go on
  2480.  
  2481.          LDA #$20
  2482.          STA FACES        ;Otherwise, draw it
  2483.  
  2484.          LDA P5X
  2485.          STA TX2
  2486.          LDA P5Y
  2487.          STA TY2
  2488.          LDA P6X
  2489.          STA TX1
  2490.          LDA P6Y
  2491.          STA TY1
  2492.          JSR DRAW         ;P5-P6
  2493.  
  2494.          LDA P7X
  2495.          STA TX2
  2496.          LDA P7Y
  2497.          STA TY2
  2498.          JSR DRAW         ;P6-P7
  2499.  
  2500.          LDA P8X
  2501.          STA TX1
  2502.          LDA P8Y
  2503.          STA TY1
  2504.          JSR DRAW         ;P7-P8
  2505.  
  2506.          LDA P5X
  2507.          STA TX2
  2508.          LDA P5Y
  2509.          STA TY2
  2510.          JSR DRAW         ;P8-P5
  2511.  
  2512. :FACE2   LDA K
  2513.          SEC
  2514.          SBC P1Z
  2515.          BVS :FACE5
  2516.          CLC
  2517.          ADC P4Z          ;K-v2z < 0?
  2518.          BVC :DRAW2
  2519.          LDA P4Z
  2520. :DRAW2   BPL :FACE5
  2521.          LDA #$02         ;If so, draw it!
  2522.          ORA FACES
  2523.          STA FACES
  2524.  
  2525.          LDX P1X          ;We're doing this this way
  2526.          STX TX1          ;to save a few cycles
  2527.          LDX P1Y
  2528.          STX TY1
  2529.  
  2530.          AND #$01         ;Shares an edge with face 1
  2531.          BNE :F2S2        ;Skip to next edge if present
  2532.  
  2533.          LDA P2X
  2534.          STA TX2
  2535.          LDA P2Y
  2536.          STA TY2
  2537.          JSR DRAW         ;P1-P2
  2538.  
  2539. :F2S2    LDX P5X
  2540.          STX TX2
  2541.          LDX P5Y
  2542.          STX TY2
  2543.          JSR DRAW         ;P1-P5
  2544.  
  2545.          LDX P6X
  2546.          STX TX1
  2547.          LDX P6Y
  2548.          STX TY1
  2549.  
  2550.          LDA FACES
  2551.          AND #$20         ;Also shares an edge with 6
  2552.          BNE :F2S4
  2553.  
  2554.          JSR DRAW         ;P5-P6
  2555.  
  2556. :F2S4    LDA P2X
  2557.          STA TX2
  2558.          LDA P2Y
  2559.          STA TY2          ;Such is face 2
  2560.          JSR DRAW         ;P6-P2
  2561.          JMP :FACE3       ;Skip 5
  2562.  
  2563. :FACE5   LDA K
  2564.          SEC
  2565.          SBC P4Z
  2566.          BVS :FACE3
  2567.          CLC
  2568.          ADC P1Z          ;Same thing again...
  2569.          BVC :DRAW5
  2570.          LDA P1Z
  2571. :DRAW5   BPL :FACE3
  2572.          LDA #$10
  2573.          ORA FACES
  2574.          STA FACES
  2575.  
  2576.          LDX P3X
  2577.          STX TX1
  2578.          LDX P3Y
  2579.          STX TY1
  2580.  
  2581.          AND #$01         ;Shares with 1
  2582.          BNE :F5S2
  2583.  
  2584.          LDA P4X
  2585.          STA TX2
  2586.          LDA P4Y
  2587.          STA TY2
  2588.          JSR DRAW         ;P3-P4
  2589.  
  2590. :F5S2    LDA P7X
  2591.          STA TX2
  2592.          LDA P7Y
  2593.          STA TY2
  2594.          JSR DRAW         ;P3-P7
  2595.  
  2596.          LDA P8X
  2597.          STA TX1
  2598.          LDA P8Y
  2599.          STA TY1
  2600.  
  2601.          LDA FACES
  2602.          AND #$20         ;Shares with 6
  2603.          BNE :F5S4
  2604.  
  2605.          JSR DRAW         ;P7-P8
  2606. :F5S4    LDA P4X
  2607.          STA TX2
  2608.          LDA P4Y
  2609.          STA TY2          ;P8-P4
  2610.          JSR DRAW         ;Two more to go!
  2611.  
  2612. :FACE3   LDA K
  2613.          SEC
  2614.          SBC P1Z
  2615.          BVS :FACE4
  2616.          CLC
  2617.          ADC P2Z
  2618.          BVC :DRAW3
  2619.          LDA P2Z
  2620. :DRAW3   BPL :FACE4       ;Ah reckon it's a'hidden, yup
  2621.          LDA #$04
  2622.          ORA FACES
  2623.          STA FACES
  2624.  
  2625.          LDX P1X
  2626.          STX TX1
  2627.          LDX P1Y
  2628.          STX TY1
  2629.  
  2630.          AND #$01         ;Shares with 1
  2631.          BNE :F3S2
  2632.  
  2633.          LDA P4X
  2634.          STA TX2
  2635.          LDA P4Y
  2636.          STA TY2
  2637.          JSR DRAW         ;P1-P4
  2638.  
  2639. :F3S2    LDX P5X
  2640.          STX TX2
  2641.          LDX P5Y
  2642.          STX TY2
  2643.  
  2644.          LDA FACES
  2645.          AND #$02         ;Shares with 2
  2646.          BNE :F3S3
  2647.  
  2648.          JSR DRAW         ;P1-P5
  2649. :F3S3    LDX P8X
  2650.          STX TX1
  2651.          LDX P8Y
  2652.          STX TY1
  2653.  
  2654.          LDA FACES
  2655.          AND #$20         ;Shares with 6
  2656.          BNE :F3S4
  2657.  
  2658.          JSR DRAW         ;P5-P8
  2659. :F3S4    LDX P4X
  2660.          STX TX2
  2661.          LDX P4Y
  2662.          STX TY2
  2663.  
  2664.          LDA FACES
  2665.          AND #$10         ;Shares with 5
  2666.          BNE FACEDONE
  2667.  
  2668.          JSR DRAW         ;P8-P4
  2669.          JMP FACEDONE
  2670.  
  2671. :FACE4   LDA K
  2672.          SEC
  2673.          SBC P2Z
  2674.          BVS FACEDONE
  2675.          CLC
  2676.          ADC P1Z
  2677.          BVC :DRAW4
  2678.          LDA P1Z
  2679. :DRAW4   BPL FACEDONE
  2680.  
  2681.          LDA P2X
  2682.          STA TX1
  2683.          LDA P2Y
  2684.          STA TY1
  2685.  
  2686.          LDA FACES
  2687.          AND #$01         ;Shares with 1
  2688.          BNE :F4S2
  2689.  
  2690.          LDA P3X
  2691.          STA TX2
  2692.          LDA P3Y
  2693.          STA TY2
  2694.          JSR DRAW         ;P2-P3
  2695.  
  2696. :F4S2    LDA P6X
  2697.          STA TX2
  2698.          LDA P6Y
  2699.          STA TY2
  2700.  
  2701.          LDA FACES
  2702.          AND #$02         ;Shares with 2
  2703.          BNE :F4S3
  2704.  
  2705.          JSR DRAW         ;P2-P6
  2706. :F4S3    LDA P7X
  2707.          STA TX1
  2708.          LDA P7Y
  2709.          STA TY1
  2710.  
  2711.          LDA FACES
  2712.          AND #$20         ;Shares with 6
  2713.          BNE :F4S4
  2714.  
  2715.          JSR DRAW         ;P6-P7
  2716. :F4S4    LDA P3X
  2717.          STA TX2
  2718.          LDA P3Y
  2719.          STA TY2
  2720.  
  2721.          LDA FACES
  2722.          AND #$10         ;Shares with 5
  2723.          BNE FACEDONE
  2724.  
  2725.          JSR DRAW         ;P7-P3
  2726. FACEDONE                  ;Whew!  Time for a beer.
  2727.  
  2728. **** Now we need to unfill the outside from the faces
  2729. UNFILL   LDY YMIN
  2730. :LOOP    >>> SETBUF
  2731.          LDX #08
  2732. :L1      LDA (BUFFER),Y
  2733.          EOR #$FF         ;Go till we find a plotted
  2734.          BNE :GOTCHA      ;point (i.e. A <> $FF)
  2735. * LDA #00 ;Unfilling as we go...
  2736.          STA (BUFFER),Y
  2737.          LDA #$80
  2738.          STA BUFFER
  2739.          LDA (BUFFER),Y
  2740.          EOR #$FF
  2741.          BNE :GOTCHA
  2742. * LDA #00
  2743.          STA (BUFFER),Y
  2744.          STA BUFFER
  2745.          INC BUFFER+1
  2746.          DEX              ;This is our safety valve
  2747.          BNE :L1          ;Really shouldn't need it
  2748.          JSR CHOKE
  2749.          JMP SWAPBUF
  2750.  
  2751. :GOTCHA                   ;A contains the EOR plot value
  2752.          STA TEMP1        ;Now find the high bit
  2753.          LDA #00
  2754. :L2      SEC
  2755.          ROL
  2756.          LSR TEMP1        ;Should really use a table
  2757.          BNE :L2          ;for this!
  2758.          AND (BUFFER),Y
  2759.          STA (BUFFER),Y
  2760.  
  2761.          LDA ZTEMP        ;Now go to the end
  2762.                           ;Carry is clear
  2763.                           ;Actually we add 7
  2764.          ADC #$06         ;16 columns of 128 bytes
  2765.          STA BUFFER+1
  2766.          LDA #$80
  2767.          STA BUFFER
  2768. :LOOP2   LDA (BUFFER),Y   ;And work backwards!
  2769.          EOR #$FF
  2770.          BNE :GOTCHA2
  2771.          STA (BUFFER),Y
  2772.          STA BUFFER       ;Stick a zero into buffer
  2773.          LDA (BUFFER),Y
  2774.          EOR #$FF
  2775.          BNE :GOTCHA2
  2776.          STA (BUFFER),Y
  2777.          LDA #$80
  2778.          STA BUFFER
  2779.          DEC BUFFER+1
  2780.          BNE :LOOP2
  2781.  
  2782. :GOTCHA2 STA TEMP1        ;Again find the high bit
  2783.          LDA #00
  2784. :L3      SEC
  2785.          ROR
  2786.          ASL TEMP1
  2787.          BNE :L3
  2788.          AND (BUFFER),Y
  2789.          STA (BUFFER),Y
  2790.  
  2791.          INY              ;Now keep going
  2792.          CPY YMAX
  2793.          BCC :LOOP        ;Until we hit ymax!
  2794.          BEQ :LOOP        ;We need the last one too.
  2795.  
  2796. **** Swap buffers
  2797.  
  2798. SWAPBUF  LDA VMCSB
  2799.          EOR #$02         ;Pretty tricky, eh?
  2800.          STA VMCSB
  2801.          LDA #$08
  2802.          EOR ZTEMP        ;ztemp=high byte just flips
  2803.          STA ZTEMP        ;between $30 and $38
  2804.  
  2805.          JMP MAIN         ;Around and around we go...
  2806.  
  2807.          TXT 'Same thing we do every night, Pinky: '
  2808.          TXT 'try to take over the world!'
  2809.  
  2810.  
  2811. *-------------------------------
  2812. * General questionable-value error procedure
  2813.  
  2814. CHOKE    LDX #00
  2815. :LOOP    LDA :CTEXT,X
  2816.          BEQ :DONE
  2817.          JSR CHROUT
  2818.          INX
  2819.          JMP :LOOP
  2820. :DONE    RTS
  2821. :CTEXT   HEX 0D           ;CR
  2822.          TXT 'something choked :('
  2823.          HEX 0D00
  2824.  
  2825.          TXT 'Narf!'
  2826.  
  2827. *-------------------------------
  2828. * Drawin' a line.  A fahn lahn.
  2829.  
  2830. *** Some useful macros
  2831.  
  2832. PLOTPX   MAC              ;plot a point in x
  2833.          PHA              ;Use this one every time
  2834.          LDA BITP,X       ;X is increased
  2835.          BMI C1
  2836.          LDA #$80         ;Table has been rearranged
  2837.          EOR BUFFER       ;for filling faces
  2838.          STA BUFFER
  2839.          BMI C2
  2840.          INC BUFFER+1
  2841. C2       LDA #%01111111   ;Note that this is changed
  2842. C1       AND (BUFFER),Y   ;for plotting filled faces
  2843.          STA (BUFFER),Y
  2844.          PLA              ;Need to save A!
  2845.          <<<
  2846.  
  2847. PLOTPY   MAC              ;Plot a point in y: simpler and necessary!
  2848.          PHA              ;Use this one when you just increase Y
  2849.          LDA BITP,X       ;but X doesn't change
  2850.          AND (BUFFER),Y
  2851.          STA (BUFFER),Y
  2852.          PLA
  2853.          <<<
  2854.  
  2855. CINIT    MAC              ;Macro to initialize the counter
  2856.          LDA ]1           ;dx or dy
  2857.          LSR
  2858.          EOR #$FF         ;(Not really two's complement)
  2859.          ADC #$01         ;A = 256-dx/2 or 256-dy/2
  2860.          <<<              ;The dx/2 makes a nicer looking line
  2861.  
  2862. XSTEP    MAC              ;Macro to take a step in X
  2863. XLOOP    INX
  2864.          ADC DY
  2865.          BCC L1
  2866. * Do we use INY or DEY here?
  2867.          IF I,]1          ;If the first character is an 'I'
  2868.          INY
  2869.          ELSE
  2870.          DEY
  2871.          FIN
  2872.          SBC DX
  2873. L1       >>> PLOTPX       ;Always take a step in X
  2874.          CPX X2
  2875.          BNE XLOOP
  2876.          <<<
  2877.  
  2878. YSTEP    MAC              ;Same thing, but for Y
  2879. YLOOP    IF I,]1
  2880.          INY
  2881.          ELSE
  2882.          DEY
  2883.          CLC              ;Very important!
  2884.          FIN
  2885.          ADC DX
  2886.          BCC L2
  2887.          INX              ;Always increase X
  2888.          SBC DY
  2889.          >>> PLOTPX
  2890.          JMP L3
  2891. L2       >>> PLOTPY       ;We only increased Y
  2892. L3       CPY Y2
  2893.          BNE YLOOP
  2894.          <<<
  2895.  
  2896. **** Initial line setup
  2897.  
  2898. DRAW     >>> MOVE,TX1     ;X1  ;Move stuff into zero page
  2899.          >>> MOVE,TX2     ;X2  ;Where it can be modified
  2900.          >>> MOVE,TY1     ;Y1
  2901.          >>> MOVE,TY2     ;Y2
  2902.          >>> SETBUF       ;Now we can clobber the buffer
  2903.  
  2904.          SEC              ;Make sure x1<x2
  2905.          LDA X2
  2906.          SBC X1
  2907.          BCS :CONT
  2908.          LDA Y2           ;If not, swap P1 and P2
  2909.          LDY Y1
  2910.          STA Y1
  2911.          STY Y2
  2912.          LDA X1
  2913.          LDY X2
  2914.          STY X1
  2915.          STA X2
  2916.  
  2917.          SEC
  2918.          SBC X1           ;Now A=dx
  2919. :CONT    STA DX
  2920.          LDX X1           ;Put x1 into X, now we can trash X1
  2921.  
  2922. COLUMN   LDA X1           ;Find the first column for X
  2923.          LSR              ;(This can be made much faster!)
  2924.          LSR              ;There are x1/8 128 byte blocks
  2925.          LSR              ;Which means x1/16 256 byte blocks
  2926.          LSR
  2927.          BCC :EVEN        ;With a possible extra 128 byte block
  2928.          LDY #$80         ;if so, set the high bit
  2929.          STY BUFFER
  2930.          CLC
  2931. :EVEN    ADC BUFFER+1     ;Add in the number of 256 byte blocks
  2932.          STA BUFFER+1     ;And store it!
  2933.  
  2934.          SEC
  2935.          LDA Y2           ;Calculate dy
  2936.          SBC Y1
  2937.          BCS :CONT2       ;Is y2>y1?
  2938.          EOR #$FF         ;Otherwise dy=y1-y2
  2939.          ADC #$01
  2940. :CONT2   STA DY
  2941.          CMP DX           ;Who's bigger: dy or dx?
  2942.          BCS STEPINY      ;If dy, we need to take big steps in y
  2943.  
  2944. STEPINX  LDY Y1           ;X is already set to x1
  2945.          LDA BITP,X       ;Plot the first point
  2946.          AND (BUFFER),Y
  2947.          STA (BUFFER),Y
  2948.          >>> CINIT,DX     ;Initialize the counter
  2949.          CPY Y2
  2950.          BCS XDECY        ;Do we step forwards or backwards in Y?
  2951.  
  2952. XINCY    >>> XSTEP,INY
  2953.          RTS
  2954.  
  2955. STEPINY  LDY Y1           ;Well, a little repetition never hurt anyone
  2956.          LDA BITP,X
  2957.          AND (BUFFER),Y
  2958.          STA (BUFFER),Y
  2959.          >>> CINIT,DY
  2960.          CPY Y2
  2961.          BCS YDECY
  2962.  
  2963. YINCY    >>> YSTEP,INY
  2964.          RTS
  2965.  
  2966. XDECY    >>> XSTEP,DEY    ;This is put here so that
  2967.          RTS              ;Branches are legal
  2968.  
  2969. YDECY    >>> YSTEP,DEY
  2970.          RTS
  2971.  
  2972.  
  2973. *-------------------------------
  2974. * Clean up
  2975.  
  2976. CLEANUP  LDA VMCSB        ;Switch char rom back in
  2977.          AND #%11110101   ;default
  2978.          STA VMCSB
  2979.  
  2980.          RTS              ;bye!
  2981.  
  2982.          TXT 'Happy Holidays! '
  2983.          TXT 'slj 12/94'
  2984.  
  2985. *-------------------------------
  2986. * Set up bit table
  2987.  
  2988.          DS ^             ;Clear to end of page
  2989.                           ;So that tables start on a page boundary
  2990. BITP     LUP 16           ;128 Entries for X
  2991.          DFB %01111111
  2992.          DFB %10111111
  2993.          DFB %11011111
  2994.          DFB %11101111
  2995.          DFB %11110111
  2996.          DFB %11111011
  2997.          DFB %11111101
  2998.          DFB %11111110
  2999.          --^
  3000.  
  3001. SIN                       ;Table of sines, 120 bytes
  3002. COS      EQU SIN+128      ;Table of cosines
  3003.                           ;Both of these trig tables are
  3004.                           ;currently set up from BASIC
  3005. ZDIV     EQU COS+128      ;Division table
  3006. TMATH    EQU ZDIV+384     ;Math table of f(x)=x*x/256
  3007.  
  3008. And here are the native C64 files:
  3009.  
  3010.  
  3011. begin 600 cube3d2.0.lnx.uu
  3012. M`0A;"`H`ES4S,C@P+#`ZES4S,C@Q+#`ZES8T-BS"*#$V,BDZF2*3$1$1$1$1
  3013. M$1$B.IDB("`@("!54T4@3%E.6"!43R!$25-33TQ612!42$E3($9)3$4B.HDQ
  3014. M,`````T@,B`@*DQ93E@@6$E)($)9(%=)3$P@0T]23$59#2`U(`U#54)%,T0R
  3015. M+C`N3Z"@H*"@#2`Q,R`-4`T@,34U(`U#54)%,T0R+C`N4Z"@H*"@#2`X-B`-
  3016. M4`T@,C$X(`U#54)%,T0R+C$N3Z"@H*"@#2`Q,R`-4`T@,34U(`U)3DE4,T0R
  3017. M+C"@H*"@H*"@#2`Q,"`-4`T@-3`@#4Y/5$53,BXPH*"@H*"@H*`-(#0@#5`-
  3018. M(#$Y,R`-````````````````````````````````````````````````````
  3019. M````````````````````````````````````````````````````````````
  3020. M````````````````````````````````````````````````````````````
  3021. M````````````````````````````````````````````````````````````
  3022. M````````````````````````````````````````````````````````````
  3023. M``````````````````"`J0"-(-"-(="M&-`I#PD0C1C0H`"I'X7[J8"%_$Q9
  3024. M@9,%$1$1("`@("`@("`@("`@($-50D4S1"!6,BXP#0T@("`@("`@("`@("`@
  3025. M("`@("!"60V?("`@(%-415!(14X@2E5$1)D@("`@1T5/4D=%(%1!64Q/4@T-
  3026. MFR`@0TA%0TL@3U54(%1(12!*04XN(#DU($E34U5%($]b@($,]2$%#2TE.
  3027. M1YL@1D]2($U/4D4@1$5404E,4R$-#1T=GA)&,2]&,I(@+2!)3D,O1$5#(%@M
  3028. M4D]4051)3TX-'1T21C,O1C22("T@24Y#+T1%0R!9+5)/5$%424].#1T=$D8U
  3029. M+T8VDB`M($E.0R]$14,@6BU23U1!5$E/3@T='1)&-Y(@4D531513#2`@4%)%
  3030. M4U,@42!43R!154E4#0T%("`@("`@4%)%4U,@04Y9($M%62!43R!"14=)3@T`
  3031. ML?OP*2#2_\C0]N;\3%F!=$A)4R!)4R!!(%-%0U)%5"!415A4($U%4U-!1T4A
  3032. M(.3_R0#P^:F/A2.%):D!C2'0J9,@TO^I`(TAT*E`:0R%^ZD%A?RI`*``H@`8
  3033. MD?O(:1"0^1BE^VDHA?NE_&D`A?R@`.B*X!#0Y*D`A:.I,(6DA0*M&-`I\0D.
  3034. MC1C0J0"%885BA6.%9(5EA698(.3_R870"Z5AR3SP6.9A3%>"R8G0":5A\$O&
  3035. M84Q7@LF&T`NE8LD\\#SF8DQ7@LF*T`FE8O`OQF),5X+)A]`+I6/)//`@YF-,
  3036. M5X+)B]`)I6/P$\9C3%>"R8C0`TSC@<E1T`-,7(MX&*5D96')>)`"Z7B%9!BE
  3037. M965BR7B0`NEXA648I69E8\EXD`+I>(5F.*5EY6:P`FEXA6<8I65E9LEXD`+I
  3038. M>(5H&*5D96;)>)`"Z7B%:3BE9.5FL`)I>(5J&*5D96C)>)`"Z7B%:SBE9.5G
  3039. ML`)I>(5L&*5D96?)>)`"Z7B%;3BE:.5DL`)I>(5N.*5EY62P`FEXA6\8I61E
  3040. M9<EXD`+I>(5P&*9GO0"-IFA]`(V%I:9GO8",.*9H_8",A::F9;V`C!`.&$G_
  3041. M:0$*&$G_:0%,)X,*A:<XIFZ]`(VF;?T`C3BF:_T`C1BF;'T`C1`.&$G_:0%*
  3042. M&$G_:0%,48-*&*9I?8",.*9J_8",A:@XIFN]@(RF;/V`C#BF;?V`C#BF;OV`
  3043. MC!`.&$G_:0%*&$G_:0%,AX-*&*9I?0"-&*9J?0"-A:FF;[V`C#BF</V`C(6J
  3044. MIFR]@(PXIF[]@(PXIFW]@(PXIFO]@(P0#AA)_VD!2AA)_VD!3,J#2ABF:GT`
  3045. MC3BF:?T`C86K&*9LO0"-IFU]`(TXIFO]`(TXIF[]`(T0#AA)_VD!2AA)_VD!
  3046. M3`"$2ABF:7V`C!BF:GV`C(6L&*9OO0"-IG!]`(V%K4Q(A&=%12!B4D%)3BP@
  3047. M5TA!5"!$3R!93U4@5T%.5"!43R!$3R!43TY)1TA4/ZE`A?>%^*6M&&6K&&6L
  3048. MA5>JO8"-J*6G&&6E&&6FA2(82?]I`84DL2(X\208:4"JI:H89:@89:F%(AA)
  3049. M_VD!A22Q(CCQ)!AI0,7WL`2%]Y`&Q?B0`H7XJ(:2A).EK1AEJSCEK(58JKV`
  3050. MC:BEIQAEI3CEIH4B&$G_:0&%)+$B./$D&&E`JJ6J&&6H..6IA2(82?]I`84D
  3051. ML2(X\208:4#%][`$A?>0!L7XD`*%^*B&E(25I:TXY:LXY:RJO8"-J*6G..6E
  3052. M..6FA2(82?]I`84DL2(X\208:4"JI:HXY:@XY:F%(AA)_VD!A22Q(CCQ)!AI
  3053. M0,7WL`2%]Y`&Q?B0`H7XJ(:6A*ZEK3CEJQAEK(59JKV`C:BEISCEI1AEIH4B
  3054. M&$G_:0&%)+$B./$D&&E`JJ6J..6H&&6IA2(82?]I`84DL2(X\208:4#%][`$
  3055. MA?>0!L7XD`*%^*B&KX2P&*6G2?]I`86G&*6J2?]I`86J&*6M2?]I`86MI:TX
  3056. MY:L89:RJO8"-J*6G..6E&&6FA2(82?]I`84DL2(X\208:4"JI:HXY:@89:F%
  3057. M(AA)_VD!A22Q(CCQ)!AI0,7WL`2%]Y`&Q?B0`H7XJ(91A%*EK3CEJSCEK*J]
  3058. M@(VHI:<XY:4XY::%(AA)_VD!A22Q(CCQ)!AI0*JEJCCEJ#CEJ84B&$G_:0&%
  3059. M)+$B./$D&&E`Q?>P!(7WD`;%^)`"A?BHAG&$4*6M&&6K..6LJKV`C:BEIQAE
  3060. MI3CEIH4B&$G_:0&%)+$B./$D&&E`JJ6J&&6H..6IA2(82?]I`84DL2(X\208
  3061. M:4#%][`$A?>0!L7XD`*%^*B&LX2TI:T89:L89:R%8*J]@(VHI:<89:489::%
  3062. M(AA)_VD!A22Q(CCQ)!AI0*JEJAAEJ!AEJ84B&$G_:0&%)+$B./$D&&E`Q?>P
  3063. M!(7WD`;%^)`"A?BHAK&$LJD`A:.E`H6DA?RI@(7[J0"B"*``D:.1^\C$]]#W
  3064. MJ?^1HY'[R,3XD/>I`)&CD?O($/F@`.:DYOS*T-JI`(6UI;8XY5=P1!AE8%`"
  3065. MI6`0.ZD!A;6EDH4_I9.%0*64A4&EE85"(#.*I9:%/Z6NA4`@,XJEKX5!I;"%
  3066. M0B`SBJ62A3^EDX5`(#.*3-J'I;8XY6!P01AE5U`"I5<0.*D@A;6EL85!I;*%
  3067. M0J6SA3^EM(5`(#.*I7&%0:50A4(@,XJE484_I5*%0"`SBJ6QA4&ELH5"(#.*
  3068. MI;8XY5=P4!AE65`"I5D01ZD"!;6%M::2AC^FDX9`*0'0"Z64A4&EE85"(#.*
  3069. MIK&&0::RAD(@,XJFLX8_IK2&0*6U*2#0`R`SBJ64A4&EE85"(#.*3(6(I;8X
  3070. MY5EP31AE5U`"I5<01*D0!;6%M::6AC^FKH9`*0'0"Z6OA4&EL(5"(#.*I7&%
  3071. M0:50A4(@,XJE484_I5*%0*6U*2#0`R`SBJ6OA4&EL(5"(#.*I;8XY5=P7!AE
  3072. M6%`"I5@04ZD$!;6%M::2AC^FDX9`*0'0"Z6OA4&EL(5"(#.*IK&&0::RAD*E
  3073. MM2D"T`,@,XJF488_IE*&0*6U*2#0`R`SBJ:OAD&FL(9"I;4I$-!B(#.*3$2)
  3074. MI;8XY5AP51AE5U`"I5<03*64A3^EE85`I;4I`=`+I9:%0:6NA4(@,XJELX5!
  3075. MI;2%0J6U*0+0`R`SBJ5QA3^E4(5`I;4I(-`#(#.*I9:%0:6NA4*EM2D0T`,@
  3076. M,XJD]ZD`A:.E`H6DH@BQHTG_T!N1HZF`A:.QHTG_T`^1HX6CYJ3*T.4@"8I,
  3077. MN(F%^ZD`."I&^]#Z,:.1HZ4":0:%I*F`A:.QHTG_T!21HX6CL:-)_]`*D:.I
  3078. M@(6CQJ30YH7[J0`X:@;[T/HQHY&CR,3XD)#PCJT8T$D"C1C0J0A%`H4"3/&!
  3079. M<T%-12!42$E.1R!712!$3R!%5D5262!.24=(5"P@<$E.2UDZ(%1262!43R!4
  3080. M04M%($]615(@5$A%(%=/4DQ$(:(`O1B*\`<@TO_H3`N*8`U33TU%5$A)3D<@
  3081. M0TA/2T5$(#HH#0!N05)&(:4_A?NE087]I4"%_*5"A?ZI`(6CI0*%I#BE_>7[
  3082. ML!.E_J3\A?R$_J7[I/V$^X7]..7[A?FF^Z7[2DI*2I`%H("$HQAEI(6D.*7^
  3083. MY?RP!$G_:0&%^L7YL#BD_+T`C#&CD:.E^4I)_VD!Q/ZP:.AE^I`#R.7Y2+T`
  3084. MC#`,J8!%HX6C,`+FI*E_,:.1HVCD_=#=8*3\O0",,:.1HZ7Z2DG_:0'$_K!4
  3085. MR&7YD!WHY?I(O0",,`RI@$6CA:,P`N:DJ7\QHY&C:$P"BTB]`(PQHY&C:,3^
  3086. MT-%@Z&7ZD`.(Y?E(O0",,`RI@$6CA:,P`N:DJ7\QHY&C:.3]T-U@B!AE^9`=
  3087. MZ.7Z2+T`C#`,J8!%HX6C,`+FI*E_,:.1HVA,5XM(O0",,:.1HVC$_M#08*T8
  3088. MT"GUC1C08&A!4%!9(&A/3$E$05E3(2!33$H@,3(O.30`````````````````
  3089. M````````````````````````````````````````````````````````````
  3090. M````````````````````````````````````````````````````````````
  3091. M````````````````````````````````````?[_?[_?[_?Y_O]_O]_O]_G^_
  3092. MW^_W^_W^?[_?[_?[_?Y_O]_O]_O]_G^_W^_W^_W^?[_?[_?[_?Y_O]_O]_O]
  3093. M_G^_W^_W^_W^?[_?[_?[_?Y_O]_O]_O]_G^_W^_W^_W^?[_?[_?[_?Y_O]_O
  3094. M]_O]_G^_W^_W^_W^?[_?[_?[_?X!A?K%^;`XI/R]`(PQHY&CI?E*2?]I`<3^
  3095. ML&CH9?J0`\CE^4B]`(PP#*F`1:.%HS`"YJ2I?S&CD:-HY/W0W6"D_+T`C#&C
  3096. MD:.E^DI)_VD!Q/ZP5,AE^9`=Z.7Z2+T`C#`,J8!%`'`J*BHJ*BHJ*BHJ*BHJ
  3097. M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*@TJH*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@
  3098. MH*"@H*"@*@TJH'-415!(14Z@:E5$1*"@H*"@H*"@H*"@H*"@H*"@*@TJH&=%
  3099. M3U)'1:!T05E,3U*@H*"@H*"@H*"@H*"@H*"@*@TJH'-405)4140ZH#<O,3$O
  3100. M.32@H*"@H*"@H*"@H*"@*@TJH&9)3DE32$5$.J`W+S$Y+SDTH*"@H*"@H*"@
  3101. MH*"@*@TJH%8R+C"@8T]-4$Q%5$5$.J`Q,B\Q-R\Y-*"@H*"@*@TJH*"@H*"@
  3102. MH*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@*@TJH'=%3$PLH$E&H$%,3*!'3T53
  3103. MH%=%3$R@5$A)4Z"@*@TJH%!23T=204V@5TE,3*!23U1!5$6@0:!#54)%+J"@
  3104. M*@TJH*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@*@TJH%8R+C"@*Z!N
  3105. M15>@04Y$H&E-4%)/5D5$(:"@H*"@*@TJH&Y/5Z!7251(H$9!4U1%4J!23U54
  3106. M24Y%4RR@H*"@*@TJH$A)1$1%3J!355)&04-%4RR@1DE,3$5$H*"@H*"@*@TJ
  3107. MH$9!0T53+*!!3D2@15A44D&@5$]0H%-%0U)%5*"@*@TJH%1%6%2@34534T%'
  3108. M15,AH*"@H*"@H*"@H*"@H*"@*@TJH*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@
  3109. MH*"@H*"@*@TJH'1(25.@4%)/1U)!3:!)4Z!)3E1%3D1%1*!43Z"@*@TJH$%#
  3110. M0T]-4$%.6:!42$6@05)424-,1:!)3J"@H*"@*@TJH&,]:$%#2TE.1RR@:D%.
  3111. M+J`Y-:!)4U-512Z@H*"@*@TJH&9/4J!$151!24Q3H$].H%1(25.@4%)/1U)!
  3112. M32R@*@TJH%)%042@5$A%H$%25$E#3$4AH*"@H*"@H*"@H*"@*@TJH*"@H*"@
  3113. MH*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@*@TJH'=2251%H%1/H%53(:"@H*"@
  3114. MH*"@H*"@H*"@H*"@*@TJH*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@
  3115. M*@TJH&U94T5,1J!72$5.H%E/54Y'H$1)1*"@H*"@H*"@*@TJH$5!1T523%F@
  3116. M1E)%455%3E2@H*"@H*"@H*"@H*"@*@TJH&1/0U1/4J!!3D2@<T%)3E0LH$%.
  3117. M1*!(14%21*"@*@TJH$=214%4H&%21U5-14Y4H*"@H*"@H*"@H*"@H*"@*@TJ
  3118. MH*!A0D]55*!)5*!!3D2@04)/550ZH$)55*"@H*"@*@TJH*!%5D5234]21:"@
  3119. MH*"@H*"@H*"@H*"@H*"@H*"@*@TJH&-!346@3U54H$)9H%1(1:!304U%H&1/
  3120. M3U*@H*"@*@TJH$%3H$E.H&F@5T5.5"Z@H*"@H*"@H*"@H*"@H*"@*@TJH*"@
  3121. MH"V@<E5"04E9052@H*"@H*"@H*"@H*"@H*"@*@TJH*"@H*"@H*"@H*"@H*"@
  3122. MH*"@H*"@H*"@H*"@H*"@*@TJH'1(3U5'2*!IH%-014%+H%=)5$B@5$A%H*"@
  3123. MH*"@*@TJH%1/3D=515.@3T:@345.H$%.1*!/1J!!3D=,15.@*@TJH$%.1*!(
  3124. M059%H$Y/5*!,3U9%+*!IH$%-H*"@H*"@*@TJH$)%0T]-1:!!4Z!33U5.1$E.
  3125. M1Z!"4D%34RR@3U*@*@TJH$&@5$E.2TQ)3D>@0UE-0D%,+J"@H*"@H*"@H*"@
  3126. M*@TJH*"@H"V@,:!C3U))3E1(24%.4Z`Q,Z"@H*"@H*"@*@TJH*"@H*"@H*"@
  3127. MH*"@H*"@H*"@H*"@H*"@H*"@H*"@*@TJH'`N<RZ@=$A)4Z!705.@5U))5%1%
  3128. M3J!54TE.1Z"@*@TJH*"@H*"@;4523$E.H#$R."Z@H*"@H*"@H*"@H*"@*@TJ
  3129. M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*@T-(&]R9R`D.#`P,`T-
  3130. M*J!C3TY35$%.5%,-#6)U9F8Q(&5Q=2`D,S`P,"`[9DE24U2@0TA!4D%#5$52
  3131. MH%-%5`UB=69F,B!E<74@)#,X,#`@.W-%0T].1*!#2$%204-415*@4T54#6)U
  3132. M9F9E<B!E<74@)&$S(#MP4D5354U!0DQ9H%1(1:!405!%H%=/3B=4H$)%H%)5
  3133. M3DY)3D<->#$@97%U("1F8B`[<$])3E13H$9/4J!$4D%724Y'H$&@3$E.10UY
  3134. M,2!E<74@)&9C(#MT2$531:!:15)/H%!!1T6@041$4D534T53#7@R(&5Q=2`D
  3135. M9F0@.T1/3B=4H$-/3D9,24-4H%=)5$B@8F%S:6,->3(@97%U("1F90UD>"!E
  3136. M<74@)&8Y#61Y(&5Q=2`D9F$-=&5M<#$@97%U("1F8B`[;T:@0T]54E-%+*!#
  3137. M3U5,1*!#3TY&3$E#5*!7251(H%@Q#71E;7`R(&5Q=2`D9F,@.W1%35!/4D%2
  3138. M6:!605))04),15,->G1E;7`@97%U("0P,B`[=5-%1*!&3U*@0E5&1D52H%-7
  3139. M05`NH*!D3TXG5*!43U5#2"X->C$@97%U("0R,B`[=5-%1*!"6:!-051(H%)/
  3140. M551)3D4->C(@97%U("0R-"`[9$].)U2@5$]50TB@5$A%4T6@14E42$52(0UK
  3141. M(&5Q=2`D8C8@.V-/3E-404Y4H%53142@1D]2H$A)1$1%3@T@("`[4U521D%#
  3142. M1:!$151%0U1)3TZ@+:!$3TXG5*!43U5#2`UF86-E<R!E<74@)&(U(#MU4T5$
  3143. MH$E.H$A)1$1%3J!355)&04-%4RX->6UI;B!E<74@)&8W(#MU4T5$H$E.H$9)
  3144. M3$Q%1*!&04-%4Z`M+:!!4PUY;6%X(&5Q=2`D9C@@.U5354%,+*!$3TXG5*!4
  3145. M3U5#2`UA;F=M87@@97%U(#$R,"`[=$A%4D6@05)%H#(J4$DO04Y'34%8H$%.
  3146. M1TQ%4PT-*J!V:6,-#79M8W-B(&5Q=2`D9#`Q.`UB:V=N9"!E<74@)&0P,C`-
  3147. M8F]R9&5R(&5Q=2`D9#`R,0US<W1A<G0@97%U(#$S-#0@.U)/5Z`YH$E.H%-#
  3148. M4D5%3J!-14U/4EF@052@,3`R-`T-#2J@:T523D%,#0UC:')O=70@97%U("1F
  3149. M9F0R#6=E=&EN(&5Q=2`D9F9E-`T-*J!S3TU%H%9!4DE!0DQ%4PT-='@Q(#T@
  3150. M)#-F#71Y,2`]("0T,`UT>#(@/2`D-#$-='DR(#T@)#0R#7`Q>"`]("0Y,B`[
  3151. M=$A%4T6@05)%H%1%35!/4D%26:!35$]204=%#7`Q>2`]("0Y,R`[=5-%1*!)
  3152. M3J!03$]45$E.1Z!42$6@4%)/2D5#5$E/3@UP,G@@/2`D.30-<#)Y(#T@)#DU
  3153. M(#MT2$59H$%21:!(15)%H%-/H%1(052@5T4-<#-X(#T@)#DV(#M$3TXG5*!(
  3154. M059%H%1/H%)%0T%,0U5,051%H%1(14TN#7`S>2`]("1A90UP-'@@/2`D868@
  3155. M.W1(15F@34%+1:!,249%H$5!4UDN#7`T>2`]("1B,`UP-7@@/2`D8C$@.W=(
  3156. M6:!!4D6@64]5H$Q/3TM)3D>@052@346@3$E+1:!42$%4/PUP-7D@/2`D8C(@
  3157. M.V1/3B=4H%E/5:!44E535*!-13\-<#9X(#T@)&(S#7`V>2`]("1B-"`[:$%6
  3158. M24Y'H$%.3U1(15*@0TA)3$2@5T%33B=4H$U9H$E$14$N#7`W>"`]("0W,0UP
  3159. M-WD@/2`D-3`-<#AX(#T@)#4Q#7`X>2`]("0U,@UP,7H@/2`D-3<@.W1(15-%
  3160. MH$%21:!:+4-/3U)$24Y!5$53#7`R>B`]("0U."`[=T6@3TY,6:!.145$H%1(
  3161. M15-%H$9/55*@5$^@0TA%0TL-<#1Z(#T@)#4Y(#M&3U*@2$E$1$5.H$9!0T53
  3162. M#7`U>B`]("0V,`UD<W@@/2`D-C$@.V1S>*!)4Z!42$6@24Y#4D5-14Y4H$9/
  3163. M4@T@("`[4D]4051)3D>@05)/54Y$H%@-9'-Y(#T@)#8R(#MS24U)3$%2H$9/
  3164. M4J!D<WDLH&1S>@UD<WH@/2`D-C,-<W@@/2`D-C0@.W1(15-%H$%21:!42$6@
  3165. M04-454%,H$%.1TQ%4Z!)3J!8H%F@04Y$H%H-<WD@/2`D-C4-<WH@/2`D-C8-
  3166. M=#$@/2`D-C<@.W1(15-%H$%21:!54T5$H$E.H%1(1:!23U1!5$E/3@UT,B`]
  3167. M("0V.`UT,R`]("0V.2`[<T5%H%1(1:!!4E1)0TQ%H$9/4J!-3U)%H$1%5$%)
  3168. M3%,-=#0@/2`D-F$-=#4@/2`D-F(-=#8@/2`D-F,-=#<@/2`D-F0-=#@@/2`D
  3169. M-F4-=#D@/2`D-F8-=#$P(#T@)#<P#6$Q,2`]("1A-2`[=$A%4T6@05)%H%1(
  3170. M1:!%3$5-14Y44Z!/1J!42$6@4D]4051)3TZ@34%44DE8#6(Q,B`]("1A-B`[
  3171. M>'EZ#6,Q,R`]("1A-PUD,C$@/2`D83@@.W1(1:!.54U"15*@1$5.3U1%4Z`H
  3172. M4D]7+$-/3%5-3BD-93(R(#T@)&$Y#68R,R`]("1A80UG,S$@/2`D86(-:#,R
  3173. M(#T@)&%C#6DS,R`]("1A9`T-#2HJ*J!M04-23U,-#6UO=F4@;6%C#2!L9&$@
  3174. M73$-('-T82!=,@T@/#P\#0UG971K97D@;6%C("`[=T%)5*!&3U*@0:!+15E0
  3175. M4D534PUW86ET(&IS<B!G971I;@T@8VUP(",P,`T@8F5Q('=A:70-(#P\/`T-
  3176. M9&5B=6<@;6%C("`[<%))3E2@0:!#2$%204-415(-H"!D;Z`P("`[9$].)U2@
  3177. M05-314U"3$4-#2!L9&$@(UTQ#2!J<W(@8VAR;W5T#2`^/CX@9V5T:V5Y(#MA
  3178. M3D2@5T%)5*!43Z!#3TY424Y510T@8VUP(",G4R<@.VU9H%-%0U)%0U2@4U=)
  3179. M5$-(H$M%60T@8FYE(&PQ#2!J<W(@8VQE86YU<`T@:FUP(&1O;F4-;#$@8VUP
  3180. M(",G6"<@.VU9H%-%0U)%5*!!0D]25*!+15D-(&)N92!D;VYE#2!J;7`@8VQE
  3181. M86YU<`T@9FEN#61O;F4@/#P\#0UD96)U9V$@;6%C#2!D;Z`P#2!L9&$@73$-
  3182. M('-T82`Q,#(T#2!F:6X-9&]N96$@/#P\#0TJ+2TM+2TM+2TM+2TM+2TM+2TM
  3183. M+2TM+2TM+2TM+2TM+0T-(&QD82`C)#`P#2!S=&$@8FMG;F0-('-T82!B;W)D
  3184. M97(-(&QD82!V;6-S8@T@86YD(",E,#`P,#$Q,3$@.W-#4D5%3J!-14U/4EF@
  3185. M5$^@,3`R-`T@;W)A(",E,#`P,3`P,#`-('-T82!V;6-S8@T-(&QD>2`C,#`-
  3186. M(&QD82`C/'1T97AT#2!S=&$@=&5M<#$-(&QD82`C/G1T97AT#2!S=&$@=&5M
  3187. M<#(-(&IM<"!T:71L90UT=&5X="!H97@@.3,P-3$Q,3$Q,2`[0TQ%05*@4T-2
  3188. M145.+*!72$E412R@0U)34J!$3@T@='AT(">@H*"@H*"@H*"@H*"@0U5"13-$
  3189. MH%8R+C`G+#!$+#!$#2!T>'0@)Z"@H*"@H*"@H*"@H*"@H*"@H$)9)RPP1`T@
  3190. M:&5X(#EF(#M#64%.#2!T>'0@)Z"@H*!35$502$5.H$I51$0G#2!H97@@.3D-
  3191. M('1X="`GH*"@H$=%3U)'1:!405E,3U(G+#!$+#!$#2!H97@@.6(-('1X="`G
  3192. MH*!#2$5#2Z!/552@5$A%H$I!3BZ@.36@25-3546@3T8G+#!$#2!H97@@.38-
  3193. M('1X="`GH*!#/4A!0TM)3D<G#2!H97@@.6(-('1X="`GH$9/4J!-3U)%H$1%
  3194. M5$%)3%,A)RPP1`T@:&5X(#!D,60Q9#EE,3(-('1X="`G1C$O1C(G+#DR#2!T
  3195. M>'0@)Z`MH$E.0R]$14.@6"U23U1!5$E/3B<L,$0-(&AE>"`Q9#%D,3(-('1X
  3196. M="`G1C,O1C0G+#DR#2!T>'0@)Z`MH$E.0R]$14.@62U23U1!5$E/3B<L,$0-
  3197. M(&AE>"`Q9#%D,3(-('1X="`G1C4O1C8G+#DR#2!T>'0@)Z`MH$E.0R]$14.@
  3198. M6BU23U1!5$E/3B<L,$0-(&AE>"`Q9#%D,3(-('1X="`G1C<G+#DR#2!T>'0@
  3199. M)Z!215-%5%,G+#!$#2!T>'0@)Z"@4%)%4U.@4:!43Z!154E4)RPP1`T@:&5X
  3200. M(#!D,#4-('1X="`GH*"@H*"@4%)%4U.@04Y9H$M%6:!43Z!"14=)3B<L,$0-
  3201. M(&AE>"`P,`UT:71L92!L9&$@*'1E;7`Q*2QY#2!B97$@.F-O;G0-(&IS<B!C
  3202. M:')O=70-(&EN>0T@8FYE('1I=&QE#2!I;F,@=&5M<#(-(&IM<"!T:71L90T@
  3203. M='AT("=T2$E3H$E3H$&@4T5#4D54H%1%6%2@34534T%'12$G#3IC;VYT(#X^
  3204. M/B!G971K97D-#2HJ*BJ@<T54H%50H%1!0DQ%4R@_*0T-*J!T04),15.@05)%
  3205. MH$-54E)%3E1,6:!3152@55"@24Z@8F%S:6,-*J!!3D2@0EF@5$A%H$%34T5-
  3206. M0DQ%4BX-#71A8FQE<R!L9&$@(SYT;6%T:`T@<W1A('HQ*S$-('-T82!Z,BLQ
  3207. M#0TJ*BHJH&-,14%2H%-#4D5%3J!!3D2@4T54H%50H")"251-05`B#7-E='5P
  3208. M(&QD82`C)#`Q(#MW2$E410T@<W1A("1D,#(Q(#MT2$E3H$E3H$1/3D6@4T^@
  3209. M5$A!5*!/3$1%4@T@;&1A(",Q-#<@.TU!0TA)3D53H%=)3$R@4T54H%50#2!J
  3210. M<W(@8VAR;W5T#2!L9&$@(R0P,"`[0T]24D5#5$Q9#2!S=&$@)&0P,C$-(&QD
  3211. M82`C/'-S=&%R=`T@861C(",Q,B`[=$A%H$=/04R@25.@5$^@0T5.5$52H%1(
  3212. M1:!'4D%02$E#4PT@<W1A('1E;7`Q(#MC3TQ534Z@,3(-(&QD82`C/G-S=&%R
  3213. M="`[<D]7H#D-('-T82!T96UP,2LQ(#MS<W1A<G2@4$])3E13H%1/H%)/5Z`Y
  3214. M#2!L9&$@(S`P#2!L9'D@(S`P#2!L9'@@(S`P(#M8H%=)3$R@0T]53E2@,3:@
  3215. M4D]74Z!&3U*@55,-(&-L8PT-.FQO;W`@<W1A("AT96UP,2DL>0T@:6YY#2!A
  3216. M9&,@(S$V#2!B8V,@.FQO;W`-(&-L8PT@;&1A('1E;7`Q#2!A9&,@(S0P(#MN
  3217. M145$H%1/H$%$1*`T,*!43Z!42$6@0D%31:!03TE.5$52#2!S=&$@=&5M<#$@
  3218. M.W1/H$I535"@5$^@5$A%H$Y%6%2@4D]7#2!L9&$@=&5M<#$K,0T@861C(",P
  3219. M,"`[=$%+1:!#05)%H$]&H$-!4E))15,-('-T82!T96UP,2LQ#2!L9'D@(S`P
  3220. M#2!I;G@-('1X82`@.WB@25.@04Q33Z!!3J!)3D1%6*!)3E1/H%1(1:!#2$%2
  3221. M04-415*@3E5-0D52#2!C<'@@(S$V#2!B;F4@.FQO;W`@.VY%142@5$^@1$^@
  3222. M252@,3:@5$E-15,-#2`^/CX@9&5B=6<L)S(G#2HJ*BJ@<T54H%50H$)51D9%
  3223. M4E,-#2!L9&$@(SQB=69F,0T@<W1A(&)U9F9E<@T@;&1A(",^8G5F9C$-('-T
  3224. M82!B=69F97(K,0T@<W1A('IT96UP(#M:5$5-4*!724Q,H$U!2T6@3$E&1:!3
  3225. M24U03$6@1D]2H%53#2!L9&$@=FUC<V(-(&%N9"`C)3$Q,3$P,#`Q(#MS5$%2
  3226. M5*!(15)%H%-/H%1(052@4U=!4*!"549&15)3H%=)3$R@5T]22Z!224=(5`T@
  3227. M;W)A(",E,#`P,#$Q,3`-('-T82!V;6-S8@T-*BHJ*J!S152@55"@24Y)5$E!
  3228. M3*!604Q515,-#6EN:70@;&1A(",P,`T@<W1A(&1S>`T@<W1A(&1S>0T@<W1A
  3229. M(&1S>@T@<W1A('-X#2!S=&$@<WD-('-T82!S>@T-(#X^/B!D96)U9RPG-"<-
  3230. M#2HM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM#2J@;4%)3J!,3T]0
  3231. M#0TJ*BHJH&=%5*!+15E04D534PT-;6%I;@T@8VQI#6MP<F5S<R!J<W(@9V5T
  3232. M:6X-(&-M<"`C,3,S(#MF,3\-(&)N92`Z9C(-(&QD82!D<W@-(&-M<"`C86YG
  3233. M;6%X+S(@.VY/H$U/4D6@5$A!3J!020T@8F5Q(#IC;VYT#2!I;F,@9'-X(#M/
  3234. M5$A%4E=)4T6@24Y#4D5!4T6@6"U23U1!5$E/3@T@:FUP(#IC;VYT#3IF,B!C
  3235. M;7`@(S$S-R`[9C(_#2!B;F4@.F8S#2!L9&$@9'-X#2!B97$@.F-O;G0-(&1E
  3236. M8R!D<W@-(&IM<"`Z8V]N=`TZ9C,@8VUP(",Q,S0-(&)N92`Z9C0-(&QD82!D
  3237. M<WD-(&-M<"`C86YG;6%X+S(-(&)E<2`Z8V]N=`T@:6YC(&1S>2`[:4Y#4D5!
  3238. M4T6@62U23U1!5$E/3@T@:FUP(#IC;VYT#3IF-"!C;7`@(S$S.`T@8FYE(#IF
  3239. M-0T@;&1A(&1S>0T@8F5Q(#IC;VYT#2!D96,@9'-Y#2!J;7`@.F-O;G0-.F8U
  3240. M(&-M<"`C,3,U#2!B;F4@.F8V#2!L9&$@9'-Z#2!C;7`@(V%N9VUA>"\R#2!B
  3241. M97$@.F-O;G0-(&EN8R!D<WH@.UHM4D]4051)3TX-(&IM<"`Z8V]N=`TZ9C8@
  3242. M8VUP(",Q,SD-(&)N92`Z9C<-(&QD82!D<WH-(&)E<2`Z8V]N=`T@9&5C(&1S
  3243. M>@T@:FUP(#IC;VYT#3IF-R!C;7`@(S$S-@T@8FYE(#IQ#2!J;7`@:6YI=`TZ
  3244. M<2!C;7`@(R=1)R`[4:!154E44PT@8FYE(#IC;VYT#2!J;7`@8VQE86YU<`T-
  3245. M.F-O;G0@<V5I("`[<U!%142@5$A)3D=3H%50H$&@0DE4#2J@/CX^H&1E8G5G
  3246. M+"<U)PT-*BHJ*J!U4$1!5$6@04Y'3$53#0UU<&1A=&4@8VQC#2!L9&$@<W@-
  3247. M(&%D8R!D<W@-(&-M<"`C86YG;6%X(#MA4D6@5T6@/CV@34%824U53:!!3D=,
  3248. M13\-(&)C8R`Z8V]N=#$-('-B8R`C86YG;6%X(#II1B!33RP@4D53150-.F-O
  3249. M;G0Q('-T82!S>`T@8VQC#2!L9&$@<WD-(&%D8R!D<WD-(&-M<"`C86YG;6%X
  3250. M#2!B8V,@.F-O;G0R#2!S8F,@(V%N9VUA>"`[<T%-1:!$14%,#3IC;VYT,B!S
  3251. M=&$@<WD-(&-L8PT@;&1A('-Z#2!A9&,@9'-Z#2!C;7`@(V%N9VUA>`T@8F-C
  3252. M(#IC;VYT,PT@<V)C("-A;F=M87@-.F-O;G0S('-T82!S>@T-*BHJ*J!R3U1!
  3253. M5$6@0T]/4D1)3D%415,-#7)O=&%T90T-*BHJH&9)4E-4+*!#04Q#54Q!5$6@
  3254. M5#$L5#(L+BXN+%0Q,`T-*BJ@=%=/H$U!0U)/4Z!43Z!324U03$E&6:!/55*@
  3255. M3$E&10UA9&1A(&UA8R`@.V%$1*!45T^@04Y'3$53H%1/1T542$52#2!C;&,-
  3256. M(&QD82!=,0T@861C(%TR#2!C;7`@(V%N9VUA>"`[:5.@5$A%H%-53:`^H#(J
  3257. M4$D_#2!B8V,@9&]N90T@<V)C("-A;F=M87@@.VE&H%-/+*!354)44D%#5*`R
  3258. M*E!)#61O;F4@/#P\#0US=6)A(&UA8R`@.W-50E1204-4H%173Z!!3D=,15,-
  3259. M('-E8PT@;&1A(%TQ#2!S8F,@73(-(&)C<R!D;VYE#2!A9&,@(V%N9VUA>"`[
  3260. M;T]04RR@5T6@3D5%1*!43Z!!1$2@,BI020UD;VYE(#P\/`T-*BJ@;D]7H$-!
  3261. M3$-53$%41:!4,2Q4,BQ%5$,N#0T@/CX^('-U8F$L<WD[<WH-('-T82!T,2`[
  3262. M5#$]4UDM4UH-(#X^/B!A9&1A+'-Y.W-Z#2!S=&$@=#(@.U0R/5-9*U-:#2`^
  3263. M/CX@861D82QS>#MS>@T@<W1A('0S(#M4,SU36"M36@T@/CX^('-U8F$L<W@[
  3264. M<WH-('-T82!T-"`[5#0]4U@M4UH-(#X^/B!A9&1A+'-X.W0R#2!S=&$@=#4@
  3265. M.U0U/5-8*U0R#2`^/CX@<W5B82QS>#MT,0T@<W1A('0V(#M4-CU36"U4,0T@
  3266. M/CX^(&%D9&$L<W@[=#$-('-T82!T-R`[5#<]4U@K5#$-(#X^/B!S=6)A+'0R
  3267. M.W-X#2!S=&$@=#@@.U0X/50R+5-8#2`^/CX@<W5B82QS>3MS>`T@<W1A('0Y
  3268. M(#M4.3U362U36`T@/CX^(&%D9&$L<W@[<WD-('-T82!T,3`@.U0Q,#U36"M3
  3269. M60T-*J!E5*!63TE,02$-#2HJ*J!N15A4+*!#04Q#54Q!5$6@82QB+&,L+BXN
  3270. M+&D-#2HJH&%.3U1(15*@55-%1E5,H$Q)5%1,1:!-04-23PUD:78R(&UA8R`@
  3271. M.V1)5DE$1:!!H%-)1TY%1*!.54U"15*@0EF@,@T[:52@25.@05-354U%1*!4
  3272. M2$%4H%1(1:!.54U"15(-(&)P;"!P;W,@.TE3H$E.H%1(1:!!0T-5355,051/
  3273. M4@T@8VQC#2!E;W(@(R1F9B`[=T6@3D5%1*!43Z!53BU.14=!5$E61:!42$6@
  3274. M3E5-0D52#2!A9&,@(S`Q(#M"6:!404M)3D>@250G4Z!#3TU03$5-14Y4#2!L
  3275. M<W(@(#M$259)1$6@0EF@5%=/#2!C;&,-(&5O<B`C)&9F#2!A9&,@(S`Q(#MM
  3276. M04M%H$E4H$Y%1T%4259%H$%'04E.#2!J;7`@9&]N961I=@UP;W,@;'-R("`[
  3277. M;E5-0D52H$E3H%!/4TE4259%#61O;F5D:78@/#P\#0UM=6PR(&UA8R`@.VU5
  3278. M3%1)4$Q9H$&@4TE'3D5$H$Y534)%4J!"6:`R#2!B<&P@<&]S;0T@8VQC#2!E
  3279. M;W(@(R1F9@T@861C(",D,#$-(&%S;`T@8VQC#2!E;W(@(R1F9@T@861C(",D
  3280. M,#$-(&IM<"!D;VYE;75L#7!O<VT@87-L#61O;F5M=6P@/#P\#0TJ*J!N3U1%
  3281. MH%1(052@5T6@05)%H$-54E)%3E1,6:!-04M)3D>@0:!-24Y/4J!,14%0#2HJ
  3282. MH$]&H$9!251(H%1(052@3D^@3U9%4D9,3U=3H%=)3$R@3T-#55(N#0TZ8V%L
  3283. M8V$@8VQC#2!L9'@@=#$-(&QD82!C;W,L>`T@;&1X('0R#2!A9&,@8V]S+'@-
  3284. M('-T82!A,3$@.V$]*$-/4RA4,2DK0T]3*%0R*2DO,@TZ8V%L8V(@;&1X('0Q
  3285. M#2!L9&$@<VEN+'@-('-E8PT@;&1X('0R#2!S8F,@<VEN+'@-('-T82!B,3(@
  3286. M.V(]*%-)3BA4,2DM4TE.*%0R*2DO,@TZ8V%L8V,@;&1X('-Y#2!L9&$@<VEN
  3287. M+'@-(#X^/B!M=6PR#2!S=&$@8S$S(#MC/5-)3BA362D-.F-A;&-D('-E8PT@
  3288. M;&1X('0X#2!L9&$@8V]S+'@-(&QD>"!T-PT@<V)C(&-O<RQX#2!S96,-(&QD
  3289. M>"!T-0T@<V)C(&-O<RQX#2!C;&,-(&QD>"!T-@T@861C(&-O<RQX(#MD23TH
  3290. M0T]3*%0X*2U#3U,H5#<I*T-/4RA4-BDM0T]3*%0U*2DO,@T@/CX^(&1I=C(-
  3291. M(&-L8PT@;&1X('0S#2!A9&,@<VEN+'@-('-E8PT@;&1X('0T#2!S8F,@<VEN
  3292. M+'@-('-T82!D,C$@.V0]*%-)3BA4,RDM4TE.*%0T*2MD22DO,@TZ8V%L8V4@
  3293. M<V5C#2!L9'@@=#4-(&QD82!S:6XL>`T@;&1X('0V#2!S8F,@<VEN+'@-('-E
  3294. M8PT@;&1X('0W#2!S8F,@<VEN+'@-('-E8PT@;&1X('0X#2!S8F,@<VEN+'@@
  3295. M.V5)/2A324XH5#4I+5-)3BA4-BDM4TE.*%0W*2U324XH5#@I*2\R#2`^/CX@
  3296. M9&EV,@T@8VQC#2!L9'@@=#,-(&%D8R!C;W,L>`T@8VQC#2!L9'@@=#0-(&%D
  3297. M8R!C;W,L>`T@<W1A(&4R,B`[93TH0T]3*%0S*2M#3U,H5#0I*V5)*2\R#3IC
  3298. M86QC9B!L9'@@=#D-(&QD82!S:6XL>`T@<V5C#2!L9'@@=#$P#2!S8F,@<VEN
  3299. M+'@-('-T82!F,C,@.V8]*%-)3BA4.2DM4TE.*%0Q,"DI+S(-.F-A;&-G(&QD
  3300. M>"!T-@T@;&1A('-I;BQX#2!S96,-(&QD>"!T.`T@<V)C('-I;BQX#2!S96,-
  3301. M(&QD>"!T-PT@<V)C('-I;BQX#2!S96,-(&QD>"!T-0T@<V)C('-I;BQX(#MG
  3302. M23TH4TE.*%0V*2U324XH5#@I+5-)3BA4-RDM4TE.*%0U*2DO,@T@/CX^(&1I
  3303. M=C(-(&-L8PT@;&1X('0T#2!A9&,@8V]S+'@-('-E8PT@;&1X('0S#2!S8F,@
  3304. M8V]S+'@-('-T82!G,S$@.V<]*$-/4RA4-"DM0T]3*%0S*2MG22DO,@T@/CX^
  3305. M(&1E8G5G82QG,S$-(#X^/B!D96)U9RPG1R<-.F-A;&-H(&-L8PT@;&1X('0V
  3306. M#2!L9&$@8V]S+'@-(&QD>"!T-PT@861C(&-O<RQX#2!S96,-(&QD>"!T-0T@
  3307. M<V)C(&-O<RQX#2!S96,-(&QD>"!T.`T@<V)C(&-O<RQX(#MH23TH0T]3*%0V
  3308. M*2M#3U,H5#<I+4-/4RA4-2DM0T]3*%0X*2DO,@T@/CX^(&1I=C(-(&-L8PT@
  3309. M;&1X('0S#2!A9&,@<VEN+'@-(&-L8PT@;&1X('0T#2!A9&,@<VEN+'@-('-T
  3310. M82!H,S(@.V@]*%-)3BA4,RDK4TE.*%0T*2MH22DO,@TZ=VAE=R!C;&,-(&QD
  3311. M>"!T.0T@;&1A(&-O<RQX#2!L9'@@=#$P#2!A9&,@8V]S+'@-('-T82!I,S,@
  3312. M.VD]*$-/4RA4.2DK0T]3*%0Q,"DI+S(-#2HJH&E4)U.@04Q,H$1/5TY(24Q,
  3313. MH$923TV@2$5212X-(&IM<"!D;W=N:&EL;`T@='AT("=G146@8E)!24XLH%=(
  3314. M052@1$^@64]5H%=!3E2@5$^@1$^@)PT@='AT("=43TY)1TA4/R<-#2HJH')/
  3315. M5$%412R@4%)/2D5#5"R@04Y$H%-43U)%H%1(1:!03TE.5%,-9&]W;FAI;&P-
  3316. M#2J@8:!.14%4H$U!0U)/#6YE9R!M86,@(#MC2$%.1T6@5$A%H%-)1TZ@3T:@
  3317. M0:!45T\G4Z!#3TU03$5-14Y4#2!C;&,-(&QD82!=,2`[3E5-0D52+@T@96]R
  3318. M(",D9F8-(&%D8R`C)#`Q#2`\/#P-#2HM+2TM+2TM+2TM+2TM+2TM+2TM+2TM
  3319. M+2TM+2TM+2TM#2J@=$A%4T6@34%#4D]3H%)%4$Q!0T6@5$A%H%!2159)3U53
  3320. MH%!23TI%0U1)3TX-*J!354)23U5424Y%+@T-<VUU;'0@;6%C(#MM54Q425!,
  3321. M6:!45T^@4TE'3D5$H#@M0DE4#2`@(#M.54U"15)3.J!A*GDO-C2@+3Z@80T@
  3322. M<W1A('HQ#2!C;&,-(&5O<B`C)&9F#2!A9&,@(R0P,0T@<W1A('HR#2!L9&$@
  3323. M*'HQ*2QY#2!S96,-('-B8R`H>C(I+'D-(#P\/"`@.V%,3*!$3TY%H#HI#0T-
  3324. M861D<W5B(&UA8R`@.V%$1*!/4J!354)44D%#5*!45T^@3E5-0D524PT@("`[
  3325. M1$5014Y$24Y'H$].H$9)4E-4H$E.4%54#2!I9B`M/5TQ(#MI1J!354)44D%#
  3326. M5`T@<V5C("`[5$A%3J!54T6@5$A)4Z!#3T1%#2!S8F,@73(-(&5L<V4@(#M/
  3327. M5$A%4E=)4T6@55-%H%1(25.@0T]$10T@8VQC#2!A9&,@73(-(&9I;@T@/#P\
  3328. M#0T-<')O:F5C="!M86,@(#MT2$6@04-454%,H%!23TI%0U1)3TZ@4D]55$E.
  3329. M10T@("`[5%=/H$E.4%544Z!!4D6@55-%1*`H6"Q9*0T@("`[0T]24D534$].
  3330. M1$E.1Z!43Z`H*R\M,2PK+RTQ*0T@("`[=$A%H%1(25)$H$E.4%54H$E3H%53
  3331. M142@5$\-("`@.T1%5$5234E.1:!)1J!42$6@4D]4051%1`T@("`[6BU#3T]2
  3332. M1$E.051%H%-(3U5,1*!"10T@("`[4U1/4D5$+*!!3D2@24:@4T^@5TA%4D4N
  3333. M#2`@(#MT2$6@0T%,3$E.1Z!23U5424Y%H$A!3D1,15,-("`@.T-(04Y'24Y'
  3334. MH%1(1:!324=.H$]&H%HN#0T@;&1A(&DS,R`[8T%,0U5,051%H%)/5$%4142@
  3335. M6CH-(#X^/B!A9&1S=6(L73$[9S,Q(#MA1$2@3U*@4U5"5%)!0U2@6`T@/CX^
  3336. M(&%D9'-U8BQ=,CMH,S(@.V%$1*!/4J!354)44D%#5*!9#2!I9B!P+%TS(#MD
  3337. M3Z!71:!.145$H%1/H%-43U)%H%1(1:!03TE.5#\-('-T82!=,R`[=$A%3J!$
  3338. M3Z!33R$-(&9I;@TJH&5O<J`C,3(XH#MW1:!!4D6@1T])3D>@5$^@5$%+1:`Q
  3339. M,C@K6@T@=&%X("`[;D]7H$E4H$E3H%)%0419H$9/4J!)3D1%6$E.1PT@;&1A
  3340. M('ID:78L>"`[=$%"3$6@3T:@1"\H6BM:,"D-('1A>2`@.WF@3D]7H$-/3E1!
  3341. M24Y3H%!23TI%0U1)3TX-#2!L9&$@8S$S(#MN3U>@0T%,0U5,051%H%)/5$%4
  3342. M142@6`T@/CX^(&%D9'-U8BQ=,3MA,3$-(#X^/B!A9&1S=6(L73([8C$R#2`^
  3343. M/CX@<VUU;'0@.W-)1TY%1*!-54Q425!,6:!A*GDO-C0M/F$-(&-L8PT@861C
  3344. M(",V-"`[;T9&4T54H%1(1:!#3T]21$E.051%#2!T87@@(#MN3U>@>*!)4Z!2
  3345. M3U1!5$5$H%@A#0T@;&1A(&8R,R`[;D]7H$E4)U.@62=3H%154DX-(#X^/B!A
  3346. M9&1S=6(L73$[9#(Q#2`^/CX@861D<W5B+%TR.V4R,@T@/CX^('-M=6QT#2!C
  3347. M;&,-(&%D8R`C-C0@.V]&1E-%5`T@8VUP('EM:6X@.V9)1U521:!/552@24:@
  3348. M252@25.@00T@8F-S(&YO=&UI;B`[34E.H$]2H$U!6*!604Q51:!&3U*@60T@
  3349. M<W1A('EM:6X-(&)C8R!N;W1M87@@.W1(25.@25.@55-%1*!)3J!#04Q#54Q!
  3350. M5$E.1PUN;W1M:6X@8VUP('EM87@@.U1(1:!&24Q,142@1D%#15,-(&)C8R!N
  3351. M;W1M87@-('-T82!Y;6%X#6YO=&UA>"!T87D@(#MN3U2@4D5!3$Q9H$Y%0T53
  3352. M4T%260T-(#P\/"`@.V%,3*!$3TY%#0T-(&QD82`C-C0@.W)%4T54H'E-24Z@
  3353. M04Y$H'E-05@-('-T82!Y;6EN#2!S=&$@>6UA>`T-*J!P,3U;,:`QH#%=#2`^
  3354. M/CX@<')O:F5C="PQ.S$[<#%Z(#MR3U1!5$5$H%J@4U1/4D5$H$E.H'`Q>@T@
  3355. M<W1X('`Q>`T@<W1Y('`Q>0TJH'`R/5LQH"TQH#%=#2`^/CX@<')O:F5C="PQ
  3356. M.RTQ.W`R>@T@<W1X('`R>`T@<W1Y('`R>0TJH'`S/5LM,:`M,:`Q70T@/CX^
  3357. M('!R;VIE8W0L+3$[+3$[;F]P92`[9$].)U2@4U1/4D6@6BU604Q510T@<W1X
  3358. M('`S>`T@<W1Y('`S>0TJH'`T/5LM,:`QH#%=#2`^/CX@<')O:F5C="PM,3LQ
  3359. M.W`T>@T@<W1X('`T>`T@<W1Y('`T>0TJH'`X/5LM,:`QH"TQ70T@/CX^(&YE
  3360. M9RQC,3,-('-T82!C,3,-(#X^/B!N96<L9C(S#2!S=&$@9C(S#2`^/CX@;F5G
  3361. M+&DS,PT@<W1A(&DS,PT@/CX^('!R;VIE8W0L+3$[,3MN;W!E#2!S='@@<#AX
  3362. M#2!S='D@<#AY#2J@<#<]6RTQH"TQH"TQ70T@/CX^('!R;VIE8W0L+3$[+3$[
  3363. M;F]P90T@<W1X('`W>`T@<W1Y('`W>0TJH'`V/5LQH"TQH"TQ70T@/CX^('!R
  3364. M;VIE8W0L,3LM,3MN;W!E#2!S='@@<#9X#2!S='D@<#9Y#2J@<#4]6S&@,:`M
  3365. M,5T-(#X^/B!P<F]J96-T+#$[,3MP-7H-('-T>"!P-7@-('-T>2!P-7D-#2J@
  3366. M8:!,25143$6@34%#4D\-#7-E=&)U9B!M86,@(#MP552@0E5&1D524Z!72$52
  3367. M1:!42$59H$-!3J!"1:!(55)4#2!L9&$@(S`P#2!S=&$@8G5F9F5R#2!L9&$@
  3368. M>G1E;7`@.UI414U0H$-/3E1!24Y3H%1(1:!(24=(H$)95$6@2$5210T@<W1A
  3369. M(&)U9F9E<BLQ#2`\/#P-#2HJ*BJ@8TQ%05*@0E5&1D52#0TJH#X^/J!S971B
  3370. M=68-*F-L<F)U9J!L9&&@(R0P,*`[<%)%5%19H%-44D%)1TA41D]25T%21"P-
  3371. M*J!L9'B@(R0P.*`[::!42$E.2PTJH&QD>:`C)#`P#2HZ;&]O<*!S=&&@*&)U
  3372. M9F9E<BDL>0TJH&EN>0TJH&)N9:`Z;&]O<`TJH&EN8Z!B=69F97(K,0TJH&1E
  3373. M>`TJH&)N9:`Z;&]O<`T-*J!T2$E3H$E3H%1(1:!.15>@04Y$H$E-4%)/5D5$
  3374. MH$)51D9%4J!#3$5!4@TJH%)/551)3D6@1D]2H$9)3$Q%1*!&04-%4PT-(#X^
  3375. M/B!S971B=68-('-T82!T96UP,2LQ(#M"549&15(RH%=)3$R@4$])3E2@5$\-
  3376. M(&QD82`C)#@P(#M"549&15(K,3(X#2!S=&$@=&5M<#$@.VU!2T53H$Q)1D6@
  3377. M1D%35$52H$9/4J!54PUF:6QC;'(@;&1A(",P,`T@;&1X(",D,#@@.W=%)TQ,
  3378. MH$1/H$E4H%173Z!!5*!!H%1)344-(&QD>2`C)#`P#3IL;V]P,2!S=&$@*&)U
  3379. M9F9E<BDL>0T@<W1A("AT96UP,2DL>0T@:6YY#2!C<'D@>6UI;@T@8FYE(#IL
  3380. M;V]P,0T@;&1A(",D9F8@.VY/5Z!,3T%$H%=)5$B@1DE,3%,-.FQO;W`R('-T
  3381. M82`H8G5F9F5R*2QY#2!S=&$@*'1E;7`Q*2QY#2!I;GD-(&-P>2!Y;6%X#2!B
  3382. M8V,@.FQO;W`R#2!L9&$@(R0P,"`[8DQ!0TN@3U54H%1(1:!215-4#3IL;V]P
  3383. M,R!S=&$@*&)U9F9E<BDL>0T@<W1A("AT96UP,2DL>0T@:6YY#2!B<&P@.FQO
  3384. M;W`S(#MU3E1)3*!Y/3$R.`T@;&1Y(",P,`T@:6YC(&)U9F9E<BLQ#2!I;F,@
  3385. M=&5M<#$K,0T@9&5X#2!B;F4@.FQO;W`Q(#MG3Z!!3$R@5$A%H%=!6:!!4D]5
  3386. M3D0-#2HJ*BJ@;D]7H$1205>@5$A%H$Q)3D53+@TJ*BHJH&)55*!&25)35*!#
  3387. M2$5#2Z!&3U*@2$E$1$5.H$9!0T53(0TJ*BHJH')%345-0D52.J!P,3U;,:`Q
  3388. MH#%=H'`R/5LQH"TQH#%=H'`S/5LM,:`M,:`Q70TJ*BHJH'`T/5LM,:`QH#%=
  3389. MH'`U/5LQH#&@+3%=H'`V/5LQH"TQH"TQ7:!P-SU;+3&@+3&@+3%=#2HJ*BJ@
  3390. M<#@]6RTQH#&@+3%=#0UL:6YE<R!L9&$@(S`P#2!S=&$@9F%C97,@.VA)1$1%
  3391. M3J!&04-%H$-/54Y415(-.F9A8V4Q(&QD82!K#2!S96,-('-B8R!P,7H-(&)V
  3392. M<R`Z9F%C938@.V]615)&3$]7H$%,4D5!1%D_#2!C;&,-(&%D8R!P-7H@.VE3
  3393. MH$LM5C%:H#R@,#\-(#MI1J!.3U0LH$9!0T6@25.@24Y625-)0DQ%#2!B=F,@
  3394. M.F1R87<Q(#MB552@5T6@34E'2%2@2$%61:!/5D521DQ/5PT@;&1A('`U>B`[
  3395. M=T%3H$]615)&3$]7H%!/4Z!/4J!.14<_#3ID<F%W,2!B<&P@.F9A8V4V(#MI
  3396. M1J!03U.@5$A%3J!++58Q6J`^H#`-#2!L9&$@(R0P,2`[;U1(15)725-%+*!$
  3397. M4D%7H%1(10T@<W1A(&9A8V5S(#M&04-%(0T-(&QD82!P,7@-('-T82!T>#$-
  3398. M(&QD82!P,7D-('-T82!T>3$-(&QD82!P,G@-('-T82!T>#(-(&QD82!P,GD-
  3399. M('-T82!T>3(-(&IS<B!D<F%W(#MP,2UP,@T-(&QD82!P,W@-('-T82!T>#$-
  3400. M(&QD82!P,WD-('-T82!T>3$-(&IS<B!D<F%W(#MP,BUP,PT-(&QD82!P-'@-
  3401. M('-T82!T>#(-(&QD82!P-'D-('-T82!T>3(-(&IS<B!D<F%W(#MP,RUP-`T-
  3402. M(&QD82!P,7@-('-T82!T>#$-(&QD82!P,7D-('-T82!T>3$-(&IS<B!D<F%W
  3403. M(#MP-"UP,:"@9D%#1:`QH$1/3D4N#2!J;7`@.F9A8V4R(#MI1J!/3D6@25.@
  3404. M5DE324),12R@5$A%H$]42$52#2`@(#M)4TXG5"X-.F9A8V4V(&QD82!K#2!S
  3405. M96,-('-B8R!P-7H-(&)V<R`Z9F%C93(-(&-L8PT@861C('`Q>B`[;D]7H$-(
  3406. M14-+H$E&H&LM5C9:H#R@,`T@8G9C(#ID<F%W-B`[;$]61:!42$%4H$]615)&
  3407. M3$]7#2!L9&$@<#%Z#3ID<F%W-B!B<&P@.F9A8V4R(#MI1J!.3U0LH$=/H$].
  3408. M#0T@;&1A(",D,C`-('-T82!F86-E<R`[;U1(15)725-%+*!$4D%7H$E4#0T@
  3409. M;&1A('`U>`T@<W1A('1X,@T@;&1A('`U>0T@<W1A('1Y,@T@;&1A('`V>`T@
  3410. M<W1A('1X,0T@;&1A('`V>0T@<W1A('1Y,0T@:G-R(&1R87<@.W`U+7`V#0T@
  3411. M;&1A('`W>`T@<W1A('1X,@T@;&1A('`W>0T@<W1A('1Y,@T@:G-R(&1R87<@
  3412. M.W`V+7`W#0T@;&1A('`X>`T@<W1A('1X,0T@;&1A('`X>0T@<W1A('1Y,0T@
  3413. M:G-R(&1R87<@.W`W+7`X#0T@;&1A('`U>`T@<W1A('1X,@T@;&1A('`U>0T@
  3414. M<W1A('1Y,@T@:G-R(&1R87<@.W`X+7`U#0TZ9F%C93(@;&1A(&L-('-E8PT@
  3415. M<V)C('`Q>@T@8G9S(#IF86-E-0T@8VQC#2!A9&,@<#1Z(#MK+58R6J`\H#`_
  3416. M#2!B=F,@.F1R87<R#2!L9&$@<#1Z#3ID<F%W,B!B<&P@.F9A8V4U#2!L9&$@
  3417. M(R0P,B`[:4:@4T\LH$1205>@250A#2!O<F$@9F%C97,-('-T82!F86-E<PT-
  3418. M(&QD>"!P,7@@.W=%)U)%H$1/24Y'H%1(25.@5$A)4Z!705D-('-T>"!T>#$@
  3419. M.U1/H%-!5D6@0:!&15>@0UE#3$53#2!L9'@@<#%Y#2!S='@@='DQ#0T@86YD
  3420. M(",D,#$@.W-(05)%4Z!!3J!%1$=%H%=)5$B@1D%#1:`Q#2!B;F4@.F8R<S(@
  3421. M.W-+25"@5$^@3D585*!%1$=%H$E&H%!215-%3E0-#2!L9&$@<#)X#2!S=&$@
  3422. M='@R#2!L9&$@<#)Y#2!S=&$@='DR#2!J<W(@9')A=R`[<#$M<#(-#3IF,G,R
  3423. M(&QD>"!P-7@-('-T>"!T>#(-(&QD>"!P-7D-('-T>"!T>3(-(&IS<B!D<F%W
  3424. M(#MP,2UP-0T-(&QD>"!P-G@-('-T>"!T>#$-(&QD>"!P-GD-('-T>"!T>3$-
  3425. M#2!L9&$@9F%C97,-(&%N9"`C)#(P(#MA3%-/H%-(05)%4Z!!3J!%1$=%H%=)
  3426. M5$B@-@T@8FYE(#IF,G,T#0T@:G-R(&1R87<@.W`U+7`V#0TZ9C)S-"!L9&$@
  3427. M<#)X#2!S=&$@='@R#2!L9&$@<#)Y#2!S=&$@='DR(#MS54-(H$E3H$9!0T6@
  3428. M,@T@:G-R(&1R87<@.W`V+7`R#2!J;7`@.F9A8V4S(#MS2TE0H#4-#3IF86-E
  3429. M-2!L9&$@:PT@<V5C#2!S8F,@<#1Z#2!B=G,@.F9A8V4S#2!C;&,-(&%D8R!P
  3430. M,7H@.W-!346@5$A)3D>@04=!24XN+BX-(&)V8R`Z9')A=S4-(&QD82!P,7H-
  3431. M.F1R87<U(&)P;"`Z9F%C93,-(&QD82`C)#$P#2!O<F$@9F%C97,-('-T82!F
  3432. M86-E<PT-(&QD>"!P,W@-('-T>"!T>#$-(&QD>"!P,WD-('-T>"!T>3$-#2!A
  3433. M;F0@(R0P,2`[<TA!4D53H%=)5$B@,0T@8FYE(#IF-7,R#0T@;&1A('`T>`T@
  3434. M<W1A('1X,@T@;&1A('`T>0T@<W1A('1Y,@T@:G-R(&1R87<@.W`S+7`T#0TZ
  3435. M9C5S,B!L9&$@<#=X#2!S=&$@='@R#2!L9&$@<#=Y#2!S=&$@='DR#2!J<W(@
  3436. M9')A=R`[<#,M<#<-#2!L9&$@<#AX#2!S=&$@='@Q#2!L9&$@<#AY#2!S=&$@
  3437. M='DQ#0T@;&1A(&9A8V5S#2!A;F0@(R0R,"`[<TA!4D53H%=)5$B@-@T@8FYE
  3438. M(#IF-7,T#0T@:G-R(&1R87<@.W`W+7`X#3IF-7,T(&QD82!P-'@-('-T82!T
  3439. M>#(-(&QD82!P-'D-('-T82!T>3(@.W`X+7`T#2!J<W(@9')A=R`[=%=/H$U/
  3440. M4D6@5$^@1T\A#0TZ9F%C93,@;&1A(&L-('-E8PT@<V)C('`Q>@T@8G9S(#IF
  3441. M86-E-`T@8VQC#2!A9&,@<#)Z#2!B=F,@.F1R87<S#2!L9&$@<#)Z#3ID<F%W
  3442. M,R!B<&P@.F9A8V4T(#MA2*!214-+3TZ@250G4Z!!)TA)1$1%3BR@6550#2!L
  3443. M9&$@(R0P-`T@;W)A(&9A8V5S#2!S=&$@9F%C97,-#2!L9'@@<#%X#2!S='@@
  3444. M='@Q#2!L9'@@<#%Y#2!S='@@='DQ#0T@86YD(",D,#$@.W-(05)%4Z!7251(
  3445. MH#$-(&)N92`Z9C-S,@T-(&QD82!P-'@-('-T82!T>#(-(&QD82!P-'D-('-T
  3446. M82!T>3(-(&IS<B!D<F%W(#MP,2UP-`T-.F8S<S(@;&1X('`U>`T@<W1X('1X
  3447. M,@T@;&1X('`U>0T@<W1X('1Y,@T-(&QD82!F86-E<PT@86YD(",D,#(@.W-(
  3448. M05)%4Z!7251(H#(-(&)N92`Z9C-S,PT-(&IS<B!D<F%W(#MP,2UP-0TZ9C-S
  3449. M,R!L9'@@<#AX#2!S='@@='@Q#2!L9'@@<#AY#2!S='@@='DQ#0T@;&1A(&9A
  3450. M8V5S#2!A;F0@(R0R,"`[<TA!4D53H%=)5$B@-@T@8FYE(#IF,W,T#0T@:G-R
  3451. M(&1R87<@.W`U+7`X#3IF,W,T(&QD>"!P-'@-('-T>"!T>#(-(&QD>"!P-'D-
  3452. M('-T>"!T>3(-#2!L9&$@9F%C97,-(&%N9"`C)#$P(#MS2$%215.@5TE42*`U
  3453. M#2!B;F4@9F%C961O;F4-#2!J<W(@9')A=R`[<#@M<#0-(&IM<"!F86-E9&]N
  3454. M90T-.F9A8V4T(&QD82!K#2!S96,-('-B8R!P,GH-(&)V<R!F86-E9&]N90T@
  3455. M8VQC#2!A9&,@<#%Z#2!B=F,@.F1R87<T#2!L9&$@<#%Z#3ID<F%W-"!B<&P@
  3456. M9F%C961O;F4-#2!L9&$@<#)X#2!S=&$@='@Q#2!L9&$@<#)Y#2!S=&$@='DQ
  3457. M#0T@;&1A(&9A8V5S#2!A;F0@(R0P,2`[<TA!4D53H%=)5$B@,0T@8FYE(#IF
  3458. M-',R#0T@;&1A('`S>`T@<W1A('1X,@T@;&1A('`S>0T@<W1A('1Y,@T@:G-R
  3459. M(&1R87<@.W`R+7`S#0TZ9C1S,B!L9&$@<#9X#2!S=&$@='@R#2!L9&$@<#9Y
  3460. M#2!S=&$@='DR#0T@;&1A(&9A8V5S#2!A;F0@(R0P,B`[<TA!4D53H%=)5$B@
  3461. M,@T@8FYE(#IF-',S#0T@:G-R(&1R87<@.W`R+7`V#3IF-',S(&QD82!P-W@-
  3462. M('-T82!T>#$-(&QD82!P-WD-('-T82!T>3$-#2!L9&$@9F%C97,-(&%N9"`C
  3463. M)#(P(#MS2$%215.@5TE42*`V#2!B;F4@.F8T<S0-#2!J<W(@9')A=R`[<#8M
  3464. M<#<-.F8T<S0@;&1A('`S>`T@<W1A('1X,@T@;&1A('`S>0T@<W1A('1Y,@T-
  3465. M(&QD82!F86-E<PT@86YD(",D,3`@.W-(05)%4Z!7251(H#4-(&)N92!F86-E
  3466. M9&]N90T-(&IS<B!D<F%W(#MP-RUP,PUF86-E9&]N92`@(#MW2$57(:"@=$E-
  3467. M1:!&3U*@0:!"1452+@T-*BHJ*J!N3U>@5T6@3D5%1*!43Z!53D9)3$R@5$A%
  3468. MH$]55%-)1$6@1E)/3:!42$6@1D%#15,-=6YF:6QL(&QD>2!Y;6EN#3IL;V]P
  3469. M(#X^/B!S971B=68-(&QD>"`C,#@-.FPQ(&QD82`H8G5F9F5R*2QY#2!E;W(@
  3470. M(R1F9B`[9T^@5$E,3*!71:!&24Y$H$&@4$Q/5%1%1`T@8FYE(#IG;W1C:&$@
  3471. M.U!/24Y4H"A)+D4NH&&@/#Z@)&9F*0TJH&QD8:`C,#"@.W5.1DE,3$E.1Z!!
  3472. M4Z!71:!'3RXN+@T@<W1A("AB=69F97(I+'D-(&QD82`C)#@P#2!S=&$@8G5F
  3473. M9F5R#2!L9&$@*&)U9F9E<BDL>0T@96]R(",D9F8-(&)N92`Z9V]T8VAA#2J@
  3474. M;&1AH",P,`T@<W1A("AB=69F97(I+'D-('-T82!B=69F97(-(&EN8R!B=69F
  3475. M97(K,0T@9&5X("`[=$A)4Z!)4Z!/55*@4T%&1519H%9!3%9%#2!B;F4@.FPQ
  3476. M(#MR14%,3%F@4TA/54Q$3B=4H$Y%142@250-(&IS<B!C:&]K90T@:FUP('-W
  3477. M87!B=68-#3IG;W1C:&$@.V&@0T].5$%)3E.@5$A%H&5O<J!03$]4H%9!3%5%
  3478. M#2!S=&$@=&5M<#$@.VY/5Z!&24Y$H%1(1:!(24=(H$))5`T@;&1A(",P,`TZ
  3479. M;#(@<V5C#2!R;VP-(&QS<B!T96UP,2`[<TA/54Q$H%)%04Q,6:!54T6@0:!4
  3480. M04),10T@8FYE(#IL,B`[1D]2H%1(25,A#2!A;F0@*&)U9F9E<BDL>0T@<W1A
  3481. M("AB=69F97(I+'D-#2!L9&$@>G1E;7`@.VY/5Z!'3Z!43Z!42$6@14Y$#2`@
  3482. M(#MC05)26:!)4Z!#3$5!4@T@("`[84-454%,3%F@5T6@041$H#<-(&%D8R`C
  3483. M)#`V(#LQ-J!#3TQ534Y3H$]&H#$R.*!"651%4PT@<W1A(&)U9F9E<BLQ#2!L
  3484. M9&$@(R0X,`T@<W1A(&)U9F9E<@TZ;&]O<#(@;&1A("AB=69F97(I+'D@.V%.
  3485. M1*!73U)+H$)!0TM705)$4R$-(&5O<B`C)&9F#2!B;F4@.F=O=&-H83(-('-T
  3486. M82`H8G5F9F5R*2QY#2!S=&$@8G5F9F5R(#MS5$E#2Z!!H%I%4D^@24Y43Z!"
  3487. M549&15(-(&QD82`H8G5F9F5R*2QY#2!E;W(@(R1F9@T@8FYE(#IG;W1C:&$R
  3488. M#2!S=&$@*&)U9F9E<BDL>0T@;&1A(",D.#`-('-T82!B=69F97(-(&1E8R!B
  3489. M=69F97(K,0T@8FYE(#IL;V]P,@T-.F=O=&-H83(@<W1A('1E;7`Q(#MA1T%)
  3490. M3J!&24Y$H%1(1:!(24=(H$))5`T@;&1A(",P,`TZ;#,@<V5C#2!R;W(-(&%S
  3491. M;"!T96UP,0T@8FYE(#IL,PT@86YD("AB=69F97(I+'D-('-T82`H8G5F9F5R
  3492. M*2QY#0T@:6YY("`[;D]7H$M%15"@1T])3D<-(&-P>2!Y;6%X#2!B8V,@.FQO
  3493. M;W`@.W5.5$E,H%=%H$A)5*!934%8(0T@8F5Q(#IL;V]P(#MW1:!.145$H%1(
  3494. M1:!,05-4H$].1:!43T\N#0TJ*BHJH'-705"@0E5&1D524PT-<W=A<&)U9B!L
  3495. M9&$@=FUC<V(-(&5O<B`C)#`R(#MP4D545%F@5%))0TM9+*!%2#\-('-T82!V
  3496. M;6-S8@T@;&1A(",D,#@-(&5O<B!Z=&5M<"`[6E1%35`]2$E'2*!"651%H$I5
  3497. M4U2@1DQ)4%,-('-T82!Z=&5M<"`[0D545T5%3J`D,S"@04Y$H"0S.`T-(&IM
  3498. M<"!M86EN(#MA4D]53D2@04Y$H$%23U5.1*!71:!'3RXN+@T-('1X="`G<T%-
  3499. M1:!42$E.1Z!71:!$3Z!%5D526:!.24=(5"R@<$E.2UDZH"<-('1X="`G5%)9
  3500. MH%1/H%1!2T6@3U9%4J!42$6@5T]23$0A)PT-#2HM+2TM+2TM+2TM+2TM+2TM
  3501. M+2TM+2TM+2TM+2TM+2TM#2J@9T5.15)!3*!154535$E/3D%"3$4M5D%,546@
  3502. M15)23U*@4%)/0T5$55)%#0UC:&]K92!L9'@@(S`P#3IL;V]P(&QD82`Z8W1E
  3503. M>'0L>`T@8F5Q(#ID;VYE#2!J<W(@8VAR;W5T#2!I;G@-(&IM<"`Z;&]O<`TZ
  3504. M9&]N92!R=',-.F-T97AT(&AE>"`P9"`[8W(-('1X="`G4T]-151(24Y'H$-(
  3505. M3TM%1*`Z*"<-(&AE>"`P9#`P#0T@='AT("=N05)&(2<-#2HM+2TM+2TM+2TM
  3506. M+2TM+2TM+2TM+2TM+2TM+2TM+2TM#2J@9%)!5TE.)Z!!H$Q)3D4NH*!AH$9!
  3507. M2$Z@3$%(3BX-#2HJ*J!S3TU%H%5314953*!-04-23U,-#7!L;W1P>"!M86,@
  3508. M(#M03$]4H$&@4$])3E2@24Z@6`T@<&AA("`[=5-%H%1(25.@3TY%H$5615)9
  3509. MH%1)344-(&QD82!B:71P+'@@.WB@25.@24Y#4D5!4T5$#2!B;6D@8S$-(&QD
  3510. M82`C)#@P(#MT04),1:!(05.@0D5%3J!214%24D%.1T5$#2!E;W(@8G5F9F5R
  3511. M(#M&3U*@1DE,3$E.1Z!&04-%4PT@<W1A(&)U9F9E<@T@8FUI(&,R#2!I;F,@
  3512. M8G5F9F5R*S$-8S(@;&1A(",E,#$Q,3$Q,3$@.VY/5$6@5$A!5*!42$E3H$E3
  3513. MH$-(04Y'140-8S$@86YD("AB=69F97(I+'D@.T9/4J!03$]45$E.1Z!&24Q,
  3514. M142@1D%#15,-('-T82`H8G5F9F5R*2QY#2!P;&$@(#MN145$H%1/H%-!5D6@
  3515. M82$-(#P\/`T-<&QO='!Y(&UA8R`@.W!,3U2@0:!03TE.5*!)3J!9.J!324U0
  3516. M3$52H$%.1*!.14-%4U-!4EDA#2!P:&$@(#MU4T6@5$A)4Z!/3D6@5TA%3J!9
  3517. M3U6@2E535*!)3D-214%31:!Y#2!L9&$@8FET<"QX(#M"552@>*!$3T533B=4
  3518. MH$-(04Y'10T@86YD("AB=69F97(I+'D-('-T82`H8G5F9F5R*2QY#2!P;&$-
  3519. M(#P\/`T-8VEN:70@;6%C("`[;4%#4D^@5$^@24Y)5$E!3$E:1:!42$6@0T]5
  3520. M3E1%4@T@;&1A(%TQ(#M$6*!/4J!$60T@;'-R#2!E;W(@(R1F9B`[*&Y/5*!2
  3521. M14%,3%F@5%=/)U.@0T]-4$Q%345.5"D-(&%D8R`C)#`Q(#MAH#V@,C4V+418
  3522. M+S*@3U*@,C4V+419+S(-(#P\/"`@.W1(1:!$6"\RH$U!2T53H$&@3DE#15*@
  3523. M3$]/2TE.1Z!,24Y%#0UX<W1E<"!M86,@(#MM04-23Z!43Z!404M%H$&@4U1%
  3524. M4*!)3J!X#7AL;V]P(&EN>`T@861C(&1Y#2!B8V,@;#$-*J!D3Z!71:!54T6@
  3525. M:6YYH$]2H&1E>:!(15)%/PT@:68@:2Q=,2`[:4:@5$A%H$9)4E-4H$-(05)!
  3526. M0U1%4J!)4Z!!3J`G:2<-(&EN>0T@96QS90T@9&5Y#2!F:6X-('-B8R!D>`UL
  3527. M,2`^/CX@<&QO='!X(#MA3%=!65.@5$%+1:!!H%-415"@24Z@>`T@8W!X('@R
  3528. M#2!B;F4@>&QO;W`-(#P\/`T->7-T97`@;6%C("`[<T%-1:!42$E.1RR@0E54
  3529. MH$9/4J!Y#7EL;V]P(&EF(&DL73$-(&EN>0T@96QS90T@9&5Y#2!C;&,@(#MV
  3530. M15)9H$E-4$]25$%.5"$-(&9I;@T@861C(&1X#2!B8V,@;#(-(&EN>"`@.V%,
  3531. M5T%94Z!)3D-214%31:!X#2!S8F,@9'D-(#X^/B!P;&]T<'@-(&IM<"!L,PUL
  3532. M,B`^/CX@<&QO='!Y(#MW1:!/3DQ9H$E.0U)%05-%1*!Y#6PS(&-P>2!Y,@T@
  3533. M8FYE('EL;V]P#2`\/#P-#2HJ*BJ@:4Y)5$E!3*!,24Y%H%-%5%50#0UD<F%W
  3534. M(#X^/B!M;W9E+'1X,3MX,2`@.VU/5D6@4U151D:@24Y43Z!:15)/H%!!1T4-
  3535. M(#X^/B!M;W9E+'1X,CMX,B`@.W=(15)%H$E4H$-!3J!"1:!-3T1)1DE%1`T@
  3536. M/CX^(&UO=F4L='DQ.WDQ#2`^/CX@;6]V92QT>3([>3(-(#X^/B!S971B=68@
  3537. M.VY/5Z!71:!#04Z@0TQ/0D)%4J!42$6@0E5&1D52#0T@<V5C("`[;4%+1:!3
  3538. M55)%H%@Q/%@R#2!L9&$@>#(-('-B8R!X,0T@8F-S(#IC;VYT#2!L9&$@>3(@
  3539. M.VE&H$Y/5"R@4U=!4*!P,:!!3D2@<#(-(&QD>2!Y,0T@<W1A('DQ#2!S='D@
  3540. M>3(-(&QD82!X,0T@;&1Y('@R#2!S='D@>#$-('-T82!X,@T-('-E8PT@<V)C
  3541. M('@Q(#MN3U>@83U$6`TZ8V]N="!S=&$@9'@-(&QD>"!X,2`[<%54H%@QH$E.
  3542. M5$^@>"R@3D]7H%=%H$-!3J!44D%32*!X,0T-8V]L=6UN(&QD82!X,2`[9DE.
  3543. M1*!42$6@1DE24U2@0T],54U.H$9/4J!X#2!L<W(@(#LH=$A)4Z!#04Z@0D6@
  3544. M34%$1:!-54-(H$9!4U1%4B$I#2!L<W(@(#MT2$521:!!4D6@6#$O.*`Q,CB@
  3545. M0EE41:!"3$]#2U,-(&QS<B`@.W=(24-(H$U%04Y3H%@Q+S$VH#(U-J!"651%
  3546. MH$),3T-+4PT@;'-R#2!B8V,@.F5V96X@.W=)5$B@0:!03U-324),1:!%6%12
  3547. M0:`Q,CB@0EE41:!"3$]#2PT@;&1Y(",D.#`@.TE&H%-/+*!3152@5$A%H$A)
  3548. M1TB@0DE4#2!S='D@8G5F9F5R#2!C;&,-.F5V96X@861C(&)U9F9E<BLQ(#MA
  3549. M1$2@24Z@5$A%H$Y534)%4J!/1J`R-3:@0EE41:!"3$]#2U,-('-T82!B=69F
  3550. M97(K,2`[84Y$H%-43U)%H$E4(0T-('-E8PT@;&1A('DR(#MC04Q#54Q!5$6@
  3551. M1%D-('-B8R!Y,0T@8F-S(#IC;VYT,B`[:5.@63(^63$_#2!E;W(@(R1F9B`[
  3552. M;U1(15)725-%H$19/5DQ+5DR#2!A9&,@(R0P,0TZ8V]N=#(@<W1A(&1Y#2!C
  3553. M;7`@9'@@.W=(3R=3H$))1T=%4CJ@1%F@3U*@1%@_#2!B8W,@<W1E<&EN>2`[
  3554. M:4:@1%DLH%=%H$Y%142@5$^@5$%+1:!"24>@4U1%4%.@24Z@60T-<W1E<&EN
  3555. M>"!L9'D@>3$@.WB@25.@04Q214%$6:!3152@5$^@6#$-(&QD82!B:71P+'@@
  3556. M.W!,3U2@5$A%H$9)4E-4H%!/24Y4#2J@96]RH",D9F8-(&%N9"`H8G5F9F5R
  3557. M*2QY#2!S=&$@*&)U9F9E<BDL>0T@/CX^(&-I;FET+&1X(#MI3DE424%,25I%
  3558. MH%1(1:!#3U5.5$52#2!C<'D@>3(-(&)C<R!X9&5C>2`[9$^@5T6@4U1%4*!&
  3559. M3U)705)$4Z!/4J!"04-+5T%21%.@24Z@>3\-#7AI;F-Y(#X^/B!X<W1E<"QI
  3560. M;GD-(')T<PT-<W1E<&EN>2!L9'D@>3$@.W=%3$PLH$&@3$E45$Q%H%)%4$54
  3561. M251)3TZ@3D5615*@2%525*!!3EE/3D4-(&QD82!B:71P+'@-*J!E;W*@(R1F
  3562. M9@T@86YD("AB=69F97(I+'D-('-T82`H8G5F9F5R*2QY#2`^/CX@8VEN:70L
  3563. M9'D-(&-P>2!Y,@T@8F-S('ED96-Y#0UY:6YC>2`^/CX@>7-T97`L:6YY#2!R
  3564. M=',-#7AD96-Y(#X^/B!X<W1E<"QD97D@.W1(25.@25.@4%54H$A%4D6@4T^@
  3565. M5$A!5`T@<G1S("`[8E)!3D-(15.@05)%H$Q%1T%,#0UY9&5C>2`^/CX@>7-T
  3566. M97`L9&5Y#2!R=',-#0TJ+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM
  3567. M+0TJH&-,14%.H%50#0UC;&5A;G5P(&QD82!V;6-S8B`[<U=)5$-(H$-(05*@
  3568. M4D]-H$)!0TN@24X-(&%N9"`C)3$Q,3$P,3`Q(#M$149!54Q4#2!S=&$@=FUC
  3569. M<V(-#2!R=',@(#M"644A#0T@='AT("=H05!06:!H3TQ)1$%94R&@)PT@='AT
  3570. M("=33$J@,3(O.30G#0TJ+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM
  3571. M+0TJH'-%5*!54*!"252@5$%"3$4-#2!D<R!>(#MC3$5!4J!43Z!%3D2@3T:@
  3572. M4$%'10T@("`[<T^@5$A!5*!404),15.@4U1!4E2@3TZ@0:!004=%H$)/54Y$
  3573. M05)9#6)I='`@;'5P(#$V(#LQ,CB@94Y44DE%4Z!&3U*@>`T@9&9B("4P,3$Q
  3574. M,3$Q,0T@9&9B("4Q,#$Q,3$Q,0T@9&9B("4Q,3`Q,3$Q,0T@9&9B("4Q,3$P
  3575. M,3$Q,0T@9&9B("4Q,3$Q,#$Q,0T@9&9B("4Q,3$Q,3`Q,0T@9&9B("4Q,3$Q
  3576. M,3$P,0T@9&9B("4Q,3$Q,3$Q,`T@+2U>#0US:6X@.W1!0DQ%H$]&H%-)3D53
  3577. M+*`Q,C"@0EE415,-8V]S(&5Q=2!S:6XK,3(X(#MT04),1:!/1J!#3U-)3D53
  3578. M#2`@(#MB3U1(H$]&H%1(15-%H%1224>@5$%"3$53H$%210T@("`[0U524D5.
  3579. M5$Q9H%-%5*!54*!&4D]-H&)A<VEC#7ID:78@97%U(&-O<RLQ,C@@.V1)5DE3
  3580. M24].H%1!0DQ%#71M871H(&5Q=2!Z9&EV*S,X-"`[;4%42*!404),1:!/1J!&
  3581. M*%@I/5@J6"\R-38-="`G4TQ*H#$R+SDT)PT-*BTM+2TM+2TM+2TM+2TM+2TM
  3582. M+2TM+0"`J0"-(-"-(="M&-`I#PD0C1C0H`"I'X7[J8"%_$Q:@9*3!1$1$2`@
  3583. M("`@("`@("`@("!#54)%,T0@5C(N,`T-("`@("`@("`@("`@("`@("`@0ED-
  3584. MGR`@("!35$502$5.($I51$29("`@($=%3U)'12!405E,3U(-#9L@($-(14-+
  3585. M($]55"!42$4@2D%.+B`Y-2!)4U-512!/1@V6("!#/4A!0TM)3D>;($9/4B!-
  3586. M3U)%($1%5$%)3%,A#0T='9X21C$O1C*2("T@24Y#+T1%0R!8+5)/5$%424].
  3587. M#1T=$D8S+T8TDB`M($E.0R]$14,@62U23U1!5$E/3@T='1)&-2]&-I(@+2!)
  3588. M3D,O1$5#(%HM4D]4051)3TX-'1T21C>2(%)%4T544PT@(%!215-3(%$@5$\@
  3589. M455)5`T-!2`@("`@(%!215-3($%.62!+15D@5$\@0D5'24X-`+'[\"D@TO_(
  3590. MT/;F_$Q:@71(25,@25,@02!314-2150@5$585"!-15-304=%(2#D_\D`\/FM
  3591. M%M`)$(T6T*F/A2.%):D!C2'0J9,@TO^I`(TAT*E`:0R%^ZD%A?RI`*``H@`8
  3592. MD?O(:1"0^1BE^VDHA?NE_&D`A?R@`.B*X!#0Y*E`&&D,A?NIV87\H@&@`*D)
  3593. MD?O(P!#0^:7[&&DHA?NE_&D`A?R@`.B*"0@I#^`3\`K)"-#<Z`D!3.F!J56%
  3594. MQ*D`A:.I,(6DA0*M&-`I\0D.C1C0J0"%885BA6.%9(5EA698(.3_R870"Z5A
  3595. MR3SP6.9A3)^"R8G0":5A\$O&84R?@LF&T`NE8LD\\#SF8DR?@LF*T`FE8O`O
  3596. MQF),GX+)A]`+I6/)//`@YF-,GX+)B]`)I6/P$\9C3)^"R8C0`TPK@LE1T`-,
  3597. MSXMX&*5D96')>)`"Z7B%9!BE965BR7B0`NEXA648I69E8\EXD`+I>(5F.*5E
  3598. MY6:P`FEXA6<8I65E9LEXD`+I>(5H&*5D96;)>)`"Z7B%:3BE9.5FL`)I>(5J
  3599. M&*5D96C)>)`"Z7B%:SBE9.5GL`)I>(5L&*5D96?)>)`"Z7B%;3BE:.5DL`)I
  3600. M>(5N.*5EY62P`FEXA6\8I61E9<EXD`+I>(5P&*9GO0"-IFA]`(V%I:9GO8",
  3601. M.*9H_8",A::F9;V`C!`.&$G_:0$*&$G_:0%,;X,*A:<XIFZ]`(VF;?T`C3BF
  3602. M:_T`C1BF;'T`C1`.&$G_:0%*&$G_:0%,F8-*&*9I?8",.*9J_8",A:@XIFN]
  3603. M@(RF;/V`C#BF;?V`C#BF;OV`C!`.&$G_:0%*&$G_:0%,SX-*&*9I?0"-&*9J
  3604. M?0"-A:FF;[V`C#BF</V`C(6JIFR]@(PXIF[]@(PXIFW]@(PXIFO]@(P0#AA)
  3605. M_VD!2AA)_VD!3!*$2ABF:GT`C3BF:?T`C86K&*9LO0"-IFU]`(TXIFO]`(TX
  3606. MIF[]`(T0#AA)_VD!2AA)_VD!3$B$2ABF:7V`C!BF:GV`C(6L&*9OO0"-IG!]
  3607. M`(V%K4R0A&=%12!B4D%)3BP@5TA!5"!$3R!93U4@5T%.5"!43R!$3R!43TY)
  3608. M1TA4/ZE`A?>%^*6M&&6K&&6LA5>JO8"-J*6G&&6E&&6FA2(82?]I`84DL2(X
  3609. M\208:2"JI:H89:@89:F%(AA)_VD!A22Q(CCQ)!AI0,7WL`2%]Y`&Q?B0`H7X
  3610. MJ(:2A).EK1AEJSCEK(58JKV`C:BEIQAEI3CEIH4B&$G_:0&%)+$B./$D&&D@
  3611. MJJ6J&&6H..6IA2(82?]I`84DL2(X\208:4#%][`$A?>0!L7XD`*%^*B&E(25
  3612. MI:TXY:LXY:RJO8"-J*6G..6E..6FA2(82?]I`84DL2(X\208:2"JI:HXY:@X
  3613. MY:F%(AA)_VD!A22Q(CCQ)!AI0,7WL`2%]Y`&Q?B0`H7XJ(:6A*ZEK3CEJQAE
  3614. MK(59JKV`C:BEISCEI1AEIH4B&$G_:0&%)+$B./$D&&D@JJ6J..6H&&6IA2(8
  3615. M2?]I`84DL2(X\208:4#%][`$A?>0!L7XD`*%^*B&KX2P&*6G2?]I`86G&*6J
  3616. M2?]I`86J&*6M2?]I`86MI:TXY:L89:RJO8"-J*6G..6E&&6FA2(82?]I`84D
  3617. ML2(X\208:2"JI:HXY:@89:F%(AA)_VD!A22Q(CCQ)!AI0,7WL`2%]Y`&Q?B0
  3618. M`H7XJ(91A%*EK3CEJSCEK*J]@(VHI:<XY:4XY::%(AA)_VD!A22Q(CCQ)!AI
  3619. M(*JEJCCEJ#CEJ84B&$G_:0&%)+$B./$D&&E`Q?>P!(7WD`;%^)`"A?BHAG&$
  3620. M4*6M&&6K..6LJKV`C:BEIQAEI3CEIH4B&$G_:0&%)+$B./$D&&D@JJ6J&&6H
  3621. M..6IA2(82?]I`84DL2(X\208:4#%][`$A?>0!L7XD`*%^*B&LX2TI:T89:L8
  3622. M9:R%8*J]@(VHI:<89:489::%(AA)_VD!A22Q(CCQ)!AI(*JEJAAEJ!AEJ84B
  3623. M&$G_:0&%)+$B./$D&&E`Q?>P!(7WD`;%^)`"A?BHAK&$LJD`A:.E`H6DA?RI
  3624. M@(7[YO>I`*((H`"1HY'[R,3WT/>EQ)&CD?L8:55I`,C$^-#RJ0"1HY'[R!#Y
  3625. MH`#FI.;\RM#5J0"%M:6V..57<$0896!0`J5@$#NI`86UI9*%/Z63A4"EE(5!
  3626. MI96%0B"GBJ66A3^EKH5`(*>*I:^%0:6PA4(@IXJEDH4_I9.%0""GBDPIB*6V
  3627. M..5@<$$895=0`J57$#BI((6UI;&%0:6RA4*ELX4_I;2%0""GBJ5QA4&E4(5"
  3628. M(*>*I5&%/Z52A4`@IXJEL85!I;*%0B"GBJ6V..57<%`895E0`J59$$>I`@6U
  3629. MA;6FDH8_II.&0"D!T`NEE(5!I96%0B"GBJ:QAD&FLH9"(*>*IK.&/Z:TAD"E
  3630. MM2D@T`,@IXJEE(5!I96%0B"GBDS4B*6V..59<$T895=0`J57$$2I$`6UA;6F
  3631. MEH8_IJZ&0"D!T`NEKX5!I;"%0B"GBJ5QA4&E4(5"(*>*I5&%/Z52A4"EM2D@
  3632. MT`,@IXJEKX5!I;"%0B"GBJ6V..57<%P895A0`J58$%.I!`6UA;6FDH8_II.&
  3633. M0"D!T`NEKX5!I;"%0B"GBJ:QAD&FLH9"I;4I`M`#(*>*IE&&/Z92AD"EM2D@
  3634. MT`,@IXJFKX9!IK"&0J6U*1#08B"GBDR3B:6V..58<%4895=0`J57$$REE(4_
  3635. MI96%0*6U*0'0"Z66A4&EKH5"(*>*I;.%0:6TA4*EM2D"T`,@IXJE<84_I5"%
  3636. M0*6U*2#0`R"GBJ66A4&EKH5"I;4I$-`#(*>*I/>I`(6CI0*%I*((L:-%Q-`;
  3637. MD:.I@(6CL:-%Q-`/D:.%H^:DRM#E('V*3":*JBG`\`-,V(F**3#P!:D/3-2)
  3638. MJ0,QHY&CI0(8:0>%I*F`A:.QHT7$T!21HX6CL:-%Q-`*D:.I@(6CQJ30YJHI
  3639. M`_`#3!6*BBD,\`6I\$P1BJG`,:.1HQBEQ&E5:0"%Q,C$^/`#3)6)K1C020*-
  3640. M&-"I"$4"A0+N(M#.(]!,.8)S04U%(%1(24Y'(%=%($1/($5615)9($Y)1TA4
  3641. M+"!P24Y+63H@5%)9(%1/(%1!2T4@3U9%4B!42$4@5T]23$0AH@"]C(KP!R#2
  3642. M_^A,?XI@#5-/34542$E.1R!#2$]+140@.B@-`&Y!4D8AI3^%^Z5!A?VE0(7\
  3643. MI4*%_JD`A:.E`H6D.*7]Y?NP$Z7^I/R%_(3^I?ND_83[A?TXY?N%^:;[I?M*
  3644. M2DJ0!:"`A*,89:2%I#BE_N7\L`1)_VD!A?K%^;`XI/R]`(PQHY&CI?E*2?]I
  3645. M`<3^L&CH9?J0`\CE^4B]`(PP#*F`1:.%HS`"YJ2I/S&CD:-HY/W0W6"D_+T`
  3646. MC#&CD:.E^DI)_VD!Q/ZP5,AE^9`=Z.7Z2+T`C#`,J8!%HX6C,`+FI*D_,:.1
  3647. MHVA,=8M(O0",,:.1HVC$_M#18.AE^I`#B.7Y2+T`C#`,J8!%HX6C,`+FI*D_
  3648. M,:.1HVCD_=#=8(@89?F0'>CE^DB]`(PP#*F`1:.%HS`"YJ2I/S&CD:-H3,J+
  3649. M2+T`C#&CD:-HQ/[0T&"M&-`I]8T8T*T6T"GOC1;08&A!4%!9(&A/3$E$05E3
  3650. M(2!33$H@,3(O.30`````````/\_S_#_/\_P_S_/\/\_S_#_/\_P_S_/\/\_S
  3651. M_#_/\_P_S_/\/\_S_#_/\_P_S_/\/\_S_#_/\_P_S_/\/\_S_#_/\_P_S_/\
  3652. M/\_S_#_/\_P_S_/\/\_S_#_/\_P_S_/\/\_S_#_/\_P_S_/\/\_S_#_/\_P_
  3653. MS_/\/\_S_#_/\_P@TO_H3'^*8`U33TU%5$A)3D<@0TA/2T5$(#HH#0!N05)&
  3654. M(:4_A?NE087]I4"%_*5"A?ZI`(6CI0*%I#BE_>7[L!.E_J3\A?R$_J7[I/V$
  3655. M^X7]..7[A?FF^Z7[2DI*D`6@@(2C`0@D"```CR!(3TQ)1$%9(#$Y.30@+2T@
  3656. M4TQ*(#$R+S(X+SDT`$0(`0"/($E.4U!)4D5$($)9($HN($-(05).15132TD`
  3657. M5@@"`(\@04Y$($]42$524RX`>0@#`(\@5$A)4R!!3%-/(%-%5%,@55`@5$%"
  3658. M3$53($9/4@"7"`0`CR!42$4@4%)/1U)!32!#54)%,T0@5C(N,`"Y"`4`ES4Q
  3659. M+#`ZES4R+#$R.#J7-34L,#J7-38L,3(X.IP`Q0@)`(8@5B@S-BD`X`@*`)<U
  3660. M,S(X,"PP.I<U,S(X,2PP.HTT,#``_P@4`$$DLB(J*BHJ*BHJ*BHJ*BHJ*BHJ
  3661. M*B(Z4[(Q`#D)&0!2)+(B'1T='1T='1T='1T='1T='1T='1TB.D0DLB(1$1$1
  3662. M$1$1$1$1$1$1$1$1$1$1$1$1(@!9"1X`@4FR,:0Q,SI3LE.J,JPH2;(T*:HS
  3663. MK"A)LC@I`(H)*`"9(A,1$1$BR"A$)"Q)*<@H4B0L,C&K4RG(*$$D+#*L4ZLQ
  3664. M*3LZ4[)3JC$Z@@"Z"3(`F2(3(L@H1"0L,38IR"A2)"PQ.2DB$I4@("`1G9V=
  3665. M("`@$9V=G2`@()(B.P#0"3P`F2(3$1$1'1T='1T='1T%*"(`\0D^`)DB$YHB
  3666. M1"0B$1$='1T='5!!5$E%3D-%+BXN(CL`_0E!`(%)LC&D,3@`)@I&`%*RM2B[
  3667. M*#$IK#8T,*HP+C4IJC$P,C0ZBR#"*%(IL[$S,J<W,`!1"E``5BA)*;)2JC4T
  3668. M,C<R.I=2+#0V.I=6*$DI++4HNR@P*:PWJC$I.H(`7@I5`(%)LC$YI#,V`(<*
  3669. M6@!2LK4HNR@Q*:PV-#"J,"XU*:HQ,#(T.HL@PBA2*;.Q-#*G.3``L@I?`%8H
  3670. M22FR4JHU-#(W,CJ74BPX,3J75BA)*2RU*+LH,"FL-ZHQ*3J"`-L*8`"9(A.:
  3671. M(D0D(A$1'1T='1U0051)14Y#12XN+B`<U!,1$2)$)#L`_PIA`$8DLB*TG;6=
  3672. MH9T2MIVJG2`B.D,QLC$Z0S*R,#I2LC$`+PMB`%,R)+(B(%!%04-%($%.1"!"
  3673. M3$534TE.1U,@5$\@64]5($E.(#$Y.34@("(`30MC`%,DLB(@3D%51TA462!/
  3674. M4B!.24-%/R`@("(`4PMD`(\`;`MF`(\@4T54(%50(%1224<@5$%"3$53`(4+
  3675. M9P"/("TM+2TM+2TM+2TM+2TM+2TM+0"P"VD`0E.R,S4Y-C@Z0D.R0E.J,3(X
  3676. M.D):LD)#JC$R.#I"3;)"6JHS.#0`P`MN`$&R,#I$0;+_K38P`/8+>`"!2;(P
  3677. MI#$R,#I3LK4H,S*LORA!*:HP+C4I.D.RM2@S,JR^*$$IJC`N-2DZ0;)!JD1!
  3678. M``H,@@"+(%.S,""G(%.R,C4VJE,`'@R,`(L@0[,P(*<@0[(R-3:J0P`R#)8`
  3679. MET)3JDDL4SJ70D.J22Q#`#@,H`"/`%`,H@"/("TM+2TM+2TM+2TM+2TM+2TM
  3680. M`&T,I0!2,K+"*%8H,3BJ4BDI.E(QLL(H5BA2*2D`E@RJ`)=6*%(I+%(R.I=6
  3681. M*%*J,3@I+%(Q.E*R4JHQ.HM2LC$YIU*R,0#&#*\`BT,QL3$RIT,QLC$Z0S*R
  3682. M0S*J,3J9(ITBRBA3)"Q#,BPQ*2*2(CLZB3$Y,`#?#+0`F<HH1B0L0S$L,BD[
  3683. M.D,QLD,QJC(`]PRY`(\@+2TM+2TM+2TM+2TM+2TM+2T`_PR^`((@20`%#<,`
  3684. MCP!.#<@`0S*R,#I3)+)3,B0ZF2(3(D0D(A$1("`@("`@("`@("`@(`5.24-%
  3685. M(2`@("`@("`@("`@("`@("`@(""9M!,1$2)$)#L`60W2`(%)LC&D.0"*#=P`
  3686. M4K*U*+LH,"FL,RFL-#"JM2B[*#`IK#$S*:HQ-S4Y.HO"*%(IL[$S,J<R,C``
  3687. ML`WF`)=2+#(Q.3J74JHU-#(W,BRU*+LH,"FL.*HQ*3J".E*R,0"V#>D`CP#8
  3688. M#>H`CR!3150@55`@355,5"!!3D0@4%)/2B!404),15,`^@WK`(\@+2TM+2TM
  3689. M+2TM+2TM+2TM+2TM+2TM+2TM+2TM``D.\`!$LC$W,#I:,+(U`"4.^@!+LK4H
  3690. M-C2L,JU:,*HP+C4I.I<Q.#(L2P!'#@0!@4JR,*0R-34Z6K)*.HL@6K$Q,C<@
  3691. MIUJR6JLR-38`8`X.`5&RM2A$K2A:,*M:K38T*:HP+C4I`'0.$0&+(%&Q,3(W
  3692. M(*<@4;(Q,C<`B@X3`8L@4;.K,3(W(*<@4;*K,3(W`)X.%`&+(%&S,""G(%&R
  3693. M,C4VJE$`J@X8`9="6JI*+%$`Q`XB`5.R2CJ+(%.Q,34P(*<@4[(R-3:K4P#9
  3694. M#BP!4;*U*%.L4ZTR-3:J,"XU*0#S#C8!ER!"3:I*+%$ZER!"3:I*JC(U-BQ1
  3695. M`/D..P&/``@//`&/("TM+2TM+2TM`"4//@%2,K+"*%8H,3BJ4BDI.E(QLL(H
  3696. M5BA2*2D`3@]``9=6*%(I+%(R.I=6*%*J,3@I+%(Q.E*R4JHQ.HM2LC$YIU*R
  3697. M,0!^#TH!BT,QL3$RIT,QLC$Z0S*R0S*J,3J9(ITBRBA3)"Q#,BPQ*2*2(CLZ
  3698. MB3,U,`"7#U0!F<HH1B0L0S$L,BD[.D,QLD,QJC(`I@]9`8\@+2TM+2TM+2T`
  3699. MK@]>`8(@2@#(#V@!GC,R-S8X.IDB2$\A($A/(2!(3R$B`.0/:0&9(D5-04E,
  3700. M(%-*541$0$Y752Y%1%4@(@`&$&H!F2(@+4]2+2!!038P,4!#1DXN0U,N1$%,
  3701. M+D-!("(`'!!K`9DB$4]2(%=2251%(%1/.B`B`#L0;`&9(B`@("!35$5612!*
  3702. M541$("`@("`@("`@(@!:$&T!F2(@("`@,3$P,"!'4D]612`C0E<@("`@("(`
  3703. M>1!N`9DB("`@($5604Y35$].+"!)3"`V,#(P,2`B`)@0<@&9(B`@("`@("`@
  3704. M("`@("`@("`@("`@("`@(@">$(8!@`#-$)`!ES(Q-"PR,CJ9(I8B.H%)LC&D
  3705. M,S@Z022R022J(M8B.D(DLD(DJB(@(CJ"`.T0F@%!)+)!)*HBUM:1D2(Z@4FR
  3706. M,:0R-#J9020[.H(`'!&D`9DB$QT1'B([.D(DLD(DJB(='2(Z@4FR,:0R,CJ9
  3707. M0B0[.H(ZF2(3$2(ZC@```"DI`$X/0`&75BA2*2Q2,CJ75BA2JC$X*2Q2,3I2
  3708. MLE*J,3J+4K(Q.:=2LC$`?@]*`8M#,;$Q,J=#,;(Q.D,RLD,RJC$ZF2*=(LHH
  3709. M4R0L0S(L,2DBDB([.HDS-3``EP]4`9G**$8D+$,Q+#(I.SI#,;)#,:HR`*8/
  3710. M60&/("TM+2TM+2TM`*X/7@&"($H`R`]H`9XS,C<V.#J9(DA/(2!(3R$@2$\A
  3711. M(@#D#VD!F2)%34%)3"!32E5$1$!.5U4N1415("(`!A!J`9DB("U/4BT!""8(
  3712. M"@"9(I,%3D]415,@1D]2($-50D4S1#(N,"!!3D0@,BXQ(@!-"!0`F2(13$]!
  3713. M1"!42$4@+D\@3T)*14-4($9)3$4@0D5&3U)%(@!F"!X`F2),3T%$24Y'($E.
  3714. M250S1#(N,"(`C@@H`)DB5$A%(%)%3$5604Y4($Q)3D53($E.($E.250S1"!!
  3715. M4D4B`+`(,@"9(DQ)3D53(#$P,"TQ-3`@04Y$(#(S,RTS,3`N(@#1"#P`F2)$
  3716. M($%.1"!:,"!!4D4@24X@3$E.12`R-#`N(@#\"$8`F2(1248@64]5(%1262!4
  3717. M3R!#2$%.1T4@4T]-151(24Y'($%.1"(`)PE0`)DB1T54($%.(#])3$Q%1T%,
  3718. M(%%504Y42519($524D]2($I54U0B`#@)6@"9(E194$4@0TQ2+B(`9`ED`)DB
  3719. M$1*>248@64]5(%=!3E0@5$\@4E5.($-50D4S1#(N,2!-04M%(@","6X`F2(2
  3720. M4U5212!43R!#2$%.1T4@1"!)3B!,24Y%(#(T,"!43R(`I`EX`)DB$D0].#4@
  3721. M050@34]35"$A(2(`T@F"`)DB$0533TU%($]&(%1(12!:15)/(%!!1T4@3$]#
  3722. M051)3TY3(%53140B```*C`"9(DU!62!(3U-%($)!4TE#("TM(%)%0D]/5"!"
  3723. M149/4D4@4T%624Y'(@`4"I8`F2)!3ED@0TA!3D=%4RXB`$,*H`"9(A%+1450
  3724. M($E.($U)3D0@5$A!5"!93U4@0T%.(%!215-3($8Q($540R(`<@JJ`)DB355,
  3725. M5$E03$4@5$E-15,@5$\@4U!%140@55`@5$A%(%)/5$%424].(@","K0`F2(1
  3726. M$2A04D534R!!3ED@2T59*2([`)\*O@"A020ZBT$DLB(BIS$Y,`#,"L@`F2*3
  3727. M0U5"13-$,BXQ($9%05154D53($U53%1)0T],3U(@04Y$($%.(@#V"M(`F2)!
  3728. M4%!!3$Q)3D=,62!44DE624%,(%1%6%154D4@34%0($]&(@`A"]P`F2)!(%-/
  3729. M4E0@+2T@250@5T%3($A!0TM%1"!43T=%5$A%4B!!5"(`30OF`)DB5$A%($Q!
  3730. M4U0@34E.551%+"!!3D0@5TE,3"!"12!44D5!5$5$(@!R"_``F2))3B!-3U)%
  3731. M($1%5$%)3"!)3B!42$4@1E5455)%+B(`G@OZ`)DB$5=%($A/4$4@64]5($Q)
  3732. M2T4@5$A%4T4@4%)/1U)!35,@04Y$(@"W"P0!F2)&24Y$(%1(14T@55-%1E5,
  3733. M(2(````:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:
  3734. 6&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:
  3735. `
  3736. end
  3737.  
  3738. ==============================================================================
  3739. 2D Graphics Toolbox -- Circles
  3740. by Stephen Judd  (sjudd@nwu.edu)
  3741.  
  3742. 3D is fun and interesting but in the end we must always display our work on a
  3743. two-dimensional surface, the CRT.  Not only are two-dimensional algorithms
  3744. the foundation of three-dimensional drawings, they are of course useful for
  3745. many other applications.  This new series of articles is intended to
  3746. complement (hah -- get it?) the 3D articles by George and myself.  Between
  3747. the two articles you should have at your disposal a powerful graphics toolbox
  3748. for all of your applications.
  3749.  
  3750. The foundation of all of our drawings is a single point, and a logical next
  3751. step would be a line.  Algorithms for doing both of these things were
  3752. discussed in depth in the first article of the 3D series, so you can look
  3753. those up in a back-issue of C=Hacking.  What is next after points and lines?
  3754. Curves!  So to start with, let's think about drawing a circle.
  3755.  
  3756. You can write the equation for a circle in many ways, depending on your
  3757. coordinate system.  In cartesian coordinates, the equation of a circle is:
  3758.  
  3759.         x^2 + y^2 = r^2            (1)
  3760.  
  3761. This is a circle centered at the origin (on a computer we can always
  3762. translate the points wherever we want), with radius r.  In polar coordinates
  3763. the equation is r=const.  We can write down trigonometric relations out the
  3764. wazoo, too, but no matter what it looks like we're going to have some
  3765. complicated math ahead of us involving multiplications and worse, i.e.
  3766. time-intensive computations.  Perhaps the simplest of these would be:
  3767.  
  3768.         x=r*cos(theta)
  3769.         y=r*sin(theta)
  3770.  
  3771. where theta runs from zero to 2*pi.  If we have a table of sines and cosines,
  3772. and use the fast multiplication algorithm given in this months 3D article, we
  3773. have a routine which gives a good circle in around 50 cycles or so per pixel,
  3774. sans plot.
  3775.  
  3776. But let's step back and consider: the above equations all give a "perfect"
  3777. circle.  Is there any way we can draw an "approximate" circle, with a large
  3778. speed increase?  The answer is of course yes, since this wouldn't be a very
  3779. interesting article otherwise!
  3780.  
  3781. Let's say we are standing at a point on the circle, and want to take a step
  3782. towards the next point.  In what direction do we take this step?  Consider a
  3783. line tangent to the circle, touching the point where we are standing.  If we
  3784. take a little step in that direction, we ought to get close to the next point
  3785. on the circle. The way to calculate the tangent line is to use the
  3786. derivative, which will give us the slope of the tangent.  Taking
  3787. differentials of equation (1) above we have
  3788.  
  3789.         2*x dx + 2*y dy = 0
  3790. or
  3791.         dy/dx = -x/y
  3792.  
  3793. Now, if I am at a point (x,y), I want to take a little step in x and a little
  3794. step in y:
  3795.  
  3796.         x = x+dx
  3797.         y = y+dy
  3798.  
  3799. but from the first equation we know that dx = -y/x * dy so that at each step
  3800. our iteration is
  3801.  
  3802.         y = y + dy
  3803.         x = x - dy*(y/x)
  3804.  
  3805. This is the basis of our algorithm.  You could also of course use
  3806.  
  3807.         x = x + dx
  3808.         y = y - dx*(x/y)
  3809.  
  3810. (this is called Euler's method for solving a differential equation, and these
  3811. concepts are fundamental to most algorithms for solving differential
  3812. equations numerically).
  3813.  
  3814. Let's start at the point x=r,y=0 i.e. the right-endpoint of the circle.
  3815. Since we are on a computer we want to take a step of length one in some
  3816. direction (i.e. step one pixel), and at this point on the circle y is clearly
  3817. increasing much faster than x. You may remember from the line drawing
  3818. algorithm that we viewed the process as "keep taking steps in x until it is
  3819. time to take a step in y". We are going to apply that same philosophy here:
  3820. keep taking steps in y until it is time to take a step (backwards) in x.  So
  3821. our iteration is now:
  3822.  
  3823.         y_{n+1} = y_n + 1
  3824.         x_{n+1} = x_n - y_n/x_n
  3825.  
  3826. Hmmm... we have this little problem now of y/x.  I certainly don't want to
  3827. deal with floating point.  How do we get around this?  The trick is to think
  3828. of x as a _discrete_ variable -- as far as a pixel is concerned x is just an
  3829. integer, and has no floating point part.  So we are going to treat x as a
  3830. constant, until it is time to decrease x by one! When does this happen?
  3831. Let's expand the x-iteration:
  3832.  
  3833.     x_{n+1} = x_n - y_n/x_n
  3834.         = (x_{n-1} - y_{n-1}/x_{n-1}) - y_n/x_n
  3835.  
  3836. This is where the magic of using a discrete x comes in.  If we make this
  3837. assumption of constant x, then x_{n-1} = x_n and the above iteration becomes
  3838.  
  3839.     x_{n+1} = x_{n-1} - (y_{n-1} + y_n)/x_{n-1}
  3840.  
  3841. If we continue this process over an interval where x is constant we get
  3842.  
  3843.     x_{n+1} = x_0 - (y_n + y_{n-1} + y_{n-2} + ...)/x_0
  3844.  
  3845. When is it time to decrease x?  When the sum of the y values at each
  3846. iteration exceeds the current x-value the fraction above will be greater than
  3847. one, and we will then decrease x.  Like I said, we keep x constant, until it
  3848. is time to decrease it! :)
  3849.  
  3850. How long do we do this for?  In the same way that at x=r y increases much
  3851. faster than x does, when y=r x increases much faster than y does.  Somehwere
  3852. in-between they have to be increasing at the same rate, which means the slope
  3853. of the tangent line is equal to +/-1, i.e. at the point x=y.  At this point
  3854. we have drawn one-eighth of the circle.  We can either draw all eight
  3855. segments of the circle independentally, or else we can use the symmetry of a
  3856. circle and do an 8-way plot.
  3857.  
  3858. TO SUMMARIZE: Here is the basic algorithm
  3859.  
  3860.     x=r
  3861.     y=0
  3862.     a=0
  3863.     :loop
  3864.     y=y+1
  3865.     a=a+y
  3866.     if a>x then x=x-1:a=a-x
  3867.     plot8(x,y)
  3868.     :until x<=y
  3869.  
  3870. Of course you can refine this in several ways, which will speed things up in
  3871. assembly.  For instance, if instead of a=0 we start with a=x, then the logic
  3872. becomes
  3873.  
  3874.     a=a-y
  3875.     if a<0 then x=x-1:a=a+x
  3876.  
  3877. To do the a=a-x you could use a table where f(x)=x, or you might try
  3878. something else; here is some code in assembly:
  3879.  
  3880.     LDX R
  3881.     LDY #00
  3882.     STY Y
  3883.     TXA
  3884. :loop    JSR PLOT8    ;Eight-way symmetric plot
  3885.     SEC         ;Might not need this depending on PLOT8
  3886.     INC Y        ;Y is in zero page
  3887.     SBC Y
  3888.     BCS :loop
  3889.     DEX
  3890.     STX X        ;X is also in zero-page
  3891.     ADC X        ;Carry is already clear
  3892.     CPX Y
  3893.     BCS :loop
  3894.     JSR PLOT8    ;Catch the last point
  3895.  
  3896. Starting at :loop we have 2+3+3+3=11 cycles in the best case and
  3897. 2+3+3+2+2+3+3+3+3=24 cycles in the worst case, excluding PLOT8.  You can, of
  3898. course, change the program logic around; if PLOT8 returned with the carry
  3899. always clear it would be much smarter to start A as A=256-A and use A=A+Y at
  3900. each step instead of A=A-Y.  Christopher Jam (phillips@ee.uwa.edu.au)
  3901. suggested starting at X=Y(=R/sqrt(2)) so that the CPX Y instruction could be
  3902. removed (I don't know how this affects accuracy, though).
  3903.  
  3904. "Yeah, but how well does it work?"  Quite well, as a matter of fact.  It will
  3905. draw a perfect circle for circles with a radius greater than twelve or so.
  3906. For circles with a smaller radius the sides start to flatten out, and the
  3907. circle becomes squareish.  Interestingly, the "discrete x" approximation
  3908. improves the result over the straight floating-point calculation
  3909. significantly!
  3910.  
  3911. So this is the best algorithm I was able to come up with for drawing a
  3912. circle.  If you have any suggestions for improvements or other ideas, please
  3913. feel free to share them :).  As always I must thank George Taylor and
  3914. Christopher Jam for their suggestions and for helping me work out some ideas.
  3915.  
  3916. If you have any particular 2D algortihms/calculations that you would like to
  3917. see, please feel free to suggest future topics for the 2D graphics toolbox.
  3918.  
  3919. Finally, here is a BASIC7.0 program which demonstrates the algorithm:
  3920.  
  3921. 0 REM FAST CIRCLE -- SLJ 9/94
  3922. 10 GRAPHIC 1,1
  3923. 15 REM X=Radius
  3924. 20 X=40:Y=0:TX=X:XO=160:YO=100
  3925. 30 DRAW1,X+XO,Y+YO:DRAW1,Y+XO,X+YO
  3926. 40 DRAW1,XO-X,YO+Y:DRAW1,XO-Y,YO+X
  3927. 50 DRAW1,XO-X,YO-Y:DRAW1,XO-Y,YO-X
  3928. 60 DRAW1,XO+X,YO=Y:DRAW1,XO+Y,YO-X
  3929. 70 IF X<=Y THEN 100
  3930. 80 Y=Y+1:TX=TX-Y
  3931. 90 IF TX<0 THEN X=X-1:TX=TX+X
  3932. 95 GOTO 30
  3933. 100 END
  3934.  
  3935. ===========================================================================
  3936. AFLI-specs v1.0
  3937. by written by D'Arc/Topaz for Chief/Padua on 28.6.1994
  3938.  
  3939. Advanged FLI is name I came up with during the time I coded the
  3940. first version of AFLI editor. I have never claimed to be the one
  3941. who discovered this new graphics mode for 64. I myself give the
  3942. credit for COLORFUL/ORIGO but I am not sure if anyone did it
  3943. before him (splits have been done but in my eyes they don't count).
  3944.  
  3945. In AFLI we can get 120 colors in theory (counted like this
  3946. 16!/(2!*14!)=120). When we put red and blue hires pixels close to
  3947. each other we get a vision of purple - thanks the television.
  3948.  
  3949. AFLI is just like FLI with $08-$0f (hires value) in $d016 and a
  3950. couple of sprites over the first three marks. With $d018 we
  3951. change the start of screen memory. And the good old $d011 for the
  3952. main work.
  3953.  
  3954. AFLI is the same as FLI but we don't use the $d800-$dc00 area
  3955. for the third color. Actually we can't. In normal hires pictures
  3956. the colors on the picture is ordered in a normal screen (normal
  3957. text screen is on $0400+). The upper 4 bits is the color for
  3958. bit 0 in picture bitmap and the lower 4 bits is the color for bit
  3959. 1 in picture bitmap (or the other way...but let us think that was
  3960. the right way).
  3961.  
  3962. For example: a normal hires picture char (8x8 bits)
  3963.  
  3964.  01234567  in hires picture where  01234567
  3965. 0 *****    the first spot of the  0bgggggbb
  3966. 1*** ***   screen has a value of  1gggbgggb
  3967. 2*** ***   $68 (blue&green) the   2gggbgggb
  3968. 3*******   hires picture looks    3gggggggb
  3969. 4*** ***   like this ---->        4gggbgggb
  3970. 5*** ***   b=blue, g=green        5gggbgggb
  3971. 6*** ***                          6gggbgggb
  3972. 7                                 7bbbbbbbb
  3973.  
  3974. The bitmap is built just as in a hires picture bit 1 means the pixel
  3975. is on and 0 that the pixel is off.
  3976.  
  3977. In FLI we have built the screen to have badlines on every scanline of
  3978. the screen. This gives us the possibility to change the screenmemory
  3979. the picture uses on everyline. Now... when AFLI (and FLI) uses screen
  3980. memory for colors and we change the screenmemory start on everyline,
  3981. we can have new colors on everyline.
  3982.  
  3983. The screens are usually ordered like this.
  3984.  
  3985. screen memory used
  3986.    0   $4000-$43ff
  3987.    1   $4400-$47ff
  3988.    2   $4800-$4bff
  3989.    3   $4c00-$4fff
  3990.    4   $5000-$53ff
  3991.    5   $5400-$57ff
  3992.    6   $5800-$5bff
  3993.    7   $5c00-$5fff
  3994.        $6000-$7fff BITMAP (the actual picture data)
  3995.  
  3996. The number of the screen is considered as the number of the line in
  3997. 8x8 pixel area.
  3998.  
  3999. An example... Here we have cut from the memory showing the first
  4000. bytes in every screen.
  4001.  
  4002. screen/rownumber
  4003.            00 01 02 03 04 05 06 07 08 09 10 11 12 13 ... 39
  4004.      $4000 ff ff ff 56 .. .. ..
  4005.      $4400 ff ff ff 67 .. ..
  4006.      $4800 ff ff ff 91 ..
  4007.      $4c00 ff ff ff b3
  4008.      $5000 ff ff ff 54
  4009.      $5400 ff ff ff 8f
  4010.      $5800 ff ff ff 54
  4011.      $5c00 ff ff ff 10
  4012.  
  4013. Actually the $ff won't have to be there. It will come to the screen
  4014. anyway. We have the same 'A' on the screen on the fourth mark ($6018-
  4015. $601f).
  4016.  
  4017.   BITMAP               AFLI PICTURE (number is the color number)
  4018.  01234567 screenvalue    01234567
  4019. 0 *****       $56      0 56666655   1=white, 0=black, 2=red ...
  4020. 1*** ***      $67      1 77767776
  4021. 2*** ***      $91      2 11191119
  4022. 3*******      $b3      3 33333333
  4023. 4*** ***      $54      4 44454445
  4024. 5*** ***      $8f      5 fff8fff8
  4025. 6*** ***      $54      6 44454445
  4026. 7             $10      7 11111111
  4027.  
  4028. Now the 'A' surely has a lot of colors.
  4029.  
  4030.  
  4031. When we code a FLI routine we know that we have succeeded when we get
  4032. a 3 marks wide area filled with value $ff on the screen. In FLI the
  4033. thing is easily taken away; we just fill the three first bytes of a
  4034. line with empty bytes ($00). In AFLI the value $ff is a color. If we
  4035. try to clear the three first marks, we still have the gray area. WHY?
  4036. The $ff value comes to the screen.. so... the $ff is a color and
  4037. the upper four bits of the byte is the color for empty pixels. We can
  4038. not clear the first three marks to wipe the thing off. We have a new
  4039. lovely problem: we have to put black (or whatever) sprites over that
  4040. area. This is just timing.
  4041.  
  4042.  
  4043. This may look very complicated and I think you will still be asking
  4044. many questions from me - the text I have written surely ain't the
  4045. best novel ever written. I'm great in jumping from a thing to
  4046. another.
  4047.  
  4048.  
  4049. --
  4050. Chief/Padua                          +44 (0) 757 706791
  4051.                               --------------------
  4052.                         My opinions are not my employers
  4053. ===========================================================================
  4054. Coding Tricks
  4055.  
  4056. The following are messages posted to comp.sys.cbm that contain little "coding
  4057. tricks" that I thought were useful. If you've got any of your own that you want
  4058. to post feel free to email them to me and I'll post them to comp.sys.cbm -
  4059. duck@pembvax1.pembroke.edu.
  4060. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  4061. From: paulvl@python.es.ele.tue.nl (Paul van Loon)
  4062. Date: 11 Oct 1994 14:28:49 GMT
  4063.  
  4064. Hello everyone,
  4065.  
  4066. I really would like to start a thread on your favorite
  4067. sequences of 6502 code. I hope much people will react
  4068. so we can build up a library of the most beautiful
  4069. 6502 code ever seen.
  4070. I would suggest little code fragments, probably not
  4071. longer than 10 lines, doing some tiny function.
  4072.  
  4073. I propose the following standard:
  4074.  
  4075. -----------------------
  4076. <xxx> <yyyyy> "text"
  4077.       <aaa>   ; comment
  4078.       <bbb>   ; comment
  4079.  
  4080. "description"
  4081. -----------------------
  4082.  
  4083. where <xxx> is the symbolic name (3 letters?) you give
  4084. to your code sequence, <yyyyy> describes your arguments
  4085. "text" gives a full name to pronounce for the symbolic name
  4086. and <aaa> and on are the 6502 instructions you use. "description"
  4087. is a description of the functionality of your code. The lines
  4088. with "---" are seperators.
  4089.  
  4090. I will hereby start with my all-time favourite code,
  4091. I discovered it only recently and I will also
  4092. show some examples of how to use it!
  4093.  
  4094. ---------------------------------------
  4095.  
  4096. B7C        "Bit 7 to Carry"
  4097.     cmp #$80
  4098.  
  4099. This instruction copies bit 7 of A to C
  4100. ---------------------------------------
  4101.  
  4102. This is really a beauty! It works because
  4103. cmp clears the carry if A is below the immediate
  4104. value, and sets it if A is higher or same.
  4105. All values lower than $80 have bit 7 equal 0,
  4106. cmp will clear C for all values below $80, and
  4107. thus will 'copy' bit 7 into carry. All values
  4108. equal or above $80 will have bit 7 equal 1,
  4109. cmp will set C for all values above $80 and
  4110. thus for this case it will also 'copy' bit 7
  4111. into carry!
  4112.  
  4113. ------------------------------------------
  4114. ASR        "Arithmetic Shift Right"
  4115.     B7C
  4116.     ror
  4117.  
  4118. This instruction does a signed divide by 2
  4119. ------------------------------------------
  4120.  
  4121. Again a beauty in my eyes! I have puzzled
  4122. many times who to write the on other CPUs
  4123. well-known ASR instruction, but I never
  4124. seemed to get it implemented without an
  4125. extra register to use like:
  4126.     tax
  4127.     asl
  4128.     txa
  4129.     ror
  4130. or even without a branch (figure that out
  4131. yourself!).
  4132.  
  4133. With these two beauties I want to give you
  4134. an idea of what I mean, and please follow me
  4135. up!.
  4136.  
  4137. BONUS. A little routine to clear the screen
  4138. without erasing the sprite pointers.
  4139.  
  4140. -----------------------------
  4141. CLS        "Clear the screen"
  4142.     ldx #250
  4143.     lda #$20
  4144. clp sta $0400-1,x   ;  0-249
  4145.     sta $0400+249,x ;250-499
  4146.     sta $0400+499,x ;500-749
  4147.     sta $0400+749,x ;750-999
  4148.     dex
  4149.     bne clp
  4150.  
  4151. Clear only the screen
  4152. ----------------------------
  4153.  
  4154. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  4155. From: paulvl@python.es.ele.tue.nl (Paul van Loon)
  4156. Subject: Re: Post your favourite little code too!
  4157. Date: 20 Oct 1994 12:17:40 GMT
  4158.  
  4159. -------------------------------------
  4160. RSL    "Rotate Straight Left"
  4161.     B7C
  4162.     rol
  4163.  
  4164. This instruction does a rotation left
  4165. through 8 bits (rol does a rotation
  4166. left through 9 bits, 8 bits of A
  4167. and 1 bit C)
  4168. -------------------------------------
  4169.  
  4170. Another useful instruction, for
  4171. a wraparound rol, e.g. for rotating
  4172. bytes in characters to simulate
  4173. parallax scrolling.
  4174.  
  4175. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  4176.  
  4177. A reliable way to create a Straight IRQ?
  4178.  
  4179. Well, this is the way I've always used, because it's reliable, flexible
  4180. doesn't mess up, or set restictions on the display, unlike routines that
  4181. depend on D011 etc...
  4182. This one only observes the VIC chip:
  4183.  
  4184. It's some time since I actually coded a routine of this kind,
  4185. and I'm writing this off memory, so there might be some errors in the
  4186. following code.
  4187.  
  4188.    <irq is initiated in the usual way, I almost always use FFFE/FFFF instead
  4189.     of 0314/0315 for interrupt vectors, but the routine should work with
  4190.     0314/315, but delay timing will be different becouse of the time being
  4191.     up by the kernal>
  4192.  
  4193.    <Set up irq vector to label 'irq1' and program desired rasterline with
  4194.     d012 & $ d011 in the usual way>
  4195.  
  4196.     <other initiation of program>
  4197.                 ...
  4198.  
  4199.                 jmp mainPrg
  4200.  
  4201. ;----------- Standard routines for all sharp irqs ----------------
  4202.  
  4203. sharp           inc $d012                 ;Set interrupt to the next line.
  4204.                 inc $d019                 ;Ready for new interrupt
  4205.                                           ;same as lda #1 : sta $d019
  4206.                 sta storeA
  4207.                 lda #<sharpirq
  4208.                 sta $fffe                 ;Alter interrupt vector
  4209.                 lda #>sharpirq
  4210.                 sta $ffff
  4211.                 cli                       ;Allow new interrupt even if we
  4212.                                           ;still are in the previos irq call
  4213. noploop
  4214.                 nop
  4215.                 nop             ; We add nop's here so that the next interrupt
  4216.                                 ; will interrupt while we are executing nop
  4217.                 ...             ; commands. Since nop commands use two cycles
  4218.                 ...             ; the interrupt will at most be delayed 1
  4219.                 ...             ; cycle.
  4220.                 ...             ; I think we needed about 11 nop's to be sure
  4221.                                 ; that execution is interrupted while they are
  4222.                                 ; run. (I'm not sure about this number)
  4223.  
  4224.                 jmp noploop     ; Although we are sure that the interrupt will
  4225.                                 ; interrupt before we reach this point, we
  4226.                                 ; add this loop to be on the safe side.
  4227.                                 ; Imagine if the program happened to be frosen
  4228.                                 ; by a carterigde and later restarted while
  4229.                                 ; executing the nop's.
  4230.  
  4231.  
  4232. sharpirq        pla             ; Delete data put to stack by the last
  4233.                 pla             ; interrupt, we don't intend to return from
  4234.                 pla             ; it.
  4235.                 stx storeX
  4236.                 sty storeY
  4237.  
  4238.                 nop             ; Now we only have an uncertainty of 1 cycle
  4239.                 nop             ; as to where the interrupt is.
  4240.                                 ; By waiting until the edge of the current
  4241.                                 ; rasterline we can determine if the interrupt
  4242.                 ...             ; was delayed by one cycle or not.
  4243.                 ...             ; (How many nop's that is required to reach the
  4244.                 ...             ; edge of the rasterline i don't remember.
  4245.                                 ; You'll just have to find it out yourself)
  4246.                                 ; These nop's may of course be exchanged by
  4247.                                 ; equivelent time consuming instructions.
  4248.  
  4249.                 lda $d012       ; get current rasterline
  4250.                 cmp $d012       ; still on same line = was delayed;
  4251.                 bne addCycle    ; add 1 cycle if not delayed.
  4252. addCycle                        ; doing a branch jump takes 1 cycle more than
  4253.                                 ; not doing one.
  4254.  
  4255.                                 ; the rastertiming is now 'straight'/sharp
  4256.                 rts             ; return to routine that cal led sharp
  4257.  
  4258.  
  4259. endIrq                          ; restore a x y
  4260. storeA          = * + 1
  4261.                 lda #0          ; For those who don't like self modifying code
  4262. storeX          = * + 1         ; this can be changed easy.
  4263.                 ldx #0
  4264. storeY          = * + 1
  4265.                 ldy #0
  4266.                 rti             ; Return from interrupt.
  4267.  
  4268. nextIrq
  4269.                 stx $fffe
  4270.                 sty $ffff
  4271.                 sta $d012
  4272.                 inc $d019       ;or lda #1 : sta $d019 if you prefere
  4273.                 rts
  4274.  
  4275. ;------------------ The actual interrupt ------------------------------
  4276.  
  4277. irq1
  4278.                 jsr sharp       ;Make interrupt sharp and store A X Y regs.
  4279.  
  4280.         <here you put your sharp interrupt dependant code>
  4281.  
  4282.         <other code that you need executed this interrupt>
  4283.  
  4284.                 ldx #<irq<?>    ;<?> is the next interrupt that is due
  4285.                 ldy #>irq<?>    ;1 if irq1 is the only interrupt.
  4286.                 lda #<rasterline for interrupt>
  4287.                 jsr nextIrq
  4288.  
  4289.                 jmp endIrq
  4290.  
  4291. ;--------------- Main program ---------------------------------
  4292.  
  4293. mainPrg
  4294.                 cli             ;allow interrupt
  4295.  
  4296.         <wait for space or something>
  4297.  
  4298.                 sei
  4299.  
  4300.         <shut everything down and restore what needs to be restored>
  4301.  
  4302.                 rts             ; Or jmp exitCode
  4303.  
  4304. *******************************************************************
  4305.  
  4306. By adding this routine:
  4307.  
  4308. saver           sta storeA
  4309.                 stx storeX
  4310.                 sty storeY
  4311.                 rts
  4312.  
  4313. ...you can at any time turn on/off the sharping by exchanging 'jsr sharp'
  4314. and 'jsr saver'.
  4315.  
  4316. I hope this is what you were looking for. Sorry for not supplying a
  4317. complete source, but as I said this is all from memory.
  4318.  
  4319. PS. My native lanuage is not english and I typed this in a hurry, so sorry
  4320. for the lousy lanuage / source.
  4321.  
  4322. Furhermore, ways of getting an rnd.
  4323.  
  4324. * lda $d012, only in large complex programs with lots of variable execution
  4325.              times where rnd is only needed once in a while.
  4326.              (Never use in raster interrupts of obvious reasons)
  4327.  
  4328. * lda $d800     ; The 4 upper bits of mem at area $d800 - $dc00 are completly
  4329.   lsr           ; unpredictable...
  4330.   lda $d801
  4331.   lsr
  4332.   lda $d802
  4333.   ...
  4334.  
  4335. * Read the values from the white noise generator to the SID.
  4336.   3rd voice set to whitenoise, and read the result.
  4337.   (sorry don't remember address to read, think it is around $d416-$d41c)
  4338.  
  4339. These give you _true_ random numbers. It's also possible to create
  4340. 'random' routines that create 'random' numbers based on a seed value.
  4341.  
  4342. Anything unclear? Mail me at s514@ii.uib.no
  4343.  
  4344. Bye...
  4345.  
  4346.  - Rolf Wilhelm Rasmussen
  4347.  
  4348.  Equal of Eternity
  4349.  
  4350. ===========================================================================
  4351. C.S. Bruce Interview
  4352. by Craig Taylor (duck@pembvax1.pembroke.edu).
  4353.  
  4354. The following is an interview of Craig Bruce, author of numerous programs such
  4355. as ZED, ACE etc for the Commodore 64/128.
  4356.  
  4357. > What computer experience did you have before the Commodore computers?
  4358.  
  4359. Very little.  I was 14 at the time, in grade nine, and it was December 1982.
  4360. My Jr. High school had a few CBM 8032s, but I never actually got to touch
  4361. one.  I took a "mini course" on computers and learned a tiny little bit about
  4362. what computers were like and about BASIC.  To give you an idea of how little
  4363. I learned, I was entirely incapable at the time of figuring out how to
  4364. increment a variable (X=X+1).
  4365.  
  4366. > What was your first Commodore computer and why?
  4367.  
  4368. My first computer was a VIC-20.  I had the choice narrowed down to a VIC, a
  4369. TI99-4A, or a Timex/Sinclair 1000(?).  (I don't think I had heard of the
  4370. Ataris or the Apple).  I chose the VIC partly because it was related to the
  4371. computers at school but mostly because it had the most impressive brochure
  4372. and I had the most information about it.  It was theoretically a Christmas
  4373. present, but it didn't stay in the box very long.  I paid half of the $400.00
  4374. price tag and my parents paid the other half.
  4375.  
  4376. > How did you learn programming on the Commodore? Did experience from other
  4377.   PC's help?
  4378.  
  4379. Ahhh, those were the days.  I learned programming from a few sources.  The
  4380. user's guide that came with the VIC was quite helpful, and I read the
  4381. magazines of the day, mostly Compute!s.  I also had a friend who went to high
  4382. school and used the computers there who knew a thing or two, and two other
  4383. friends who got VIC-20s soon after me, so we learned from each other.
  4384.  
  4385. I also took a relatively informal night course that was offered for
  4386. programming VIC-20s.  By the time I took it, though, I had already learned
  4387. just about everything that the course tought: BASIC.  Then, in the last
  4388. class, the instuctor talked just a little bit about machine langauge, just
  4389. enough for me to understand what was in the VIC-20 Programmer's Reference
  4390. Guide.  I learned 6502 machine language shortly after that.
  4391.  
  4392. Experience from other PCs didn't really factor into things, since I had no
  4393. experience with any other PC.  However, when the time came to learn about
  4394. other computers and other programming languages (in high school and bachelor
  4395. university), I had an enormous advantage over the other students, since I
  4396. understood so thoroughly how computers worked because of my VIC-20
  4397. experience.
  4398.  
  4399. > What other interests, besides hacking on the Commodore, do you have?
  4400.  
  4401. Not many.  I don't get out much and I have only a handful of friends.  I
  4402. spend most of my time sleeping, watching TV, net surfing, doing school work,
  4403. and/or hacking on Commodores.  Hacking on Commodores is in my blood.  While
  4404. I'm doing these other things, I'm usually thinking about hacking on
  4405. Commodores.  You might say that I'm a sterotypical total computer geek.  I do
  4406. like biking, though.  I bike to school every day.  And music.
  4407.  
  4408. > What is your feelings on the demise of Commodore?
  4409.  
  4410. Losing Commodore was a little sad, but as someone said on the newsgroup when
  4411. Commodore went under, "What has Commodore done for you lately?".  We
  4412. 8-bitters lost all support from Commodore long before its demise.  I
  4413. certainly don't blame them; 8-bit computers are a thing of the past and there
  4414. wasn't a big enough market to support a company the size of Commodore.
  4415.  
  4416. > Do you see anything in the future that signals anything that will extend the
  4417.   useful lifetime of the Commodore 8-bits?
  4418.  
  4419. IMHO, there are only two things that 8-bit computers need to survive in the
  4420. hands of hobbiests indefinitely: serious system software and modern hardware
  4421. peripherals.  Some serious system software has begun to surface recently :-),
  4422. and Creative Micro Designs has been providing modern peripherals for us to
  4423. use.  New application programs are needed too, but I'm assuming that
  4424. hobbiests + serious_system_software --> serious_new_application_programs.
  4425. (Perhaps this is a bit self-serving).
  4426.  
  4427. Eight-bit computers have two big advantages over bigger PCs: a much lower
  4428. price and a much higher understandability quotient.  Both of these are very
  4429. important to hobbiests.
  4430.  
  4431. > Do you feel that with the addition of newer periphials that are gradually
  4432.   superceeding the CPU's job (REU, RamLink, SwiftLink etc...) that the
  4433.   Commodore 8-bit standard machine is no longer standard??
  4434.  
  4435. Indeed, there are lots of options.  But I think that this is a good thing.
  4436. The original Commodores are quite limited, and this modern hardware is needed
  4437. to allow the Commodores to remain useful in the networked world.  An
  4438. important feature of all of these new products is that you can flip a switch
  4439. or pull out a cartidge and you're back to your little old standard Commodore.
  4440. Of course, who really wants to do this.
  4441.  
  4442. The reason that I have stayed with my little Commodore for all of these years
  4443. is that I believe that it still has quite enough power (using modern
  4444. peripherals and expanded memory) to do what I require of it.  For example,
  4445. it's quite possible to have a nice little 17K text editor that can edit huge
  4446. files and be very useful.  You don't need a multi-megabyte program with all
  4447. kinds of snazzy features that requires a monsterous machine to run on to do
  4448. this.  These multi-megabyte programs are simply bloated and poorly designed.
  4449.  
  4450. > Will there ever be an update to Zed? (a question asked on a lot of the
  4451.   commericial providers)
  4452.  
  4453. Yes.  I've been promising this for a long time, but the right time to do this
  4454. is finally near.
  4455.  
  4456. > What is the process that you use for writing your programs?
  4457.  
  4458. I'll start this answer with a Unix-fortune quotation:
  4459.  
  4460. "Real programmers don't draw flowcharts.  Flowcharts are, after all, the
  4461.  illiterate's form of documentation.  Cavemen drew flowcharts; look how
  4462.  much good it did them."
  4463.  
  4464. For complicated algorithms, I'll sit down write some pseudo-code, and I
  4465. always plan and write out complicated data structures.  But other than this,
  4466. I usually just sit down and write code, after kicking ideas around in my head
  4467. long enough for me to know what I have to do.
  4468.  
  4469. > It's been noticed that you have a "fanatacism" about speed in your programs.
  4470.   Can you elaborate on this?
  4471.  
  4472. Guilty as charged.  As I said above, I despise bloated software that needs a
  4473. mega-machine to run on fast enough.  I like software that is sleek and mean,
  4474. and I have an axe to grind that little 8-bit Commodore computers offer quite
  4475. enough computing power for most applications that most people would use them
  4476. for.  The exceptions are number-crunching, huge-data processing, and heavy
  4477. computation.  However, for most interactive programs, an 8-bit processor is
  4478. quite enough.  So, I grind my axe by producing fast programs.  Arguably, that
  4479. effort is sometimes misspent (like in the printing to the screen in ACE -- I
  4480. still have a few more tricks up my sleeve though...), but I like to go a
  4481. little too far sometimes to make people go, "Wow! I didn't know this little
  4482. machine could do that so fast!!"  I like to upset the notion that you need a
  4483. huge machine to get adequate performance.  (In fact, sometimes the opposite
  4484. is true, since programmers assume that they can be extra sloppy when
  4485. programming for huge machines).
  4486.  
  4487. As a user, I like crisp responsiveness.  This is a feature of personal
  4488. computers that can sometimes be absent on big multi-user virtual-memory
  4489. machines.
  4490.  
  4491. I also have a big thing against backwards compatibility ("hysterical
  4492. raisins"). This is a significant cause of software bloatedness.  This is one
  4493. reason that ACE, for example, was designed from scratch rather then with the
  4494. pre-set limitation that all BASIC-compatible programs should run with it (a
  4495. la CS-DOS).
  4496.  
  4497. > Is there anything that you find particularly useful / handy about the
  4498.   Commodore's architecture?
  4499.  
  4500. Yeah, it's simple.
  4501.  
  4502. > And the corallary: Is there anything particularly annoying?
  4503.  
  4504. Yeah, it's limited.
  4505.  
  4506. > What is currently in the works / planned??
  4507.  
  4508. My Commodore job queue looks like the following:
  4509.  
  4510. 1. Update my Unix VBM file filter.  Make it produce a new format of VBM files
  4511.    with run-length encoding compression.  Investigate LZW(?) compression.
  4512.  
  4513. 2. Work on ACE release #13: Internal cleanup.  Reorganize the internal memory
  4514.    usage, add features to the command shell, clean up memory and device
  4515.    management inside the kernel, update the VBM program, add a SwiftLink
  4516.    device driver, make a simple glass-tty terminal program.
  4517.  
  4518. 3. Develop a new portable archiver format and write a C program for Unix,
  4519.    ".car" format.
  4520.  
  4521. 4. Write my next article for C= Hacking, which will be about the detailed
  4522.    design of a distributed multitasking microkernel operating system for
  4523.    the C128.  This article will also include a minimal multitasking
  4524.    implementation.
  4525.  
  4526. 5. Work on ACE release #14: Port Zed to ACE.  Get the basic editing features
  4527.    going.
  4528.  
  4529. 6. Work on ACE release #15: Finish the ACE assembler.  Add the file-inclusion,
  4530.    conditional and macro assembly features.  Make it accept more dyadic
  4531.    operators in expressions, fix the label typing, make it generate
  4532.    relocatable executable code modules, and make it handle modular compilation
  4533.    (".o" files).
  4534.  
  4535. 7. Work on ACE release #16: Archiving.  Update the "bcode" and "unbcode"
  4536.    programs to support uucode, nucode and hexcode formats.  Toss the old
  4537.    "uuencode" and "uudecode" programs.  Implement "car" and "uncar" programs.
  4538.    Look into "zip" format.
  4539.  
  4540. 8. Start on BOS, the distributed multitasking microkernel operating system
  4541.    for the 128.
  4542.  
  4543. (Actually, some of these things will be done by the time that C= Hacking
  4544.  comes out).
  4545.  
  4546. Keep on Hackin'!
  4547.  
  4548. ===========================================================================
  4549. Aligning 1541 Drives
  4550. by Ward Shrake (taken from comp.sys.cbm)
  4551.  
  4552. A discussion regarding Commodore 1541 disk drive alignment procedures, with
  4553. suggestions.
  4554.  
  4555. Background information.
  4556.  
  4557. The best way I've ever seen to consistently and reliably get a 1541 disk
  4558. drive aligned perfectly, was caused by copy protection. It is sort of appropo
  4559. that copy protection, which usually causes the "head knock" problem that puts
  4560. drives out of alignment in the first place, should also be able to solve the
  4561. problem it created.
  4562.  
  4563. An older version of a disk utility program, ("Disector" v3.0, as I remember
  4564. it), had copy protection that would not let you load the disk up unless your
  4565. disk alignment was perfect. While initially loading itself, it would search
  4566. and search, never quitting, until it found what it was looking for, exactly
  4567. where it was looking for it. It would stay in an endless loop, searching
  4568. forever, never making it to so far as the first screen. This essentially
  4569. "locked up" the computer, if the program thought the disk it was on was an
  4570. illegal copy.
  4571.  
  4572. This quickly became the most hassle-free, no-worry alignment program I've
  4573. ever seen. I have seen and used most of the others; this method beat them
  4574. all, no contest, in my opinion.
  4575.  
  4576. The other programs, the ones made for aligning your drive,  never
  4577. consistently worked acceptably well, in my experience. Other technical users
  4578. apparently feel the same way about them, as the "General FAQ, v2.1" on
  4579. Commodores points out. They would work OK part of the time, or on part of the
  4580. drives you tried, but not all, I found. Or they would say you now had a
  4581. perfectly-aligned drive, but some difficult copy protection schemes would
  4582. still not load and run on the newly tuned-up drive friend. A friend of mine,
  4583. now deceased, once had a drive no alignment program could fix. We tried
  4584. everything we could find. After aligning it with a given method or program,
  4585. some programs would load that would not load before, but others would now no
  4586. longer work, that used to work before. All in all, it was very frustrating,
  4587. and the general feeling was that there has to be a better, easier, more
  4588. reliable way to do this.
  4589.  
  4590. All an alignment program has to do, is to make sure that when the disk drive
  4591. says it is precisely at a given track's physical location, that it is really
  4592. there, centered on that track.
  4593.  
  4594. There are other Commodore adjustments, but alignment seems to be, by far, the
  4595. most common problem. Disk drive rotational speed can be adjusted, but it
  4596. usually is not the problem. In fact, I've seen more than one drive, that when
  4597. adjusted to read a program-reported "perfect" 300 rpm rotation speed, they
  4598. quit reading disks; requiring speed to be set at a reported 310 rpm, to work
  4599. again. The end stop gap can also be adjusted, but I've never seen it be the
  4600. real culprit with a non-working disk drive. Your experience may vary, of
  4601. course, but I've always found that it is best to concentrate on alignment
  4602. first, then fool around with the other adjustments ONLY after alignment is
  4603. truly corrected, and only if it still refuses to work properly.
  4604.  
  4605. Once alignment is corrected, there are methods available to insure that it
  4606. stays that way. For instance, you can have the stepper motor's pulley
  4607. mechanically pinned to its shaft, instead of merely relying on the factory's
  4608. interference fit to hold it. Commodore 1541 drives were made to be self-
  4609. aligning, apparently, which would be fine if "head knocking" protection
  4610. schemes were not around. Since they are, the pulley should, ideally, not be
  4611. allowed to turn on its shaft, which is what causes misalignment problems.
  4612.  
  4613. How I used to align 1541 disk drives....
  4614.  
  4615. To precisely align a given 1541 disk drive, I used the old, unbroken copy I
  4616. had of Disector (v3.0, I think), and followed these steps.  With power to the
  4617. drive off an disconnected,  you first took off the upper and lower halves of
  4618. the outer plastic casing of the drive. This exposed the electronics inside.
  4619. You then found and loosened (but not removed!) the two stepper motor mounting
  4620. screws, which are on the underside of the disk drive's internal mechanisms.
  4621. After that, you hooked the power cable back up, and hooked the drive to the
  4622. computer like it normally is.
  4623.  
  4624. Once you've done this, you set the drive up on one side, so that you can
  4625. (carefully!) reach into the mechanism, to physically rotate the stepper
  4626. motor, which would normally be on the bottom of the drive. You type in the
  4627. program's loading instructions on the computer, and you then wait until the
  4628. screen went black (copy protection searching for certain info on the
  4629. diskette). This is where  the program  "locks up," with the unaligned drive.
  4630.  
  4631. Once the program is loading, but stuck and unable to find what it wants, you
  4632. reach into the mechanism, very slowly and carefully, turning the stepper
  4633. motor a slight bit in either direction, and stopping. Tiny adjustments are a
  4634. lot; don't overdo it. Be patient; don't go too fast, or move it too much! You
  4635. watch the screen carefully, and listen to the drive's sounds.
  4636.  
  4637. When you have rotated the stepper motor to the proper place, the sounds and
  4638. the screen will act a little different, perhaps only slightly so. Wait a
  4639. second, not moving the stepper motor at all. When you are right on,
  4640. alignment-wise, the program will find what it is looking for, and the
  4641. program's main menu will appear.
  4642.  
  4643. Once the main menu has come onto the screen, you have a perfectly aligned
  4644. drive. Then you have to retighten the stepper mounting screws, being very
  4645. careful not to accidentally move the motor in the process. Hold the motor
  4646. firmly while retightening both screws in small steps, alternating back and
  4647. forth between them until they are both tight. The rotational force of the
  4648. screws turning, forces the motor to move some, so watch for it.
  4649.  
  4650. With this method, using a specially-prepared disk, I always got perfect
  4651. results; everything would load, every time, from then on. (Assuming that the
  4652. disk was formatted with a good drive to begin with; any disks you made
  4653. recently, on your badly-aligned drive, may not load after the alignment
  4654. procedure.  Transfer the info on these disks, to a second, known-good drive,
  4655. before you do this procedure. This is normal, however, no matter what method
  4656. you use to align a bad drive.)
  4657.  
  4658. Here's the problem with this method...
  4659.  
  4660. This procedure only works with a special disk, one that is no longer
  4661. available. With the special disk, alignment is quick, hassle-free, and it
  4662. always gave excellent, reliable results the first time around. Without the
  4663. "perfect" disk, this procedure is worthless. This is obviously a problem,
  4664. since the method relies on a disk that is no longer available to the public.
  4665. You can't make your own, because you don't know if the disk drives you are
  4666. using, are truly perfect to start with! Disks made by users, on Commodore
  4667. equipment, never worked; they just matched your drive's alignment to that of
  4668. someone else's equipment, which may be borderline bad to start with.
  4669.  
  4670. Here's what I suggest to solve this...
  4671.  
  4672. Your mission, should some hot programmer out there choose to accept it, is to
  4673. create a program that will create a "special" disk, and a
  4674. Commodore-compatible program to try to read that special disk.
  4675.  
  4676. Ideally, the Commodore-compatible reading program would be short and simple
  4677. enough to fit inside 8k of memory, so it could fit on a cartridge. This would
  4678. allow it to work, even if a user's disk drive would not load programs
  4679. anymore. It could still be stored on a diskette, too, with a little planning.
  4680.  
  4681. Theoretically, once you had the specially-formatted diskette, and the program
  4682. on cartridge, you would only need a screwdriver to take the drive apart, and
  4683. a Commodore microcomputer to run the program on. No other special tools would
  4684. be needed, and very little technical knowledge would be required; just some
  4685. general safety tips, because you are working around sensitive electronic
  4686. parts, with wall current coming into the drive itself, at least on older
  4687. 1541's.
  4688.  
  4689. Why should a programmer go to all the trouble?
  4690.  
  4691. I'm sure there are a lot of people out there who could use this, if some hot
  4692. programmer should decide to write it, and make it available to the rest of
  4693. us. There are always programmers out there, somewhere, eager to show off
  4694. their computer skills, and their creativity. It is one of the things that
  4695. makes the computer community so great in the first place. (If people out
  4696. there can write IBM-to-Commodore disk file readers, this should be a breeze!)
  4697.  
  4698. Techies should appreciate it as a great, reliable and cheap way to align
  4699. troublesome disk drives, and those people with a C64 in a closet would sure
  4700. appreciate their technical buddies getting their dead systems going again!
  4701.  
  4702. Description of what I have in mind, as to how it should work.
  4703.  
  4704. You need a Commodore computer (the 64 is most popular), one 1541 disk drive
  4705. that needs alignment (or that you want to check), a screwdriver to open the
  4706. drive up, a specially-prepared disk used only for alignment purposes, and a
  4707. computer program that would run on the Commodore that would look at and
  4708. analyze the information that is on the specially-prepared diskette, as the
  4709. computer program tries to read it.
  4710.  
  4711. OK. Here's where it gets cute.
  4712.  
  4713. The problem with most disk alignment methods, as I see it, is that it relies
  4714. totally on technology that the Commodore has available; trying to create a
  4715. special disk on a 1541, I just don't see as being realistic, or the best way
  4716. to do it. The 1541 has many limitations, compared to some other disk drives
  4717. which operate on other computer platforms. Don't get me wrong; I love
  4718. Commodore computers, and have for years. But, realistically, the 5.25 inch
  4719. drives found in say an IBM machine, are just plain better in many ways than
  4720. the 1541. They are made to hold much more information, and to do that, they
  4721. have to be much more precise in doing so than the 1541 was ever designed to
  4722. be.
  4723.  
  4724. If a person were to do this, I would suggest that they write an IBM program
  4725. that would use a high density, 1.2 megabyte capacity, 5.25-inch type of disk
  4726. drive to create the special diskettes, which the 1541 would later read.
  4727.  
  4728. Doing this would allow the creation of very thin tracks on the diskette's
  4729. surface, spaced closely together. This would, within the limitations of the
  4730. 1541's read head, allow the Commodore to "see" precisely where it currently
  4731. was, to one side or the other of some "centered" position. The advantage of
  4732. thin tracks, widthwise, is that the read head won't see them at all,
  4733. reliably, unless you are exactly, perfectly right on top of them. Another
  4734. advantage to this, again within the limitations of the 1541's read head
  4735. (whatever that may be), is that left or right of center, the head would
  4736. likely pick up the next track over, letting you know you were off by a
  4737. certain amount automatically.
  4738.  
  4739. I hope I'm making myself clear, in my explanation of this. If I am not, Email
  4740. me with your questions, and I'll try to answer them better, and/or update
  4741. this file, to entice someone else to work on this. I really would like to see
  4742. it done. (Current Email address, as of Sep 94: wardshrake@aol.com on the
  4743. Internet, or just WardShrake on AOL. Will soon have a Compuserve Email
  4744. address, too: I'll be user 75207,1005 there, or 75207.1005@compuserve.com on
  4745. the Internet.)
  4746.  
  4747. Anyway, let's continue. With the IBM creating a specially-made disk just for
  4748. this one purpose, you would not even have to worry about following any
  4749. standard formatting procedures. No user-stored data would ever be written to
  4750. the diskette, so standard sectoring could be safely ignored. You could create
  4751. any signal or sectoring scheme you like, as long as the IBM could create it,
  4752. and the Commodore could read it; and you'd be writing both programs, anyway,
  4753. making this easier to insure, right?
  4754.  
  4755. I can hear some die-hard Commodore users saying, "I hate IBM's" or "I don't
  4756. even have an IBM" or some such. Fine. Not a problem. If all the
  4757. IBM-compatible program did was to create a special floppy disk, once, then
  4758. quit, you would not even need to OWN an IBM, you'd just need to be able to
  4759. USE one for a few minutes.
  4760.  
  4761. Even if you don't have access to one at work, and don't know of anyone who
  4762. has one to lend you, I will stick with this suggestion, because I know that
  4763. some businesses that make photocopies often also rent IBM's and Mac's on an
  4764. hourly basis, for very little money. My local Kinko's copy center rents them
  4765. both at $10.00 an hour. You would only need it for a few minutes or so.
  4766.  
  4767. The diskette-creation program would only need a few minutes to run, to make
  4768. up a special disk, so you'd only be paying for a good quality, blank high
  4769. density floppy, and ten or fifteen minutes of rental time, tops. The copy
  4770. center person may even be able to start up the floppy-based IBM program for
  4771. you, if you don't know how to do it yourself. That should come to $5.00 or
  4772. less, even if you don't own or normally have access to an IBM compatible
  4773. computer! You can't beat that, for a utility to align equipment!
  4774.  
  4775. OK. In overview, you'd need to use an IBM-compatible computer, just long
  4776. enough to load an IBM-compatible program which would create one special,
  4777. 5.25" diskette, perhaps on a high density floppy. You would then open up your
  4778. Commodore drive's case, and start up a special program on your Commodore 64,
  4779. to read the created diskette. (Again, an 8k Commodore program would fit very
  4780. easily on a cartridge, for easiest loading and running.)
  4781.  
  4782. While the computer and drive were running, you would (very carefully, and
  4783. observing safety precautions) loosen the stepper motor's screws, and slowly
  4784. turn the motor clockwise and counter-clockwise, until the Commodore program's
  4785. screen info told you that you were exactly where you should be, right over
  4786. the proper track. Not to the left or right of it, but in perfect alignment.
  4787.  
  4788. Because the Commodore disk-reading program would be "on" constantly, and
  4789. reporting any small changes to you via information on your screen, you would
  4790. only have to take a few minutes of fiddling, doing a simple, non-technical
  4791. turning of the stepper motor, to get the drive aligned. The two computer
  4792. programs that would make up this package would be doing most of the work.
  4793.  
  4794. I imagine a drive could be perfectly aligned, and back in running order, in
  4795. fifteen minutes or less. Five, if you paid attention to the process, and had
  4796. some practice before. Remember, this is based on an alignment procedure I
  4797. really used to do, using a heavily-protected diskette, so I am extrapolating
  4798. from my personal experiences, even though I'm talking about a theory here.
  4799.  
  4800. I don't see where there would be any easier, simpler method of doing a disk
  4801. alignment. The user wouldn't even have to know a thing about tracks and
  4802. sectors; they would just loosen two screws, following some instructions, and
  4803. turn the motor. What could be any easier?
  4804.  
  4805. The program could, if it was really creative and well-done, tell them to
  4806. rotate the motor clockwise or counter-clockwise (as they face it), to dial
  4807. the motor precisely in. Tracks to either side of an arbitrary (track 18?)
  4808. center position would say to go one way, tracks on the other would say the
  4809. reverse. When you turn it too far one way, it would reverse its instructions
  4810. to you; you would know you were very close then. When you were "right on,"
  4811. the program would tell you so. You'd lock the screws down, carefully, and as
  4812. long as you hadn't jiggled the motor when you tightened it back down, you
  4813. would be all done!
  4814.  
  4815. How much easier could it be, right? (On the final user, that is!)
  4816.  
  4817. If anyone is interested in doing this, or goes out and does it, please let me
  4818. know via Email. I'd like to hear about it. Again, it would be something
  4819. possible, useful, and a really neat trick. I know there are people out there
  4820. that program on both the IBM and the Commodore; the various cross-reading
  4821. programs attest to that, well enough!
  4822.  
  4823. Ward Shrake
  4824. Covina, California
  4825.  
  4826. ==================================================================---END---===
  4827.  
  4828.