; ; BOUNCING PIXELS DEMO: Sends 10 pixels off bouncing on the screen. ; Copyright 1999, Joseph Zbiciak ; ; ROM Header and function stubs adapted from SHELL.SRC, by Carl Mueller, Jr. ; org $5000 ROMWIDTH equ 10 ; rom is 10-bits wide ; EXEC-ROM HEADER ROMHDR: DCW lo|MODATA, hi|MODATA ; ^ moving object grafx DCW lo|RTAB, hi|RTAB ; ^ routine tab DCW lo|START, hi|START ; ^ start program address DCW lo|BKGDATA, hi|BKGDATA ; ^ background graphics DCW lo|CARDTAB, hi|CARDTAB ; ^ card tab DCW lo|TITLE, hi|TITLE ; ^ date / title string DCW $9F ; run code after title, clicks on DCW $00 ; -> to STIC $32 DCW $00 ; 0 = color stack, 1 = f/b mode DCW 9, 9, 9, 9 ; color stack elements 1 - 4 DCW $09 ; border color ; Moving Object offsets = last 16 pictures in GRAM ; [What is this for? Do I need it for this program? --JZ] DCW $180, $190, $1A0, $1B0, $1C0, $1D0, $1E0, $1F0 CARDTAB: DCW $1, $0 RTAB: DCW $0, $0 ; TITLE ; ; Copyright date, title, and code to patch title. PROC TITLE DCW 99, 'Bouncing Pixels', $0 ; 1999 ; Code to patch title screen MVO@ R5, R6 ; Cyan screen MVII $09, R0 ; Color 9 is Cyan (pastels.) MVO R0, $28 ; Color stack 0 = Cyan MVO R0, $29 ; Color stack 1 = Cyan MVO R0, $2A ; Color stack 2 = Cyan MVO R0, $2B ; Color stack 3 = Cyan MVO R0, $2C ; Border color = Cyan ; Patch the title string to say '=JRMZ=' instead of Mattel. XORR R3, R3 ; Black MVII $23D, R4 ; First 'Mattel' in top-left JSR R5, $187B ; Write string (ptr in R5) DCW '=JRMZ=', 0 ; Guess who? :-) MOVR R7, R1 SUBI 8, R1 ; Point to '=JRMZ=' above (save 4 words) XORR R3, R3 ; Black MVII $2D5, R4 ; Second 'Mattel' in lower-right JSR R5, $1867 ; Write string (ptr in R1) ; Make all the rest of the text black to match MVII $243, R3 ; Start after first JRMZ MVII 7, R0 ; Mask = 0xFFF8. That's the 1s complement... COMR R0 ; ...of 7. (Saves an SDBD.) MVII 146, R2 ; We only need to touch 146 words. @@titlelp: MVI@ R3, R1 ; Read a word from the display ANDR R0, R1 ; Mask the foreground color MVO@ R1, R3 ; Write the word back INCR R3 ; Point to next word DECR R2 ; Decrement our loop count BNEQ @@titlelp ; Iterate. ; Done. MVI@ R6, R7 ; Return to caller ENDP ; HANDTAB ; Vector table for handling the controllers. HANDTAB: DCW lo|HTDisc, hi|HTDisc ; Disc handler DCW lo|HTKeypad, hi|HTKeypad ; Keypad handler DCW lo|HTActU, hi|HTActU ; Upper action btn DCW lo|HTActR, hi|HTActR ; Lower Right act btn DCW lo|HTActL, hi|HTActL ; Lower Left act btn ; HTDisc ; Handler for disc-press events PROC HTDisc JR R5 ENDP ; HTKeypad ; Handler for Keypad events PROC HTKeypad JR R5 ENDP ; Upper buttons handler PROC HTActU JR R5 ENDP ; Lower Right button handler PROC HTActR JR R5 ENDP ; Lower Left button handler PROC HTActL JR R5 ENDP ; Moving Objects bitmaps MODATA: DCW $0 ; Background Cards bitmaps BKGDATA: DCW $0 ; Colored squares pixel-manipulation routines. ; J. Zbiciak, July 1999 ; PIXCALC -- Pixel Calculation: Convert x,y into addr,mask ; Input: R1 = x, R2 = y, R5 = return address ; Output: R1 = pixel mask, R2 = address in CARDTAB ; Clobbered: R3, R4 PROC PIXCALC SLL R2, 1 ; y' = y << 1 MOVR R2, R4 ; mskidx = y << 1 ANDI 2, R4 ; mskidx = (y << 1) & 2 SUBR R4, R2 ; y' = (y & ~1) << 1 MOVR R2, R3 ; save y' SLL R2, 2 ; y'' = (y & ~1) << 3 ADDR R3, R2 ; y''' = y' + y'' = (y >> 1) * 20 SARC R1, 1 ; c = x & 1; x' = x >> 1 ADCR R4 ; mskidx = ((y << 1) & 2) + (x & 1) ADDR R1, R2 ; ofs = x' + y''' = (x >> 1) + (y >> 1) * 20 ADDI $200, R2 ; ptr = ofs + $200 = &CARDTAB[ofs] ==> R2 ADDR R4, R4 ; mskidx' = mskidx * 2 SDBD ADDI MSKTBL, R4 ; mskptr = MSKTBL + mskidx' = &MSKTBL[mskidx] SDBD MVI@ R4, R1 ; mask = *mskptr ==> R1 MOVR R5, R7 ; return ENDP ; PUTPIXEL -- Put pixel at x, y coordinates with color 'c' (0-7) ; Input: R0 = color (0-7), R1 = x, R2 = y ; Output: R1 = word @R2, R2 = CARDTAB address ; Clobbers: R0, R1, R2, R3, R4, R5 PROC PUTPIXEL MVO@ R5, R6 ; Save return address MOVR R7, R5 ADDI 5, R5 ; Return to actual pixel draw below B PIXCALC ; Convert x,y into mask,addr ; PUTPIXELR -- Put pixel 'raw': accepts address, mask, and color ; (Alternate entry point for putpixel.) ; Input: R0 = color (0-7), R1 = pixmask, R2 = CARDTAB addr, R5 = ret addr ; Output: R1 = word @R2, R2 = CARDTAB address ; Clobbers: R0, R5 PUTPIXELR: MVO@ R5, R6 ; Save return address ADDR R0, R0 ; c' = c * 2 SDBD ADDI CLRTBL, R0 ; clrptr = CLRTBL + c' = &CLRTBL[c] MOVR R0, R5 ; use an incrementing data pointer SDBD MVI@ R5, R0 ; color = CLRTBL[c] ANDR R1, R0 ; color = color & mask (select desired pix) COMR R1 ; invert mask AND@ R2, R1 ; pix = CARDTAB & ~mask (clear pixel) ADDR R0, R1 ; pix' = pix + color (merge pixels) MVO@ R1, R2 ; CARDTAB[ofs] = pix' (write pixels) MVI@ R6, R7 ; return. ENDP ; GETPIXEL -- Get pixel at x, y address ; Input: R1 = x, R2 = y ; Output: R0 = color, R2 = CARDTAB address ; Clobbers: R1, R3, R4, R5 PROC GETPIXEL MVO@ R5, R6 ; Save return address MOVR R7, R5 ADDI 5, R5 ; Return to actual pixel read below B PIXCALC ; Convert x,y into mask,addr ; GETPIXELR -- Get pixel 'raw': accepts address, mask ; (Alternate entry point for getpixel) ; Input: R1 = pixmask, R2 = cardtab address ; Output: R0 = color, R2 = cardtab address ; Clobbers: R1 GETPIXELR: MVO@ R5, R6 ; Save return address MVI@ R2, R0 ; pix = CARDTAB[ofs] ANDR R1, R0 ; pix' = pix & mask MOVR R0, R1 ; SWAP R0, 1 ; ANDI $20, R0 ; ADDR R1, R0 ; merge oddball bit from lower right pixel SLL R1, 2 ; SWAP R1, 1 ; ADDR R1, R0 ; Fold upper, lower pairs of pixels MOVR R0, R1 ; SLR R0, 1 ; SLR R0, 2 ; ADDR R1, R0 ; Fold left, right pixels ANDI 7, R0 ; Select remaining pixel MVI@ R6, R7 ; return ENDP ; Data tables for pixel routines MSKTBL: DCW $07, $00, $38, $00, $C0, $01, $00, $26 CLRTBL: DCW $00, $00, $49, $02, $92, $04, $DB, $06 DCW $24, $21, $6D, $23, $B6, $25, $FF, $27 ;=========================================================================== ; START: Code which runs after title screen. PROC START MVO@ R5, R6 ; Save return address on stack MVII $00F0, R0 MVII $0200, R4 SDBD MVII $1000, R1 JSR R5, $1741 ; Clear BACKTAB to color sq mode DIS ; This demo has no interaction and no need for interrupts. XORR R0, R0 MVO R0, $2C ; Black border. ; Draw the 'playfield'... the place where the pixel will do its ; bouncing. The screen coordinates go from (0,0) to (39,23) ; ; (5,3) (34,3) ; ************************ ; * (11,8) (28,8) * ; * * * * ; * * * * ; * * * * ; * * * * ; * ************** * ; * (11,16) (28,16) * ; (5,19) (34,19) ; Draw horizontal lines MVII 5, R1 @@hloop: MVII 1, R0 ; Blue MVII 3, R2 ; y = 3 MVO R1, $340 ; Save 'x'. Putpixel trashes it. JSR R5, PUTPIXEL ; Draw upper row MVI $340, R1 ; Restore 'x'. ; Are we in the range for the second horizontal line? CMPI 11, R1 BLT @@skiph CMPI 28, R1 BGT @@skiph MVII 2, R0 ; Red MVII 16, R2 ; y = 16 JSR R5, PUTPIXEL ; Draw lower row MVI $340, R1 ; Restore 'x' @@skiph: INCR R1 CMPI 34, R1 BLE @@hloop ; End of horizontal line loop. ; Draw vertical lines. There are four of these. MVII 4, R2 @@vloop: ; Far left side MVII 5, R1 ; x = 5 MVII 1, R0 ; Blue MVO R2, $340 ; Remember 'y'. Putpixel trashes it. JSR R5, PUTPIXEL ; pixel(5, y) = blue MVI $340, R2 ; Restore 'y'. ; Far right side MVII 34, R1 ; x = 34 MVII 1, R0 ; Blue JSR R5, PUTPIXEL ; pixel(34, y) = blue MVI $340, R2 ; Restore 'y' again. ; Are we in the row range for the inner to columns? CMPI 8, R2 BLT @@skipv CMPI 15, R2 BGT @@skipv ; Inner left side MVII 11, R1 ; x = 11 MVII 2, R0 ; Red JSR R5, PUTPIXEL ; pixel (11, y) = red MVI $340, R2 ; Restore 'y' yet again. ; Inner right side MVII 28, R1 ; x = 28 MVII 2, R0 ; Red JSR R5, PUTPIXEL ; pixel (28, y) = red MVI $340, R2 ; Take a wild guess. @@skipv: INCR R2 CMPI 19, R2 BLE @@vloop ; End of vertical line loop. ; The main event: Launch a bunch of bouncing pixels. main: MVII $300, R4 ; Pixel records start at $300. MVII 10, R0 ; 10 bouncing pixels MVII 1, R1 ; All blue MVII 5, R2 ; Start at x = 5 MVII 1, R3 ; This toggles between +/- 1 MVII 22, R5 ; Row 22 @@mkpixlp: MVO@ R2, R4 ; x = 5 + 3*k MVO@ R5, R4 ; y = 22 MVO@ R3, R4 ; xvel = +/- 1 NEGR R3 MVO@ R3, R4 ; yvel = -/+ 1 MVO@ R1, R4 ; color = 1 ADDI 3, R2 DECR R0 BNEQ @@mkpixlp MVO R4, $33F ; Remember end of pixel records @@mainlp: MVII $3FF, R3 ; Delay constant. @@dly: DECR R3 MVO R0, $20 ; Whack vid enable just in case. MOVR R3, R3 BNEQ @@dly MVII $300, R4 ; Start of list of pixel records @@drawpix: JSR R5, BOUNCEPIX ; Update current pixel, point to next MVO R0, $20 ; Vid enable, just in case. CMP $33F, R4 ; Are we at end yet? BLT @@drawpix ; No? Keep going. B @@mainlp ; Go around the main loop again. ENDP ; BOUNCEPIX PROC BOUNCEPIX MVO@ R5, R6 ; Save return address MVO@ R4, R6 ; Save pixel record pointer ; Update pixel position, and detect whether we hit something MVII $340, R5 MVI@ R4, R1 ; Load X position MVI@ R4, R2 ; Load Y position MVO@ R1, R5 ; Store X in temp. local storage MVO@ R2, R5 ; Store Y in temp. local storage MVI@ R4, R0 ; Load X velocity ADDR R0, R1 ; Add XVEL to X position MVO@ R0, R5 ; Store XVEL in temp. local storage MVI@ R4, R0 ; Load Y velocity ADDR R0, R2 ; Add YVEL to Y position MVO@ R0, R5 ; Store YVEL in temp. local storage MVI@ R4, R0 MVO@ R0, R5 MVO@ R1, R5 ; Store candidate X coordinate MVO@ R2, R5 ; Store candidate Y coordinate XORR R3, R3 @@ytst: ; Did we hit a screen border? TSTR R2, R2 BMI @@yhit ; hit top CMPI 23, R2 BLE @@xtst ; didn't hit bottom @@yhit: MVII 2, R3 ; Mark yvel to be inverted @@xtst: MOVR R1, R1 BMI @@xhit ; hit left CMPI 39, R1 BLE @@btst ; didn't hit right @@xhit: ADDI 1, R3 ; Mark xvel to be inverted B @@hits @@btst: ; Did we already hit a border? If so, then don't test for barriers. MOVR R3, R3 BNEQ @@hits ; Did we hit an interior barrier? JSR R5, GETPIXEL XORR R3, R3 MVI $345, R1 MVI $346, R2 MOVR R0, R0 BEQ @@nohits ; didn't hit barrier INCR R0 ANDI 7, R0 BNEQ @@putit INCR R0 @@putit: JSR R5, PUTPIXEL ; Did we hit it on x, y or both? ; This works by testing whether there was a barrier along just X, ; just Y, both X and Y, or on just a corner. MVI $340, R1 ; Undo X movement, see if we still hit MVI $346, R2 ; Retain Y movement JSR R5, GETPIXEL XORR R3, R3 MOVR R0, R0 BEQ @@noxbar ; No barrier along X MVII 2, R3 ; Invert Y if there's a horizontal barrier @@noxbar: MVI $345, R1 ; Retain X movement MVI $341, R2 ; Undo Y movement, see if we still hit MVO R3, $347 ; Save hit status. JSR R5, GETPIXEL MVI $347, R3 ; Restore hit status. MOVR R0, R0 BEQ @@noybar ; No barrier along Y ADDI 1, R3 ; Invert X if there's a vertical barrier @@noybar: ; If we didn't see an x or y barrier, we hit a corner, so negate ; both X and Y velocity. MOVR R3, R3 BNEQ @@hits MVII 3, R3 B @@hits @@hits: ; Increment the color of the pixel MVI $344, R0 INCR R0 CMPI 7, R0 BLT @@colorok MVII 1, R0 @@colorok: MVO R0, $344 ; Reflect x, y as needed MVI $342, R1 ; Old X velocity MVI $343, R2 ; Old Y velocity ; If R3 is non-zero, invert X, Y velocity. SARC R3, 1 BNC @@noinvx NEGR R1 MVO R1, $342 @@noinvx: SARC R3, 1 BNC @@noinvy NEGR R2 MVO R2, $343 @@noinvy: ADD $340, R1 ; Add new xvel to old xpos ADD $341, R2 ; Add new yvel to old ypos @@nohits: ; Save out the updated x, y positions (in R1, R2) MVI@ R6, R4 MVO@ R1, R4 ; Save new X to pixel record MVO@ R2, R4 ; Save new Y to pixel record MVO R4, $345 MVI $344, R0 ; Get pixel color JSR R5, PUTPIXEL ; Draw new pixel MVI $340, R1 ; Get old X MVI $341, R2 ; Get old Y XORR R0, R0 ; Clear old pixel to black JSR R5, PUTPIXEL ; Now, write it all back out to the invocation record. MVI $345, R4 MVII $342, R5 MVI@ R5, R0 ; New X velocity MVO@ R0, R4 MVI@ R5, R0 ; New Y velocity MVO@ R0, R4 MVI@ R5, R0 ; New color MVO@ R0, R4 ; R4 now points to next pixel record. MVI@ R6, R7 ; Return. ENDP