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 temp1 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 adc #12 ;tHE GOAL IS TO CENTER THE GRAPHICS sta temp1 ;cOLUMN 12 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 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 X1<X2 lda x2 sbc x1 bcs :cont lda y2 ;iF NOT, SWAP p1 AND p2 ldy y1 sta y1 sty y2 lda x1 ldy x2 sty x1 sta x2 sec sbc x1 ;nOW a=DX:cont sta dx ldx x1 ;pUT X1 INTO x, NOW WE CAN TRASH x1column lda x1 ;fIND THE FIRST COLUMN FOR x lsr  ;(tHIS CAN BE MADE MUCH FASTER!) lsr  ;tHERE ARE X1/8 128 BYTE BLOCKS lsr  ;wHICH MEANS X1/16 256 BYTE BLOCKS lsr bcc :even ;wITH A POSSIBLE EXTRA 128 BYTE BLOCK ldy #$80 ;IF SO, SET THE HIGH BIT sty buffer clc:even adc buffer+1 ;aDD IN THE NUMBER OF 256 BYTE BLOCKS sta buffer+1 ;aND STORE IT! sec lda y2 ;cALCULATE DY sbc y1 bcs :cont2 ;iS Y2>Y1? 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