* * This is the filled polygon routine for the * 3D graphics library. It is based on the polygonamy * routine, improved in some places and modified in others * to save memory, but it ought to be WELL within a factor * of two speed-wise. * * To use: * - Set up a list of points blah blah * - yak yak yak * Points may lie in range yada yada yada * * Written over the 4th of July weekend. * * (Plus a few evenings :) * * SLJ 7/97 * * v2 -- New variables, later will add multicolor mode * DY > 255 now allowed * Routines to plot points and lines * SLJ 3/99 * REL DSK '@0:polyfill' MULTLO1 = $B1 ;Pointers to multiplication MULTLO2 = $B3 ;tables MULTHI1 = $B5 MULTHI2 = $B7 BITMAP = $B9 ;Pointer to base of bitmap (hi) FILLPAT = $BB ;Pointer to fill pattern PLISTXLO = $BD ;POINTER to list of x coords (lo) PLISTXHI = $BF PLISTYLO = $C1 ;Pointer to list of y coords PLISTYHI = $C3 TEMP1 = $55 ;Temporary var TEMP2 = $56 LBITS = $57 ;Fill pattern NUMPTS = $58 REMPTS = $59 ;Remaining number of points LINDEX = $5A ;Left point index RINDEX = $5B ;Right point index * LDY and RDY aren't used anywhere * LDY = $5C ;Left dy * RDY = $5D ;Right dy YLEFT = $5C ;Remaining points left YRIGHT = $5E ;remaining points right LDXINT = $60 ;Left dx, integer part LDXREM = $61 ;remainder RDXINT = $62 RDXREM = $63 LEFTXLO = $64 ;Left x coordinate LEFTXHI = $65 LEFTREM = $66 ;remainder RIGHTXLO = $67 RIGHTXHI = $68 RIGHTREM = $69 YCOUNT = $6A ;Counter = 0..7 YROW = $6B ;Current row LCOL = $6C ;Column, left coordinate BPOINT = $6D ;Pointer to bitmap ROWHIGH = $6F ;Actual high byte of bitmap pointer DIVXLO = $70 ;Division: DIVX/DIVY DIVXHI = $71 DIVY = $72 DIVTEMP = MULTLO1 ;High byte of DY LOG = $CC00 ;Logarithm table EXP = $CD00 ;Exponential table NEGEXP = $CE00 ;e^-x PQ = $0200 ;Point index queue * * Short test routine * DO 0 INIT STY NUMPTS LDY #$C0 STY MULTLO2+1 INY STY MULTLO1+1 LDY #$C3 STY MULTHI2+1 INY STY MULTHI1+1 LDA #TESTPAT STA FILLPAT+1 LDA BITMAP STA BPOINT+1 LDA #00 STA BPOINT LDX #32 LDY #00 TYA :LOOP STA (BPOINT),Y INY BNE :LOOP INC BPOINT+1 DEX BNE :LOOP LDX NUMPTS JMP POLYFILL ;Y=# of points TESTPAT HEX FFFFFFFFFFFFFFFF FIN * * Some tables * XCOLUMN ;xcolumn(x)=x/8 ]BLAH = 0 LUP 32 DFB ]BLAH,]BLAH,]BLAH,]BLAH DFB ]BLAH,]BLAH,]BLAH,]BLAH ]BLAH = ]BLAH+1 --^ * Below are EOR #$FF for merging into the bitmap, instead * of just ORAing into the bitmap. LBITP ;Left bit patterns LUP 32 * DFB $FF,$7F,$3F,$1F,$0F,$07,$03,$01 DFB 00,$80,$C0,$E0,$F0,$F8,$FC,$FE --^ RBITP ;right bit patterns LUP 32 * DFB $80,$C0,$E0,$F0,$F8,$FC,$FE,$FF DFB $7F,$3F,$1F,$0F,$07,$03,$01,$00 --^ * * The fill routine. It just blasts into the bitmap, * with self-modifying code determining the entry and * exit points. * FILLMAIN ]BLAH = 0 ;This assembles to LUP 32 ;LDY #00 STA (BPOINT),Y LDY #]BLAH ;LDY #08 STA (BPOINT),Y STA (BPOINT),Y ;... ]BLAH = ]BLAH+8 ;LDY #248 STA (BPOINT),Y --^ INC BPOINT+1 ;Advance pointer to column 32 COL32 LDY #00 STA (BPOINT),Y LDY #08 ;33 STA (BPOINT),Y LDY #16 STA (BPOINT),Y LDY #24 STA (BPOINT),Y LDY #32 STA (BPOINT),Y LDY #40 ;37 STA (BPOINT),Y LDY #48 STA (BPOINT),Y LDY #56 ;Column 39 STA (BPOINT),Y FILLEND RTS ;64+256=320 FILL JMP FILLMAIN ;166 bytes * * Tables of high and low bitmap row offsets * LOBROW DFB 00,64,128,192,00,64,128,192 DFB 00,64,128,192,00,64,128,192 DFB 00,64,128,192,00,64,128,192 DFB 00 HIBROW DFB 00,01,02,03,05,06,07,08 DFB 10,11,12,13,15,16,17,18 DFB 20,21,22,23,25,26,27,28 DFB 30 COLTAB ;coltab(x)=x*8 DFB 0,8,16,24,32,40,48,56,64,72,80 DFB 88,96,104,112,120,128,136,144 DFB 152,160,168,176,184,192,200 DFB 208,216,224,232,240,248 DFB 0,8,16,24,32,40,48,56 * Now on a page boundary! * * The jump table for the 3d library routines * * We should be at $8A00 * CALCMAT EXT LOCROT EXT GLOBROT EXT ACCROTX EXT ACCROTY EXT ACCROTZ EXT JMP CALCMAT JMP ACCROTX JMP ACCROTY JMP ACCROTZ JMP GLOBROT JMP LOCROT JMP POLYFILL JMP PLOT JMP DRAWLINE VERSION LDA #2 RTS * * Table of entry point offsets into fill routine. * The idea is to enter on an LDY * FILLENT DFB 0,4,8,12,16,20,24,28,32,36,40 ;0-10 DFB 44,48,52,56,60,64,68,72,76,80 ;11-20 DFB 84,88,92,96,100,104,108,112 ;21-28 DFB 116,120,124,128 ;29-32 DFB 134 ;Skip over INC BPOINT+1 DFB 138,142,146,150,154,158 ;34-39 DFB 162 ;Remember that we use FILLENT+1 * * Table of RTS points in fill routine. * The idea is to rts after the NEXT LDY #xx so as to * get the correct pointer to the rightmost column. * * Thus, these entries are just the above +2 * FILLRTS DFB 2,6,10,14,18,22,26,30,34,38,42 ;0-10 DFB 46,50,54,58,62,66,70,74,78,82 ;11-20 DFB 86,90,94,98,102,106,110,114,118,122,126 DFB 132 ;Skip over INC DFB 136,140,144,148,152,156,160 ;33-39 TXT 'Are you the king of the jews?' * * There are two types of lines: ones that move right and * ones that move left. They may have either positive * or negative slope, for a total of four routines. * * Each line requires two parts: the initial computation * of dx/dy, and the actual updating of the line. When * dy=0 the next set of points must be moved to. The * initial step is always dx/2, to make nice looking lines, * but the initial column/bit pattern must be handled * carefully, depending on the slope. * * The complementary routine jump address must be passed * in, for negative changes in slope. * * * Part 1: Compute dy * * Since the very last point must be plotted in a special * way (else not be plotted at all), ]1=address of routine * to handle last point. * DYLINEL MAC ;Line with left points BEGIN LDX LINDEX L1 DEC REMPTS ;Remaining lines to plot BPL L2 ;Zero is still plotted INC YLEFT LDA REMPTS CMP #$FF ;Last point BCS ]1 EXIT RTS * JMP ALLDONE ;If we hit zero L2 JSR CALCDYL BMI EXIT ;(sometimes points get screwed up) ORA YLEFT BEQ L1 ;If DY=0 then skip to next point STX LINDEX <<< DYLINER MAC LDX RINDEX L1 DEC REMPTS BPL L2 LDA REMPTS ;Might have to handle endpoint CMP #$FE BCS ]1 RRTS RTS ;We really should never get here L3 LDX #00 ;Wrap around L2 CPX NUMPTS BCS L3 LDY PQ,X STY TEMP1 LDA (PLISTYHI),Y PHA LDA (PLISTYLO),Y ;Start point INX SEC LDY PQ,X STY TEMP2 SBC (PLISTYLO),Y ;Next point STA YRIGHT STA DIVY PLA SBC (PLISTYHI),Y STA YRIGHT+1 STA DIVTEMP BMI RRTS ;(sometimes points get screwed up) ORA DIVY BEQ L1 ;Advance if dy=0 STX RINDEX <<< * * Part 2: Compute dx. If dx has negative the expected * sign then jump to the complementary routine. * * dx>0 means forwards point is to the right of the * current point, and vice-versa. * LINELM MAC ;Left line, dx<0 LDY TEMP1 LDA (PLISTXHI),Y STA LEFTXHI LDA (PLISTXLO),Y ;Current point STA LEFTXLO LDY TEMP2 SEC ;Carry can be clear if jumped to SBC (PLISTXLO),Y ;Next point STA DIVXLO LDA LEFTXHI SBC (PLISTXHI),Y BPL CONT1 ;If dx>0 then jump out JMP ]1 ;Entry address CONT1 STA DIVXHI JSR LINELM2 DONE <<< ;Now .X=low byte, .A=high byte ;(of advanced point) ;and carry=clear LINELP MAC ;Left line, dx>0 LDY TEMP2 LDA (PLISTXHI),Y TAX LDA (PLISTXLO),Y ;Next point LDY TEMP1 SEC ;Carry can be clear if jumped to SBC (PLISTXLO),Y ;Current point STA DIVXLO TXA SBC (PLISTXHI),Y BPL CONT1 ;If dx<0 then jump out JMP ]1 ;Entry address CONT1 STA DIVXHI LDA (PLISTXLO),Y ;Current point STA LEFTXLO LDA (PLISTXHI),Y STA LEFTXHI JSR LINELP2 DONE2 <<< ;Now .X=low byte, .A=high byte ;of current point * * Now do the same for the right lines * LINERP MAC ;Right line, dx>0 LDY TEMP2 LDA (PLISTXHI),Y TAX LDA (PLISTXLO),Y ;Next point LDY TEMP1 SEC SBC (PLISTXLO),Y ;Current point STA DIVXLO TXA SBC (PLISTXHI),Y BPL CONT1 ;If dx<0 then jump out JMP ]1 ;Entry address CONT1 STA DIVXHI LDA (PLISTXLO),Y ;Current point (DEY above) STA RIGHTXLO LDA (PLISTXHI),Y STA RIGHTXHI JSR LINERP2 DONE <<< ;Now .X=low byte, .A=high byte ;carry=clear LINERM MAC ;Right line, dx<0 LDY TEMP1 LDA (PLISTXHI),Y STA RIGHTXHI LDA (PLISTXLO),Y ;Current point STA RIGHTXLO LDY TEMP2 SEC SBC (PLISTXLO),Y ;Next point STA DIVXLO LDA RIGHTXHI SBC (PLISTXHI),Y BPL CONT1 ;If dx<0 then jump out JMP ]1 ;Entry address CONT1 STA DIVXHI JSR LINERM2 DONE <<< ;Now .X=low byte, .A=high byte * * Next, the parts which update the X coordinates * for positive and negative dx (in real space, of * course -- the stored value of dx is always positive) * * Parameters passed in are: * ]1 = lo byte x coord * ]2 = high byte x coord * ]3 = remainder * ]4 = dy (unused!) * ]5 = dx/dy, integer * ]6 = dx/dy, remainder * PUPDATE MAC ;dx>0 LDA ]3 CLC ADC ]6 STA ]3 LDA ]1 ;x=x+dx/dy ADC ]5 TAX STA ]1 BCC CONT INC ]2 ;High byte, x CLC CONT LDA ]2 <<< ;Carry is CLEAR on exit ;.X = lo byte xcoord ;.A = hi byte MUPDATE MAC ;dx<0 LDA ]3 ;remainder SEC SBC ]6 STA ]3 LDA ]1 ;x=x-dx/dy SBC ]5 STA ]1 TAX BCS CONT DEC ]2 ;high byte CONT LDA ]2 CLC <<< ;carry is clear ;.X=x-coord low byte ;.A=high byte * * Compute the columns and plot the endpoints * * .X contains the low byte of the x-coord * .A was JUST loaded with the high byte * * Carry is assumed to be CLEAR * LCOLUMN MAC * LDA LEFTXHI BEQ CONT CMP #2 BCC CONT1 ASL BCS NEG POS LDA #$FF ;Column flag STA LCOL BNE DONE NEG LDA #00 ;If negative, column=0 STA LCOL STA LBITS ;(will be EOR #$FF'ed) LDA #4 ;Start filling at column 1 STA FILL+1 BNE DONE CONT1 CPX #64 ;Check X<320 BCS POS LDA #32 ;Add 32 columns! INC BPOINT+1 ;and advance pointer CONT ADC XCOLUMN,X STA LCOL TAY LDA LBITP,X STA LBITS ;For later use in RCOLUMN LDA FILLENT+1,Y ;Get fill entry address STA FILL+1 DONE <<< ;By pushing off the plot until ;later, things like shared ;columns won't hose other things ;on the screen. * * Note that RCOLUMN does the actual filling * * On entry, .X = lo byte x-coord, and .A was JUST loaded * with the high byte. * * Carry must be CLEAR. * RCOLUMN MAC * LDA RIGHTXHI BEQ CONT CMP #2 BCC CONT1 ASL BCS JDONE ;Skip plot+fill if x<0 POS LDX LCOL BMI JDONE ;Skip if lcol>40! LDY YCOUNT ;Plot the left edge LDA (FILLPAT),Y STA TEMP1 LDY COLTAB,X ;Get column index EOR (BPOINT),Y ;Merge into the bitmap AND LBITS ;bits EOR #$FF EOR TEMP1 ;voila! STA (BPOINT),Y LDA TEMP1 JSR FILL ;Just fill to last column JDONE JMP DONE UNDER LDY LCOL ;It is possible that, due to BMI DONE ;rounding, etc. the left column LDX #00 ;got ahead of the right column ;x=0 will force load of $FF SAME LDA RBITP,X ;If zero, they share column EOR LBITS STA LBITS LDY YCOUNT LDA (FILLPAT),Y STA TEMP1 LDX LCOL LDY COLTAB,X EOR (BPOINT),Y ;Merge AND LBITS EOR TEMP1 STA (BPOINT),Y ;and plot JMP DONE CONT1 CPX #64 ;Check for X>319 BCS POS LDA #32 ;Add 32 columns! CONT ADC XCOLUMN,X CMP LCOL ;Make sure we want to fill BCC UNDER BEQ SAME LDY RBITP,X STY TEMP1 LDX LCOL STA LCOL ;Right column LDY YCOUNT ;Plot the left edge LDA (FILLPAT),Y STA TEMP2 LDY COLTAB,X ;Get column index EOR (BPOINT),Y ;Merge into bitmap AND LBITS EOR TEMP2 STA (BPOINT),Y LDY LCOL ;right column LDX FILLRTS,Y ;fill terminator LDA #$60 ;RTS STA FILLMAIN,X LDA TEMP2 ;Fill pattern JSR FILL EOR (BPOINT),Y AND TEMP1 ;Right bits EOR TEMP2 ;Merge STA (BPOINT),Y LDA #$91 ;STA (),Y STA FILLMAIN,X ;Fill leaves .X unchanged ;And leaves .Y with correct offset DONE <<< * * Finally, we need to decrease the Y coordinate and * update the pointer if necessary. * * Also, since BPOINT may have been altered, we need * to restore the high byte. * * ]1 = loop address * UPYRS MAC LDA ROWHIGH STA BPOINT+1 DEC BPOINT DEC YCOUNT BMI FIXIT JMP ]1 FIXIT LDA #7 STA YCOUNT LDY YROW BEQ EXIT ;If y<0 then exit DEY STY YROW ORA LOBROW,Y STA BPOINT LDA HIBROW,Y CLC ADC BITMAP STA BPOINT+1 STA ROWHIGH JMP ]1 EXIT RTS <<< * * Like the above, but for the y>=200 routine * BIGFIX MAC * LDA ROWHIGH * STA BPOINT+1 * DEC BPOINT DEC YCOUNT BMI FIXIT JMP ]1 FIXIT LDA #7 STA YCOUNT DEC YROW LDY YROW ORA LOBROW,Y STA BPOINT LDA HIBROW,Y CLC ADC BITMAP STA BPOINT+1 STA ROWHIGH CPY #24 BEQ EXIT ;If y<0 then exit JMP ]1 EXIT <<< ;Don't leave this hanging :) * * Yay, time to code! * * Load X with the number of points in the point list * POLYFILL STX NUMPTS STX REMPTS LDA #00 ;First find the largest Y STA TEMP1 STA TEMP2 STA LINDEX :LOOP LDY PQ,X LDA (PLISTYLO),Y CMP TEMP1 LDA (PLISTYHI),Y BMI :SKIP SBC TEMP2 BCC :SKIP STX LINDEX LDA (PLISTYLO),Y STA TEMP1 LDA (PLISTYHI),Y STA TEMP2 :SKIP DEX BNE :LOOP LDX LINDEX BNE GOGOGO ;Possible that all Y<0 RTSMP RTS GOGOGO STX RINDEX LDY PQ,X LDA (PLISTXLO),Y STA LEFTXLO STA RIGHTXLO LDA (PLISTXHI),Y STA LEFTXHI STA RIGHTXHI LDA TEMP1 LSR TEMP2 ;Compute initial row ROR LSR TEMP2 ROR LSR TEMP2 ROR STA YROW TAX LDA TEMP1 ;Initial bit pattern AND #$07 STA YCOUNT ORA LOBROW,X ;Initial bitmap address STA BPOINT LDA HIBROW,X CLC ADC BITMAP STA BPOINT+1 STA ROWHIGH * * Hidden face check. Since point order is invariant * under rotations but reversed by reflections, all that * is required is to make sure the points are in order, * i.e. check the line slopes. * >>> DYLINEL,RTSMP CHECKMP >>> LINELM,CHECKPP JSR CHKLCOL ;To save some memory >>> LINERP,CHECKMM STA TEMP2 ;Possible to fail if dy=0 LDA LEFTXLO SEC SBC RIGHTXLO STA DIVXLO ;temp LDA LEFTXHI SBC RIGHTXHI STA DIVXHI LDA DIVXLO SEC SBC LDXINT BCS :C1 DEC DIVXHI SEC :C1 SBC RDXINT STA DIVXLO LDA DIVXHI SBC #00 BMI :OK ;Skip unless leftx <= rightx ORA DIVXLO BEQ :OK :RTS1 RTS :OK LDY YROW CPY #25 BCS :OOPS LDA TEMP2 ;Restore A=high byte x JMP RCOLMP ;Jump into right column update :OOPS TAY ;Set flags CLC JMP BCMP ;Run calculation until Y<200 TXT 'Crucify him!' * * Sigh... need to save some memory, so this is now here. * CHKLCOL >>> LCOLUMN ;Update column info >>> DYLINER,CHEXIT RTS CHEXIT PLA ;REALLY exit. PLA RTS CHECKPP >>> LINELP,CHECKMP JSR CHKLCOL >>> LINERP,CHECKPM STA TEMP2 LDA LEFTXLO SEC SBC RIGHTXLO STA DIVXLO ;temp LDA LEFTXHI SBC RIGHTXHI STA DIVXHI LDA DIVXLO CLC ADC LDXINT BCC :C1 INC DIVXHI :C1 SEC SBC RDXINT STA DIVXLO LDA DIVXHI SBC #00 BMI :OK ;If >= then punt ORA DIVXLO BNE :RTS LDA LDXREM ;If 0, then compare slopes SEC SBC RDXREM LDA LDXINT SBC RDXINT BCC :OK :RTS RTS :OK LDY YROW CPY #25 BCS :OOPS LDA TEMP2 ;Restore A=high byte x JMP RCOLPP ;Jump into right column update :OOPS LDA TEMP2 ;Set flags CLC JMP BCPP ;Run calculation until Y<200 CHECKMM >>> LINERM,CHECKMP STA TEMP2 LDA LEFTXLO SEC SBC RIGHTXLO STA DIVXLO ;temp LDA LEFTXHI SBC RIGHTXHI STA DIVXHI LDA DIVXLO SEC SBC LDXINT BCS :C1 DEC DIVXHI :C1 CLC ADC RDXINT STA DIVXLO LDA DIVXHI ADC #00 BMI :OK ;If >= then punt ORA DIVXLO BNE :TOAST LDA RDXREM SEC SBC LDXREM LDA RDXINT SBC LDXINT BCC :OK :TOAST RTS :OK LDY YROW CPY #25 BCS :OOPS LDA TEMP2 ;Restore A=high byte x JMP RCOLMM ;Jump into right column update :OOPS LDA TEMP2 ;Set flags CLC JMP BCMM ;Run calculation until Y<200 CHECKPM >>> LINERM,CHECKPM ;It's possible, if dy=0 STA TEMP2 ;Remember that we've advanced LDA LEFTXLO SEC SBC RIGHTXLO STA DIVXLO ;temp LDA LEFTXHI SBC RIGHTXHI STA DIVXHI LDA DIVXLO CLC ADC LDXINT BCC :C1 INC DIVXHI CLC :C1 ADC RDXINT LDA DIVXHI ADC #00 BMI :OK ;If >= then punt RTS :OK LDY YROW CPY #25 BCS :OOPS LDA TEMP2 ;Restore A=high byte x JMP RCOLPM ;Jump into right column update :OOPS LDA TEMP2 ;Set flags CLC JMP BCPM ;Run calculation until Y<200 * * And finally, the main routine! (Yay :) * * Left lines minus, right lines positive DYL1 DEC YLEFT+1 BPL UL1 >>> DYLINEL,ENDMP LEFTMP >>> LINELM,LEFTPP JMP LCOLMP ENDMP RTS ;Actually, we don't want to get here! LOOP1 DEC YLEFT BEQ DYL1 UL1 >>> MUPDATE,LEFTXLO;LEFTXHI;LEFTREM;TEMP1;LDXINT;LDXREM LCOLMP >>> LCOLUMN DEC YRIGHT BNE UR1 DEC YRIGHT+1 BPL UR1 >>> DYLINER,ENDMP RIGHTMP >>> LINERP,RIGHTMM JMP RCOLMP UR1 >>> PUPDATE,RIGHTXLO;RIGHTXHI;RIGHTREM;TEMP1;RDXINT;RDXREM RCOLMP >>> RCOLUMN >>> UPYRS,LOOP1 * Left positive, right positive * * Endpoint: left advances, right=current point DYL2 DEC YLEFT+1 BPL UL2 >>> DYLINEL,UL2 LEFTPP >>> LINELP,LEFTMP JMP LCOLPP LOOP2 DEC YLEFT BEQ DYL2 UL2 >>> PUPDATE,LEFTXLO;LEFTXHI;LEFTREM;TEMP1;LDXINT;LDXREM LCOLPP >>> LCOLUMN DEC YRIGHT BNE UR2 DEC YRIGHT+1 BPL UR2 >>> DYLINER,ENDPP RIGHTPP >>> LINERP,RIGHTPM JMP RCOLPP ENDPP LDY PQ,X LDA (PLISTXLO),Y ;Last point TAX LDA (PLISTXHI),Y CLC JMP RCOLPP UR2 >>> PUPDATE,RIGHTXLO;RIGHTXHI;RIGHTREM;TEMP1;RDXINT;RDXREM RCOLPP >>> RCOLUMN >>> UPYRS,LOOP2 * Left positive, right negative * * End: left and right advance normally DYL3 DEC YLEFT+1 BPL UL3 >>> DYLINEL,UL3 LEFTPM >>> LINELP,LEFTMM JMP LCOLPM LOOP3 DEC YLEFT BEQ DYL3 UL3 >>> PUPDATE,LEFTXLO;LEFTXHI;LEFTREM;TEMP1;LDXINT;LDXREM LCOLPM >>> LCOLUMN DEC YRIGHT BNE UR3 DEC YRIGHT+1 BPL UR3 >>> DYLINER,UR3 RIGHTPM >>> LINERM,RIGHTPP JMP RCOLPM UR3 >>> MUPDATE,RIGHTXLO;RIGHTXHI;RIGHTREM;TEMP1;RDXINT;RDXREM RCOLPM >>> RCOLUMN >>> UPYRS,LOOP3 * Left negative, right negative * * End: left=current point, right advances EXITMM ;X points to the last point INC YRIGHT ;Sneaky! LDY PQ,X LDA (PLISTXLO),Y TAX LDA (PLISTXHI),Y CLC JMP LCOLMM DYL4 DEC YLEFT+1 BPL UL4 >>> DYLINEL,EXITMM LEFTMM >>> LINELM,LEFTPM JMP LCOLMM LOOP4 DEC YLEFT BEQ DYL4 UL4 >>> MUPDATE,LEFTXLO;LEFTXHI;LEFTREM;TEMP1;LDXINT;LDXREM LCOLMM >>> LCOLUMN DEC YRIGHT BNE UR4 DEC YRIGHT+1 BPL UR4 >>> DYLINER,UR4 RIGHTMM >>> LINERM,RIGHTMP JMP RCOLMM UR4 >>> MUPDATE,RIGHTXLO;RIGHTXHI;RIGHTREM;TEMP1;RDXINT;RDXREM RCOLMM >>> RCOLUMN >>> UPYRS,LOOP4 TXT 'He saved others; let him save himself.' * * Routines to advance but not plot * BIGLOOP1 DEC YLEFT BNE BL1 DEC YLEFT+1 BPL BL1 >>> DYLINEL,BENDMP BIGLMP >>> LINELM,BIGLPP JMP BC1 BENDMP RTS ;Actually, we don't want to get here! BL1 >>> MUPDATE,LEFTXLO;LEFTXHI;LEFTREM;TEMP1;LDXINT;LDXREM BC1 DEC YRIGHT BNE BR1 DEC YRIGHT+1 BPL BR1 >>> DYLINER,BENDMP BIGRMP >>> LINERP,BIGRMM JMP BC2 BR1 >>> PUPDATE,RIGHTXLO;RIGHTXHI;RIGHTREM;TEMP1;RDXINT;RDXREM BCMP ;Entry point from hidden check BC2 >>> BIGFIX,BIGLOOP1 JMP LOOP1 BIGLOOP2 DEC YLEFT BNE BL2 DEC YLEFT+1 BPL BL2 >>> DYLINEL,BL2 BIGLPP >>> LINELP,BIGLMP JMP BC3 BL2 >>> PUPDATE,LEFTXLO;LEFTXHI;LEFTREM;TEMP1;LDXINT;LDXREM BC3 DEC YRIGHT BNE BR2 DEC YRIGHT+1 BPL BR2 >>> DYLINER,BENDPP BIGRPP >>> LINERP,BIGRPM JMP BC4 BENDPP RTS BR2 >>> PUPDATE,RIGHTXLO;RIGHTXHI;RIGHTREM;TEMP1;RDXINT;RDXREM BCPP BC4 >>> BIGFIX,BIGLOOP2 JMP LOOP2 BIGLOOP3 DEC YLEFT BNE BL3 DEC YLEFT+1 BPL BL3 >>> DYLINEL,BENDPP BIGLPM >>> LINELP,BIGLMM JMP BC5 BL3 >>> PUPDATE,LEFTXLO;LEFTXHI;LEFTREM;TEMP1;LDXINT;LDXREM BC5 DEC YRIGHT BNE BR3 DEC YRIGHT+1 BPL BR3 >>> DYLINER,BR3 BIGRPM >>> LINERM,BIGRPP JMP BC6 BR3 >>> MUPDATE,RIGHTXLO;RIGHTXHI;RIGHTREM;TEMP1;RDXINT;RDXREM BCPM BC6 >>> BIGFIX,BIGLOOP3 JMP LOOP3 BIGRTS RTS BIGLOOP4 DEC YLEFT BNE BL4 DEC YLEFT+1 BPL BL4 >>> DYLINEL,BIGRTS BIGLMM >>> LINELM,BIGLPM JMP BC7 BL4 >>> MUPDATE,LEFTXLO;LEFTXHI;LEFTREM;TEMP1;LDXINT;LDXREM BC7 DEC YRIGHT BNE BR4 DEC YRIGHT+1 BPL BR4 >>> DYLINER,BR4 BIGRMM >>> LINERM,BIGRMP JMP BC8 BR4 >>> MUPDATE,RIGHTXLO;RIGHTXHI;RIGHTREM;TEMP1;RDXINT;RDXREM BCMM BC8 >>> BIGFIX,BIGLOOP4 JMP LOOP4 TXT 'Hail, king of the jews.' * * Called by DYLINEx macros. It checks for negative dy. * Yep, it's here to save on memory. * * v2 -- handled automatically now that dy>255 is allowed DO 0 FLOWCHK LDY TEMP1 LDA (PLISTYHI),Y LDY TEMP2 SBC (PLISTYHI),Y RTS FIN * * Called by DYLINEx macros -- computes left DY etc. * * Right line will follow, if more mem is needed. * CDYL2 PLA LDX NUMPTS CALCDYL LDY PQ,X STY TEMP1 LDA (PLISTYHI),Y PHA LDA (PLISTYLO),Y ;Remember, y -decreases- DEX BMI CDYL2 ;Loop around if needed LDY PQ,X STY TEMP2 SEC SBC (PLISTYLO),Y STA YLEFT STA DIVY PLA SBC (PLISTYHI),Y STA YLEFT+1 STA DIVTEMP RTS * * Called by LINELM macro * LINELM2 JSR DIVXY ;Returns int,rem = .X,.A STX LDXINT CMP #$FF ;if dy=1 BNE :NOT1 ;then X=dx/2 STX TEMP2 ;just two steps of dx/2 LDA #00 ROR ;Get carry bit from dx/2 STA LDXREM BCC :CONT2 :NOT1 STA LDXREM TXA ;x=x-dxdy/2 LSR STA TEMP2 :CONT2 LDA #$80 STA LEFTREM ;rem = 1/2 LDA LEFTXLO SEC SBC TEMP2 STA LEFTXLO TAX ;X=advanced point LDA LEFTXHI SBC #00 STA LEFTXHI CLC RTS * * Called by LINELP macro * LINELP2 JSR DIVXY ;Returns int,rem = .X,.A STX LDXINT CMP #$FF ;if dy=1 BNE :NOT1 ;then A=dx/2 LDA #00 ROR ;Get carry bit from dx/2 STA LDXREM LDA #$80 STA LEFTREM LDX LEFTXLO LDA LEFTXHI BCC :RTS ;And start from current point :NOT1 STA LDXREM LDA #$80 STA LEFTREM ;Initialize remainder to 1/2 TXA ;x=x-dxdy/2 LSR STA TEMP2 LDA LEFTXLO TAX ;.X = current point SEC SBC TEMP2 STA LEFTXLO LDA LEFTXHI BCS :DONE DEC LEFTXHI TAY ;Set/clear Z flag :DONE CLC :RTS RTS * * Called by LINERP macro * LINERP2 JSR DIVXY ;Returns int,rem = .X,.A STX RDXINT CMP #$FF BNE :NOT1 LDA #00 ROR STA RDXREM LDA #$80 STA RIGHTREM TXA BCC :CONT2 ;Advance by dxdy/2 :NOT1 STA RDXREM LDA #$80 ;-1/2 STA RIGHTREM TXA ;x=x+dxdy/2 LSR CLC :CONT2 ADC RIGHTXLO STA RIGHTXLO TAX ;Move right and use new point LDA RIGHTXHI ADC #00 STA RIGHTXHI CLC ;What if rightx equaled -1? RTS * * Called by LINERM * LINERM2 JSR DIVXY ;Returns int,rem = .X,.A STX RDXINT CMP #$FF BNE :NOT1 LDA #00 ROR STA RDXREM LDA #$80 STA RIGHTREM LDX RIGHTXLO ;Advance from current point LDA RIGHTXHI BCC :DONE :NOT1 STA RDXREM LDA #$80 STA RIGHTREM ;1/2 TXA ;x=x+dxdy/2 LDX RIGHTXLO ;.X = current point LSR CLC ADC RIGHTXLO STA RIGHTXLO LDA RIGHTXHI BCC :DONE INC RIGHTXHI TAY ;Reset Z CLC :DONE RTS * * DIVXY * * This guy is the old predictor-corrector method, * modified slightly to be more general. * * It computes 2X/2Y as the predictor, then corrects * in both directions. Both X and Y must be positive. * X is assumed to be 9-bits and Y is 8-bits. * * Inputs: .X=dx/2 .A=dy/2, dx and dy are in xdivlo etc. * * Result is returned in X=integer part, A=remainder * * Remainder is now a fraction of 256. * * DX and DY can now be huge -- they are simply shifted * right until DX < 512 and DY < 256. * DIVSHIFT LSR DIVTEMP ROR DIVY LSR DIVXHI ROR DIVXLO DIVXY LDA DIVTEMP ;Div by 2 if dy>255 BNE DIVSHIFT LDA DIVXHI CMP #2 BCS DIVSHIFT ;Or if dx>511 LSR ;Compute dx/2 LDA DIVXLO ROR TAX LDA DIVY LSR ;dy/2 BEQ :TWOSTEP ;If Y=1 then handle special TAY LDA LOG,X ;This is the division part SEC SBC LOG,Y BCC :NEG TAX LDA EXP,X TAX ;Now we have int estimate STA MULTLO1 STA MULTHI1 EOR #$FF ADC #00 ;Carry is guaranteed set STA MULTLO2 STA MULTHI2 LDY DIVY LDA (MULTLO1),Y SEC SBC (MULTLO2),Y ;a=N*dy STA TEMP1 LDA (MULTHI1),Y SBC (MULTHI2),Y STA TEMP2 LDA DIVXLO ;R=dx-a SBC TEMP1 ;C set STA TEMP1 LDA DIVXHI SBC TEMP2 LDA TEMP1 ;A=remainder BCC :RNEG ;If R>0 then assume R<255 ;(true unless dx>500 or so) :RPOS CMP DIVY ;If R>=dy then BCC :DONE :L1 INX ;a=a+1 SBC DIVY ;R=R-dy CMP DIVY BCS :L1 :DONE ;Now X contains integer, A rem ;y=dy * * Compute remainder as a fraction of 256, i.e. * 256*r/dy * * Currently, a small error may occur for large r * (cumulative error of 1-2 pixels, up to 4 in rare cases) * :FRACREM STX TEMP1 TAX BEQ :ZERO LDA LOG,X SEC SBC LOG,Y TAX LDA NEGEXP,X :ZERO LDX TEMP1 RTS ;And, if R<0 then assume ;R>-255 :RNEG DEX ADC DIVY BCC :RNEG JMP :FRACREM :NEG LDX #00 ;Since log is monotonic, and LDA DIVXLO ;we /2, there is no chance LDY DIVY JMP :FRACREM ;of undershooting. :TWOSTEP LDA DIVXHI ;If Y=1 LSR LDA DIVXLO ;then just two steps of size ROR ;dx/2 TAX LDA #255 RTS TXT 'Jesus, remember me when you come ' TXT 'into your kingdom.' *------------------------------- * * Plot and line commands * X1 = $60 Y1 = $62 X2 = $64 Y2 = $66 DX = $68 DY = $6A NPOINTS = $6C POINT = $6E XC = $70 YC = $71 BITP = $72 TEMP = $5F BITS DFB $80,$40,$20,$10,$08,$04,$02,$01 * * PLOT -- plot a point! * * On entry: point in (x1,y1), bitmap in BITMAP * * On exit: plotted point! * PLOT LDA X1+1 BMI :EXIT LDX X1 ;Check range CPX #64 SBC #01 BCS :EXIT LDY Y1+1 BNE :EXIT LDA Y1 CMP #200 BCS :EXIT LSR LSR LSR TAY JSR SETPOINT ;Compute address LDA X1 AND #$07 TAX LDA BITS,X ;Change in lib3d ORA (POINT),Y STA (POINT),Y :EXIT RTS * * Drawin' a line. A fahn lahn. * * The same routines are used for on-screen and off-screen * coordinates, but when off-screen, STA (BITMAP),Y is * changed to BIT xx. Slower, but much more compact. * LINESWAP LDX #3 :L1 LDA X1,X ;If not, swap P1 and P2 LDY X2,X STA X2,X TYA STA X1,X DEX BPL :L1 DRAWLINE LDA X2 ;Make sure x1=y1? LDA Y1 ;Otherwise dy=y1-y2 SEC SBC Y2 STA DY LDA Y1+1 SBC Y2+1 LDX #$88 ;DEY :DYPOS STA DY+1 STX YINCDEC STX XINCDEC LDA X1 STA XC ;Next compute column AND #$07 ;Bit pattern TAX LDA BITS,X STA BITP LDA X1+1 LSR ROR XC LSR ROR XC LSR ROR XC ;X column :CONT1 LDA Y1 ;Now do the same for Y STA YC LDA Y1+1 LSR ROR YC LSR ROR YC LSR ROR YC LDX DY CPX DX ;Who's bigger: dy or dx? LDA DY+1 SBC DX+1 BCC STEPINX ;If dx, then... * * Y-direction stepping: * y=y+1 * a=a-dx * if a<0 then a=a+dy:x=x+1 * STEPINY * LDX DY STX NPOINTS LDA DY+1 JSR LINSETUP LDA DY ;Init counter to dy/2 LSR * * Main loop * YLOOP STA TEMP LDA (POINT),Y ;Otherwise plot ORA BITP YSTA STA (POINT),Y YINCDEC INY ;Advance Y coordinate CPY #8 BCC :CONT ;No prob if Y=0..7 JSR FIXY :CONT LDA TEMP ;Restore A SEC SBC DX BCS YCONT ADC DY LSR BITP BCC YCONT JSR XCPLUS1 YCONT DEX ;X is counter BNE YLOOP DEC NPOINTS+1 BEQ YLOOP RTS * * Big steps in X direction * STEPINX LDX DX LDA DX+1 JSR LINSETUP LDA DX ;Init counter to dx/2 LSR XLOOP STA TEMP LDA (POINT),Y ;Otherwise plot ORA BITP XSTA STA (POINT),Y LDA TEMP SEC SBC DY BCS XLSR ADC DX XINCDEC INY CPY #8 BCC XLSR STA TEMP JSR FIXY LDA TEMP XLSR LSR BITP BCC :C1 JSR XCPLUS1 :C1 DEX ;counter BNE XLOOP DEC NPOINTS+1 BEQ XLOOP RTS * * Set up lines for drawing * LINSETUP STX NPOINTS STA NPOINTS+1 ; JSR FIXDXDY ;If DX or DY > 256 then /2 ;If DX or DY > 256 then /2 :SHIFT LDA DY+1 ORA DX+1 BEQ :C1 LSR DY+1 ROR DY LSR DX+1 ROR DX JMP :SHIFT :C1 JSR SETSTA LDX NPOINTS ;Number of points INX ;+1 for endpoint LDY YC ; JMP SETPOINT * * SETPOINT -- Compute bitmap address * * On entry: x-cooord in X1 * y-COLUMN in .Y * * On exit: .Y -> Y1 AND #$07 (ready for plotting) * * Both x and y are assumed to be in range! * SETPOINT ; LDY YCOL ;Compute column LDA X1 AND #$F8 CLC ADC LOBROW,Y ;Base row STA POINT LDA X1+1 ADC HIBROW,Y ADC BITMAP STA POINT+1 LDA Y1 AND #$07 TAY RTS * * Update columns * XCPLUS1 ;Increase x-column ROR BITP STA TEMP LDA POINT ADC #8 STA POINT BCC :C1 INC POINT+1 CLC :C1 LDA X1 ;X1 needed to compute ADC #8 ;bitmap address STA X1 BCC :C2 INC X1+1 :C2 INC XC BMI :LDA BNE :C3 ;Entered left side of screen, STY Y1 LDY YC JSR SETSTA ;so calculate pointers JSR SETPOINT :C3 LDA XC CMP #40 BCS PLAEXIT :LDA LDA TEMP RTS * * Subroutine to fix up pointer when Y decreases through * zero or increases through 7. * FIXY INY ;Y=255 or Y=8 BEQ :DECPTR :INCPTR INC YC BMI :LDY0 BNE :C1 JSR SETSTA ;Just entered screen :C1 LDY YC CPY #25 BCS PLAEXIT ;See-ya! JSR SETPOINT :LDY0 LDY #00 RTS :DECPTR DEC YC BMI PLAEXIT LDY YC CPY #24 ;just entered screen BNE :BCS JSR SETSTA CLC :BCS BCS :LDY JSR SETPOINT :LDY LDY #7 RTS PLAEXIT PLA ;Remove old return address PLA RTS * * If point is on-screen, then STA to bitmap. * Otherwise, BIT * SETSTA LDA XC CMP #40 ;pos and neg BCS :BIT LDA YC CMP #25 BCS :BIT LDA #$91 ;STA (),Y DFB $2C :BIT LDA #$24 ;BIT zp STA YSTA STA XSTA RTS TXT 'Father, into thy hands I commit my spirit' |n @à†¬„Ìøÿ¿)×@X£