p******************************** *                              * * sTEPHEN jUDD                 * * gEORGE tAYLOR                * * sTARTED: 7/11/94             * * fINISHED: 7/19/94            * * V2.0 cOMPLETED: 12/17/94     * *                              * * wELL, IF ALL GOES WELL THIS  * * PROGRAM WILL ROTATE A CUBE.  * *                              * * V2.0 + nEW AND iMPROVED!     * * nOW WITH FASTER ROUTINES,    * * HIDDEN SURFACES, FILLED      * * FACES, AND EXTRA TOP SECRET  * * TEXT MESSAGES!               * *                              * * tHIS PROGRAM IS INTENDED TO  * * ACCOMPANY THE ARTICLE IN     * * c=hACKING, jAN. 95 ISSUE.    * * fOR DETAILS ON THIS PROGRAM, * * READ THE ARTICLE!            * *                              * * wRITE TO US!                 * *                              * * mYSELF WHEN YOUNG DID        * * EAGERLY FREQUENT             * * dOCTOR AND sAINT, AND HEARD  * * GREAT aRGUMENT               * *  aBOUT IT AND ABOUT: BUT     * *  EVERMORE                    * * cAME OUT BY THE SAME dOOR    * * AS IN i WENT.                * *    - rUBAIYAT                * *                              * * tHOUGH i SPEAK WITH THE      * * TONGUES OF MEN AND OF ANGLES * * AND HAVE NOT LOVE, i AM      * * BECOME AS SOUNDING BRASS, OR * * A TINKLING CYMBAL.           * *    - 1 cORINTHIANS 13        * *                              * * p.s. tHIS WAS WRITTEN USING  * *      mERLIN 128.             * ******************************** org $8000 * cONSTANTS buff1 equ $3000 ;fIRST CHARACTER SET buff2 equ $3800 ;sECOND CHARACTER SET buffer equ $a3 ;pRESUMABLY THE TAPE WON'T BE RUNNING x1 equ $fb ;pOINTS FOR DRAWING A LINE y1 equ $fc ;tHESE ZERO PAGE ADDRESSES x2 equ $fd ;DON'T CONFLICT WITH basic y2 equ $fe dx equ $f9 dy equ $fa temp1 equ $fb ;oF COURSE, COULD CONFLICT WITH X1 temp2 equ $fc ;tEMPORARY VARIABLES ztemp equ $02 ;uSED FOR BUFFER SWAP.  dON'T TOUCH. z1 equ $22 ;uSED BY MATH ROUTINE z2 equ $24 ;dON'T TOUCH THESE EITHER! k equ $b6 ;cONSTANT USED FOR HIDDEN ;SURFACE DETECTION - DON'T TOUCH faces equ $b5 ;uSED IN HIDDEN SURFACES. ymin equ $f7 ;uSED IN FILLED FACES -- AS ymax equ $f8 ;USUAL, DON'T TOUCH angmax equ 120 ;tHERE ARE 2*PI/ANGMAX ANGLES * vic vmcsb equ $d018 bkgnd equ $d020 border equ $d021 sstart equ 1344 ;ROW 9 IN SCREEN MEMORY AT 1024 * kERNAL chrout equ $ffd2 getin equ $ffe4 * sOME VARIABLES tx1 = $3f ty1 = $40 tx2 = $41 ty2 = $42 p1x = $92 ;tHESE ARE TEMPORARY STORAGE p1y = $93 ;uSED IN PLOTTING THE PROJECTION p2x = $94 p2y = $95 ;tHEY ARE HERE SO THAT WE p3x = $96 ;DON'T HAVE TO RECALCULATE THEM. p3y = $ae p4x = $af ;tHEY MAKE LIFE EASY. p4y = $b0 p5x = $b1 ;wHY ARE YOU LOOKING AT ME LIKE THAT? p5y = $b2 ;dON'T YOU TRUST ME? p6x = $b3 p6y = $b4 ;hAVING ANOTHER CHILD WASN'T MY IDEA. p7x = $71 p7y = $50 p8x = $51 p8y = $52 p1z = $57 ;tHESE ARE Z-COORDINATES p2z = $58 ;wE ONLY NEED THESE FOUR TO CHECK p4z = $59 ;FOR HIDDEN FACES p5z = $60 dsx = $61 ;dsx IS THE INCREMENT FOR ;ROTATING AROUND X dsy = $62 ;sIMILAR FOR dsy, dsz dsz = $63 sx = $64 ;tHESE ARE THE ACTUAL ANGLES IN X Y AND Z sy = $65 sz = $66 t1 = $67 ;tHESE ARE USED IN THE ROTATION t2 = $68 t3 = $69 ;sEE THE ARTICLE FOR MORE DETAILS t4 = $6a t5 = $6b t6 = $6c t7 = $6d t8 = $6e t9 = $6f t10 = $70 a11 = $a5 ;tHESE ARE THE ELEMENTS OF THE ROTATION MATRIX b12 = $a6 ;xyz c13 = $a7 d21 = $a8 ;tHE NUMBER DENOTES (ROW,COLUMN) e22 = $a9 f23 = $aa g31 = $ab h32 = $ac i33 = $ad *** mACROS move mac lda ]1 sta ]2 <<< getkey mac ;wAIT FOR A KEYPRESS wait jsr getin cmp #00 beq wait <<< debug mac ;pRINT A CHARACTER   do 0 ;dON'T ASSEMBLE lda #]1 jsr chrout >>> getkey ;aND WAIT TO CONTINUE cmp #'S' ;mY SECRECT SWITCH KEY bne l1 jsr cleanup jmp done l1 cmp #'X' ;mY SECRET ABORT KEY bne done jmp cleanup fin done <<< debuga mac do 0 lda ]1 sta 1024 fin donea <<< *------------------------------- lda #$00 sta bkgnd sta border lda vmcsb and #%00001111 ;sCREEN MEMORY TO 1024 ora #%00010000 sta vmcsb ldy #00 lda #ttext sta temp2 jmp title ttext hex 9305111111 ;CLEAR SCREEN, WHITE, CRSR DN txt '             CUBE3D V2.0',0D,0D txt '                  BY',0D hex 9f ;CYAN txt '    STEPHEN JUDD' hex 99 txt '    GEORGE TAYLOR',0D,0D hex 9b txt '  CHECK OUT THE JAN. 95 ISSUE OF',0D hex 96 txt '  C=HACKING' hex 9b txt ' FOR MORE DETAILS!',0D hex 0d1d1d9e12 txt 'F1/F2',92 txt ' - INC/DEC X-ROTATION',0D hex 1d1d12 txt 'F3/F4',92 txt ' - INC/DEC Y-ROTATION',0D hex 1d1d12 txt 'F5/F6',92 txt ' - INC/DEC Z-ROTATION',0D hex 1d1d12 txt 'F7',92 txt ' RESETS',0D txt '  PRESS Q TO QUIT',0D hex 0d05 txt '      PRESS ANY KEY TO BEGIN',0D hex 00 title lda (temp1),y beq :cont jsr chrout iny bne title inc temp2 jmp title txt 'tHIS IS A SECRET TEXT MESSAGE!' :cont >>> getkey **** sET UP TABLES(?) * tABLES ARE CURRENTLY SET UP IN basic * AND BY THE ASSEMBLER. tables lda #>tmath sta z1+1 sta z2+1 **** cLEAR SCREEN AND SET UP "BITMAP" setup lda #$01 ;wHITE sta $d021 ;tHIS IS DONE SO THAT OLDER lda #147 ;MACHINES WILL SET UP jsr chrout lda #$00 ;CORRECTLY sta $d021 lda #sstart ;rOW 9 sta temp1+1 ;sstart POINTS TO ROW 9 lda #00 ldy #00 ldx #00 ;X WILL COUNT 16 ROWS FOR US clc :loop sta (temp1),y iny adc #16 bcc :loop clc lda temp1 adc #40 ;nEED TO ADD 40 TO THE BASE POINTER sta temp1 ;tO JUMP TO THE NEXT ROW lda temp1+1 adc #00 ;tAKE CARE OF CARRIES sta temp1+1 ldy #00 inx txa ;x IS ALSO AN INDEX INTO THE CHARACTER NUMBER cpx #16 bne :loop ;nEED TO DO IT 16 TIMES >>> debug,'2' **** sET UP BUFFERS lda #buff1 sta buffer+1 sta ztemp ;ZTEMP WILL MAKE LIFE SIMPLE FOR US lda vmcsb and #%11110001 ;sTART HERE SO THAT SWAP BUFFERS WILL WORK RIGHT ora #%00001110 sta vmcsb **** sET UP INITIAL VALUES init lda #00 sta dsx sta dsy sta dsz sta sx sta sy sta sz >>> debug,'4' *------------------------------- * mAIN LOOP **** gET KEYPRESS main cli kpress jsr getin cmp #133 ;f1? bne :f2 lda dsx cmp #angmax/2 ;nO MORE THAN PI beq :cont inc dsx ;OTHERWISE INCREASE X-ROTATION jmp :cont :f2 cmp #137 ;f2? bne :f3 lda dsx beq :cont dec dsx jmp :cont :f3 cmp #134 bne :f4 lda dsy cmp #angmax/2 beq :cont inc dsy ;iNCREASE Y-ROTATION jmp :cont :f4 cmp #138 bne :f5 lda dsy beq :cont dec dsy jmp :cont :f5 cmp #135 bne :f6 lda dsz cmp #angmax/2 beq :cont inc dsz ;Z-ROTATION jmp :cont :f6 cmp #139 bne :f7 lda dsz beq :cont dec dsz jmp :cont :f7 cmp #136 bne :q jmp init :q cmp #'Q' ;Q QUITS bne :cont jmp cleanup :cont sei ;sPEED THINGS UP A BIT * >>> debug,'5' **** uPDATE ANGLES update clc lda sx adc dsx cmp #angmax ;aRE WE >= MAXIMUM ANGLE? bcc :cont1 sbc #angmax :iF SO, RESET :cont1 sta sx clc lda sy adc dsy cmp #angmax bcc :cont2 sbc #angmax ;sAME DEAL :cont2 sta sy clc lda sz adc dsz cmp #angmax bcc :cont3 sbc #angmax :cont3 sta sz **** rOTATE COORDINATES rotate *** fIRST, CALCULATE T1,T2,...,T10 ** tWO MACROS TO SIMPLIFY OUR LIFE adda mac ;aDD TWO ANGLES TOGETHER clc lda ]1 adc ]2 cmp #angmax ;iS THE SUM > 2*PI? bcc done sbc #angmax ;iF SO, SUBTRACT 2*PI done <<< suba mac ;sUBTRACT TWO ANGLES sec lda ]1 sbc ]2 bcs done adc #angmax ;oOPS, WE NEED TO ADD 2*PI done <<< ** nOW CALCULATE T1,T2,ETC. >>> suba,sy;sz sta t1 ;T1=SY-SZ >>> adda,sy;sz sta t2 ;T2=SY+SZ >>> adda,sx;sz sta t3 ;T3=SX+SZ >>> suba,sx;sz sta t4 ;T4=SX-SZ >>> adda,sx;t2 sta t5 ;T5=SX+T2 >>> suba,sx;t1 sta t6 ;T6=SX-T1 >>> adda,sx;t1 sta t7 ;T7=SX+T1 >>> suba,t2;sx sta t8 ;T8=T2-SX >>> suba,sy;sx sta t9 ;T9=SY-SX >>> adda,sx;sy sta t10 ;T10=SX+SY * eT VOILA! *** nEXT, CALCULATE a,b,c,...,i ** aNOTHER USEFUL LITTLE MACRO div2 mac ;dIVIDE A SIGNED NUMBER BY 2 ;iT IS ASSUMED THAT THE NUMBER bpl pos ;IS IN THE ACCUMULATOR clc eor #$ff ;wE NEED TO UN-NEGATIVE THE NUMBER adc #01 ;BY TAKING IT'S COMPLEMENT lsr ;DIVIDE BY TWO clc eor #$ff adc #01 ;mAKE IT NEGATIVE AGAIN jmp donediv pos lsr ;nUMBER IS POSITIVE donediv <<< mul2 mac ;mULTIPLY A SIGNED NUMBER BY 2 bpl posm clc eor #$ff adc #$01 asl clc eor #$ff adc #$01 jmp donemul posm asl donemul <<< ** nOTE THAT WE ARE CURRENTLY MAKING A MINOR LEAP ** OF FAITH THAT NO OVERFLOWS WILL OCCUR. :calca clc ldx t1 lda cos,x ldx t2 adc cos,x sta a11 ;a=(COS(T1)+COS(T2))/2 :calcb ldx t1 lda sin,x sec ldx t2 sbc sin,x sta b12 ;b=(SIN(T1)-SIN(T2))/2 :calcc ldx sy lda sin,x >>> mul2 sta c13 ;c=SIN(SY) :calcd sec ldx t8 lda cos,x ldx t7 sbc cos,x sec ldx t5 sbc cos,x clc ldx t6 adc cos,x ;dI=(COS(T8)-COS(T7)+COS(T6)-COS(T5))/2 >>> div2 clc ldx t3 adc sin,x sec ldx t4 sbc sin,x sta d21 ;d=(SIN(T3)-SIN(T4)+dI)/2 :calce sec ldx t5 lda sin,x ldx t6 sbc sin,x sec ldx t7 sbc sin,x sec ldx t8 sbc sin,x ;eI=(SIN(T5)-SIN(T6)-SIN(T7)-SIN(T8))/2 >>> div2 clc ldx t3 adc cos,x clc ldx t4 adc cos,x sta e22 ;e=(COS(T3)+COS(T4)+eI)/2 :calcf ldx t9 lda sin,x sec ldx t10 sbc sin,x sta f23 ;f=(SIN(T9)-SIN(T10))/2 :calcg ldx t6 lda sin,x sec ldx t8 sbc sin,x sec ldx t7 sbc sin,x sec ldx t5 sbc sin,x ;gI=(SIN(T6)-SIN(T8)-SIN(T7)-SIN(T5))/2 >>> div2 clc ldx t4 adc cos,x sec ldx t3 sbc cos,x sta g31 ;g=(COS(T4)-COS(T3)+gI)/2 >>> debuga,g31 >>> debug,'G' :calch clc ldx t6 lda cos,x ldx t7 adc cos,x sec ldx t5 sbc cos,x sec ldx t8 sbc cos,x ;hI=(COS(T6)+COS(T7)-COS(T5)-COS(T8))/2 >>> div2 clc ldx t3 adc sin,x clc ldx t4 adc sin,x sta h32 ;h=(SIN(T3)+SIN(T4)+hI)/2 :whew clc ldx t9 lda cos,x ldx t10 adc cos,x sta i33 ;i=(COS(T9)+COS(T10))/2 ** iT'S ALL DOWNHILL FROM HERE. jmp downhill txt 'gEE bRAIN, WHAT DO YOU WANT TO DO ' txt 'TONIGHT?' ** rOTATE, PROJECT, AND STORE THE POINTS downhill * a NEAT MACRO neg mac ;cHANGE THE SIGN OF A TWO'S COMPLEMENT clc lda ]1 ;NUMBER. eor #$ff adc #$01 <<< *------------------------------- * tHESE MACROS REPLACE THE PREVIOUS PROJECTION * SUBROUTINE. smult mac ;mULTIPLY TWO SIGNED 8-BIT ;NUMBERS: a*y/64 -> a sta z1 clc eor #$ff adc #$01 sta z2 lda (z1),y sec sbc (z2),y <<< ;aLL DONE :) addsub mac ;aDD OR SUBTRACT TWO NUMBERS ;DEPENDING ON FIRST INPUT if -=]1 ;iF SUBTRACT sec ;THEN USE THIS CODE sbc ]2 else ;OTHERWISE USE THIS CODE clc adc ]2 fin <<< project mac ;tHE ACTUAL PROJECTION ROUTINE ;TWO INPUTS ARE USED (X,Y) ;CORRESPONDING TO (+/-1,+/-1) ;tHE THIRD INPUT IS USED TO ;DETERMINE IF THE ROTATED ;Z-COORDINATE SHOULD BE ;STORED, AND IF SO WHERE. ;tHE CALLING ROUTINE HANDLES ;CHANGING THE SIGN OF Z. lda i33 ;cALCULATE ROTATED Z: >>> addsub,]1;g31 ;aDD OR SUBTRACT X >>> addsub,]2;h32 ;aDD OR SUBTRACT Y if p,]3 ;dO WE NEED TO STORE THE POINT? sta ]3 ;tHEN DO SO! fin * eor #128 ;wE ARE GOING TO TAKE 128+Z tax ;nOW IT IS READY FOR INDEXING lda zdiv,x ;tABLE OF D/(Z+Z0) tay ;y NOW CONTAINS PROJECTION lda c13 ;nOW CALCULATE ROTATED X >>> addsub,]1;a11 >>> addsub,]2;b12 >>> smult ;sIGNED MULTIPLY a*y/64->a clc adc #64 ;oFFSET THE COORDINATE tax ;nOW x IS ROTATED X! lda f23 ;nOW IT'S Y'S TURN >>> addsub,]1;d21 >>> addsub,]2;e22 >>> smult clc adc #64 ;oFFSET cmp ymin ;fIGURE OUT IF IT IS A bcs notmin ;MIN OR MAX VALUE FOR Y sta ymin bcc notmax ;tHIS IS USED IN CALCULATING notmin cmp ymax ;THE FILLED FACES bcc notmax sta ymax notmax tay ;nOT REALLY NECESSARY <<< ;aLL DONE lda #64 ;rESET yMIN AND yMAX sta ymin sta ymax * p1=[1 1 1] >>> project,1;1;p1z ;rOTATED Z STORED IN p1z stx p1x sty p1y * p2=[1 -1 1] >>> project,1;-1;p2z stx p2x sty p2y * p3=[-1 -1 1] >>> project,-1;-1;nope ;dON'T STORE Z-VALUE stx p3x sty p3y * p4=[-1 1 1] >>> project,-1;1;p4z stx p4x sty p4y * p8=[-1 1 -1] >>> neg,c13 sta c13 >>> neg,f23 sta f23 >>> neg,i33 sta i33 >>> project,-1;1;nope stx p8x sty p8y * p7=[-1 -1 -1] >>> project,-1;-1;nope stx p7x sty p7y * p6=[1 -1 -1] >>> project,1;-1;nope stx p6x sty p6y * p5=[1 1 -1] >>> project,1;1;p5z stx p5x sty p5y * a LITTLE MACRO setbuf mac ;pUT BUFFERS WHERE THEY CAN BE HURT lda #00 sta buffer lda ztemp ;ZTEMP CONTAINS THE HIGH BYTE HERE sta buffer+1 <<< **** cLEAR BUFFER * >>> setbuf *clrbuf lda #$00 ;pRETTY STRAIGHTFORWARD, * ldx #$08 ;i THINK * ldy #$00 *:loop sta (buffer),y * iny * bne :loop * inc buffer+1 * dex * bne :loop * tHIS IS THE NEW AND IMPROVED BUFFER CLEAR * ROUTINE FOR FILLED FACES >>> setbuf sta temp1+1 ;BUFFER2 WILL POINT TO lda #$80 ;BUFFER+128 sta temp1 ;mAKES LIFE FASTER FOR US filclr lda #00 ldx #$08 ;wE'LL DO IT TWO AT A TIME ldy #$00 :loop1 sta (buffer),y sta (temp1),y iny cpy ymin bne :loop1 lda #$ff ;nOW LOAD WITH FILLS :loop2 sta (buffer),y sta (temp1),y iny cpy ymax bcc :loop2 lda #$00 ;bLACK OUT THE REST :loop3 sta (buffer),y sta (temp1),y iny bpl :loop3 ;uNTIL y=128 ldy #00 inc buffer+1 inc temp1+1 dex bne :loop1 ;gO ALL THE WAY AROUND **** nOW DRAW THE LINES. **** bUT FIRST CHECK FOR HIDDEN FACES! **** rEMEMBER: p1=[1 1 1] p2=[1 -1 1] p3=[-1 -1 1] **** p4=[-1 1 1] p5=[1 1 -1] p6=[1 -1 -1] p7=[-1 -1 -1] **** p8=[-1 1 -1] lines lda #00 sta faces ;hIDDEN FACE COUNTER :face1 lda k sec sbc p1z bvs :face6 ;oVERFLOW ALREADY? clc adc p5z ;iS K-V1Z < 0? ;iF NOT, FACE IS INVISIBLE bvc :draw1 ;bUT WE MIGHT HAVE OVERFLOW lda p5z ;wAS OVERFLOW POS OR NEG? :draw1 bpl :face6 ;iF POS THEN K-V1Z > 0 lda #$01 ;oTHERWISE, DRAW THE sta faces ;FACE! lda p1x sta tx1 lda p1y sta ty1 lda p2x sta tx2 lda p2y sta ty2 jsr draw ;p1-p2 lda p3x sta tx1 lda p3y sta ty1 jsr draw ;p2-p3 lda p4x sta tx2 lda p4y sta ty2 jsr draw ;p3-p4 lda p1x sta tx1 lda p1y sta ty1 jsr draw ;p4-p1  fACE 1 DONE. jmp :face2 ;iF ONE IS VISIBLE, THE OTHER ;ISN'T. :face6 lda k sec sbc p5z bvs :face2 clc adc p1z ;nOW CHECK IF k-V6Z < 0 bvc :draw6 ;lOVE THAT OVERFLOW lda p1z :draw6 bpl :face2 ;iF NOT, GO ON lda #$20 sta faces ;oTHERWISE, DRAW IT lda p5x sta tx2 lda p5y sta ty2 lda p6x sta tx1 lda p6y sta ty1 jsr draw ;p5-p6 lda p7x sta tx2 lda p7y sta ty2 jsr draw ;p6-p7 lda p8x sta tx1 lda p8y sta ty1 jsr draw ;p7-p8 lda p5x sta tx2 lda p5y sta ty2 jsr draw ;p8-p5 :face2 lda k sec sbc p1z bvs :face5 clc adc p4z ;k-V2Z < 0? bvc :draw2 lda p4z :draw2 bpl :face5 lda #$02 ;iF SO, DRAW IT! ora faces sta faces ldx p1x ;wE'RE DOING THIS THIS WAY stx tx1 ;TO SAVE A FEW CYCLES ldx p1y stx ty1 and #$01 ;sHARES AN EDGE WITH FACE 1 bne :f2s2 ;sKIP TO NEXT EDGE IF PRESENT lda p2x sta tx2 lda p2y sta ty2 jsr draw ;p1-p2 :f2s2 ldx p5x stx tx2 ldx p5y stx ty2 jsr draw ;p1-p5 ldx p6x stx tx1 ldx p6y stx ty1 lda faces and #$20 ;aLSO SHARES AN EDGE WITH 6 bne :f2s4 jsr draw ;p5-p6 :f2s4 lda p2x sta tx2 lda p2y sta ty2 ;sUCH IS FACE 2 jsr draw ;p6-p2 jmp :face3 ;sKIP 5 :face5 lda k sec sbc p4z bvs :face3 clc adc p1z ;sAME THING AGAIN... bvc :draw5 lda p1z :draw5 bpl :face3 lda #$10 ora faces sta faces ldx p3x stx tx1 ldx p3y stx ty1 and #$01 ;sHARES WITH 1 bne :f5s2 lda p4x sta tx2 lda p4y sta ty2 jsr draw ;p3-p4 :f5s2 lda p7x sta tx2 lda p7y sta ty2 jsr draw ;p3-p7 lda p8x sta tx1 lda p8y sta ty1 lda faces and #$20 ;sHARES WITH 6 bne :f5s4 jsr draw ;p7-p8 :f5s4 lda p4x sta tx2 lda p4y sta ty2 ;p8-p4 jsr draw ;tWO MORE TO GO! :face3 lda k sec sbc p1z bvs :face4 clc adc p2z bvc :draw3 lda p2z :draw3 bpl :face4 ;aH RECKON IT'S A'HIDDEN, YUP lda #$04 ora faces sta faces ldx p1x stx tx1 ldx p1y stx ty1 and #$01 ;sHARES WITH 1 bne :f3s2 lda p4x sta tx2 lda p4y sta ty2 jsr draw ;p1-p4 :f3s2 ldx p5x stx tx2 ldx p5y stx ty2 lda faces and #$02 ;sHARES WITH 2 bne :f3s3 jsr draw ;p1-p5 :f3s3 ldx p8x stx tx1 ldx p8y stx ty1 lda faces and #$20 ;sHARES WITH 6 bne :f3s4 jsr draw ;p5-p8 :f3s4 ldx p4x stx tx2 ldx p4y stx ty2 lda faces and #$10 ;sHARES WITH 5 bne facedone jsr draw ;p8-p4 jmp facedone :face4 lda k sec sbc p2z bvs facedone clc adc p1z bvc :draw4 lda p1z :draw4 bpl facedone lda p2x sta tx1 lda p2y sta ty1 lda faces and #$01 ;sHARES WITH 1 bne :f4s2 lda p3x sta tx2 lda p3y sta ty2 jsr draw ;p2-p3 :f4s2 lda p6x sta tx2 lda p6y sta ty2 lda faces and #$02 ;sHARES WITH 2 bne :f4s3 jsr draw ;p2-p6 :f4s3 lda p7x sta tx1 lda p7y sta ty1 lda faces and #$20 ;sHARES WITH 6 bne :f4s4 jsr draw ;p6-p7 :f4s4 lda p3x sta tx2 lda p3y sta ty2 lda faces and #$10 ;sHARES WITH 5 bne facedone jsr draw ;p7-p3 facedone ;wHEW!  tIME FOR A BEER. **** nOW WE NEED TO UNFILL THE OUTSIDE FROM THE FACES unfill ldy ymin :loop >>> setbuf ldx #08 :l1 lda (buffer),y eor #$ff ;gO TILL WE FIND A PLOTTED bne :gotcha ;POINT (I.E. a <> $ff) * lda #00 ;uNFILLING AS WE GO... sta (buffer),y lda #$80 sta buffer lda (buffer),y eor #$ff bne :gotcha * lda #00 sta (buffer),y sta buffer inc buffer+1 dex ;tHIS IS OUR SAFETY VALVE bne :l1 ;rEALLY SHOULDN'T NEED IT jsr choke jmp swapbuf :gotcha ;a CONTAINS THE eor PLOT VALUE sta temp1 ;nOW FIND THE HIGH BIT lda #00 :l2 sec rol lsr temp1 ;sHOULD REALLY USE A TABLE bne :l2 ;FOR THIS! and (buffer),y sta (buffer),y lda ztemp ;nOW GO TO THE END ;cARRY IS CLEAR ;aCTUALLY WE ADD 7 adc #$06 ;16 COLUMNS OF 128 BYTES sta buffer+1 lda #$80 sta buffer :loop2 lda (buffer),y ;aND WORK BACKWARDS! eor #$ff bne :gotcha2 sta (buffer),y sta buffer ;sTICK A ZERO INTO BUFFER lda (buffer),y eor #$ff bne :gotcha2 sta (buffer),y lda #$80 sta buffer dec buffer+1 bne :loop2 :gotcha2 sta temp1 ;aGAIN FIND THE HIGH BIT lda #00 :l3 sec ror asl temp1 bne :l3 and (buffer),y sta (buffer),y iny ;nOW KEEP GOING cpy ymax bcc :loop ;uNTIL WE HIT YMAX! beq :loop ;wE NEED THE LAST ONE TOO. **** sWAP BUFFERS swapbuf lda vmcsb eor #$02 ;pRETTY TRICKY, EH? sta vmcsb lda #$08 eor ztemp ;ZTEMP=HIGH BYTE JUST FLIPS sta ztemp ;BETWEEN $30 AND $38 jmp main ;aROUND AND AROUND WE GO... txt 'sAME THING WE DO EVERY NIGHT, pINKY: ' txt 'TRY TO TAKE OVER THE WORLD!' *------------------------------- * gENERAL QUESTIONABLE-VALUE ERROR PROCEDURE choke ldx #00 :loop lda :ctext,x beq :done jsr chrout inx jmp :loop :done rts :ctext hex 0d ;cr txt 'SOMETHING CHOKED :(' hex 0d00 txt 'nARF!' *------------------------------- * dRAWIN' A LINE.  a FAHN LAHN. *** sOME USEFUL MACROS plotpx mac ;PLOT A POINT IN X pha ;uSE THIS ONE EVERY TIME lda bitp,x ;x IS INCREASED bmi c1 lda #$80 ;tABLE HAS BEEN REARRANGED eor buffer ;FOR FILLING FACES sta buffer bmi c2 inc buffer+1 c2 lda #%01111111 ;nOTE THAT THIS IS CHANGED c1 and (buffer),y ;FOR PLOTTING FILLED FACES sta (buffer),y pla ;nEED TO SAVE a! <<< plotpy mac ;pLOT A POINT IN Y: SIMPLER AND NECESSARY! pha ;uSE THIS ONE WHEN YOU JUST INCREASE y lda bitp,x ;BUT x DOESN'T CHANGE and (buffer),y sta (buffer),y pla <<< cinit mac ;mACRO TO INITIALIZE THE COUNTER lda ]1 ;DX OR DY lsr eor #$ff ;(nOT REALLY TWO'S COMPLEMENT) adc #$01 ;a = 256-DX/2 OR 256-DY/2 <<< ;tHE DX/2 MAKES A NICER LOOKING LINE xstep mac ;mACRO TO TAKE A STEP IN x xloop inx adc dy bcc l1 * dO WE USE iny OR dey HERE? if i,]1 ;iF THE FIRST CHARACTER IS AN 'i' iny else dey fin sbc dx l1 >>> plotpx ;aLWAYS TAKE A STEP IN x cpx x2 bne xloop <<< ystep mac ;sAME THING, BUT FOR y yloop if i,]1 iny else dey clc ;vERY IMPORTANT! fin adc dx bcc l2 inx ;aLWAYS INCREASE x sbc dy >>> plotpx jmp l3 l2 >>> plotpy ;wE ONLY INCREASED y l3 cpy y2 bne yloop <<< **** iNITIAL LINE SETUP draw >>> move,tx1;x1 ;mOVE STUFF INTO ZERO PAGE >>> move,tx2;x2 ;wHERE IT CAN BE MODIFIED >>> move,ty1;y1 >>> move,ty2;y2 >>> setbuf ;nOW WE CAN CLOBBER THE BUFFER sec ;mAKE SURE X1Y1? eor #$ff ;oTHERWISE DY=Y1-Y2 adc #$01 :cont2 sta dy cmp dx ;wHO'S BIGGER: DY OR DX? bcs stepiny ;iF DY, WE NEED TO TAKE BIG STEPS IN Y stepinx ldy y1 ;x IS ALREADY SET TO X1 lda bitp,x ;pLOT THE FIRST POINT * eor #$ff and (buffer),y sta (buffer),y >>> cinit,dx ;iNITIALIZE THE COUNTER cpy y2 bcs xdecy ;dO WE STEP FORWARDS OR BACKWARDS IN y? xincy >>> xstep,iny rts stepiny ldy y1 ;wELL, A LITTLE REPETITION NEVER HURT ANYONE lda bitp,x * eor #$ff and (buffer),y sta (buffer),y >>> cinit,dy cpy y2 bcs ydecy yincy >>> ystep,iny rts xdecy >>> xstep,dey ;tHIS IS PUT HERE SO THAT rts ;bRANCHES ARE LEGAL ydecy >>> ystep,dey rts *------------------------------- * cLEAN UP cleanup lda vmcsb ;sWITCH CHAR ROM BACK IN and #%11110101 ;DEFAULT sta vmcsb rts ;BYE! txt 'hAPPY hOLIDAYS! ' txt 'SLJ 12/94' *------------------------------- * sET UP BIT TABLE ds ^ ;cLEAR TO END OF PAGE ;sO THAT TABLES START ON A PAGE BOUNDARY bitp lup 16 ;128 eNTRIES FOR x dfb %01111111 dfb %10111111 dfb %11011111 dfb %11101111 dfb %11110111 dfb %11111011 dfb %11111101 dfb %11111110 --^ sin ;tABLE OF SINES, 120 BYTES cos equ sin+128 ;tABLE OF COSINES ;bOTH OF THESE TRIG TABLES ARE ;CURRENTLY SET UP FROM basic zdiv equ cos+128 ;dIVISION TABLE tmath equ zdiv+384 ;mATH TABLE OF F(X)=X*X/256