From 7385179a387857f88308af74ef37f846700f2430 Mon Sep 17 00:00:00 2001 From: Carlos O'Connor Date: Mon, 1 Apr 2024 03:12:30 -0500 Subject: [PATCH] Mouse support --- pvsneslib/include/snes/pad.h | 25 +- pvsneslib/source/consoles.asm | 6 + pvsneslib/source/crt0_snes.asm | 3 + pvsneslib/source/pads.asm | 244 +++++++++++- snes-examples/pads/mouse/Makefile | 30 ++ snes-examples/pads/mouse/buttons.png | Bin 0 -> 5806 bytes snes-examples/pads/mouse/cursor.png | Bin 0 -> 5153 bytes snes-examples/pads/mouse/data.asm | 28 ++ snes-examples/pads/mouse/hdr.asm | 46 +++ snes-examples/pads/mouse/mouse.c | 421 +++++++++++++++++++++ snes-examples/pads/mouse/pvsneslibfont.bmp | Bin 0 -> 3190 bytes 11 files changed, 799 insertions(+), 4 deletions(-) create mode 100644 snes-examples/pads/mouse/Makefile create mode 100644 snes-examples/pads/mouse/buttons.png create mode 100644 snes-examples/pads/mouse/cursor.png create mode 100644 snes-examples/pads/mouse/data.asm create mode 100644 snes-examples/pads/mouse/hdr.asm create mode 100644 snes-examples/pads/mouse/mouse.c create mode 100644 snes-examples/pads/mouse/pvsneslibfont.bmp diff --git a/pvsneslib/include/snes/pad.h b/pvsneslib/include/snes/pad.h index 3b6133600..7b53495fb 100644 --- a/pvsneslib/include/snes/pad.h +++ b/pvsneslib/include/snes/pad.h @@ -64,6 +64,16 @@ extern u16 pad_keysold[2]; extern u16 pad_keysrepeat[2]; extern u8 snes_mplay5; /*!< \brief 1 if MultiPlay5 connected */ +extern u8 snes_mouse; /*!< \brief 1 if Mouse is going to be used */ + +extern u8 mouseConnect[2]; /*! \brief 1 if Mouse present */ +extern u8 mouseButton[2]; /*! \brief 1 if button is pressed, stays for a bit and then it gets released (Click mode). */ +extern u8 mousePressed[2]; /*! \brief 1 if button is pressed, stays until is unpressed (Turbo mode). */ +extern u8 mouse_x[2], mouse_y[2]; /*! \brief Mouse acceleration. daaaaaaa, d = direction (0: up/left, 1: down/right), a = acceleration. */ +extern u8 mouseSpeedSet[2]; /*! \brief Mouse speed setting. 0: slow, 1: normal, 2: fast */ + +#define mouse_L 0x01 /*! \brief SNES Mouse Left button mask.*/ +#define mouse_R 0x02 /*! \brief SNES Mouse Right button mask.*/ /*! \def REG_JOYxLH @@ -109,7 +119,7 @@ extern u8 snes_mplay5; /*!< \brief 1 if MultiPlay5 connected */ #define REG_JOYxLH(a) (((vuint16 *)0x4218)[(a)]) /*! \fn scanPads() - \brief Wait for pad ready and read pad values in . + \brief Wait for pad ready and read pad values in. */ void scanPads(void); @@ -147,8 +157,19 @@ void padsClear(u16 value); void detectMPlay5(void); /*! \fn scanMPlay5() - \brief Wait for multiplayer5 pads ready and read pad values in . + \brief Wait for multiplayer5 pads ready and read pad values in. */ void scanMPlay5(void); +/*! \fn mouseRead(void) + \brief Wait for mouse ready and read mouse values in. +*/ +void mouseRead(void); + +/*! \fn MouseSpeedChange(u8 port) + \brief Set mouse hardware speed (populate mouseSpeed[] first). + \param port Specify wich port to use (0-1) +*/ +void MouseSpeedChange(u8 port); + #endif // SNES_PADS_INCLUDE diff --git a/pvsneslib/source/consoles.asm b/pvsneslib/source/consoles.asm index b81397620..fe31a0f8a 100644 --- a/pvsneslib/source/consoles.asm +++ b/pvsneslib/source/consoles.asm @@ -383,6 +383,12 @@ consoleVblank: beq + jsl scanMPlay5 bra cvbloam ++ lda snes_mouse + beq + + jsl mouseRead + lda mouseConnect + and mouseConnect + 1 ; If both ports have a mouse plugged, it will skip pad controller reading + bne cvbloam + jsl scanPads cvbloam: diff --git a/pvsneslib/source/crt0_snes.asm b/pvsneslib/source/crt0_snes.asm index 2ee40991f..84f176846 100644 --- a/pvsneslib/source/crt0_snes.asm +++ b/pvsneslib/source/crt0_snes.asm @@ -343,6 +343,9 @@ fast_start: stz.w snes_frame_count stz.w snes_frame_count_svg + stz.b snes_mouse ; set mouse usage disabled by default + stz.w mouseConnect; + jsr.l main ; write exit code to $fffd diff --git a/pvsneslib/source/pads.asm b/pvsneslib/source/pads.asm index 282d369f0..bce18ccd0 100644 --- a/pvsneslib/source/pads.asm +++ b/pvsneslib/source/pads.asm @@ -91,6 +91,31 @@ scope_sinceshot dsb 2 .ENDS +;--------------------------------------------------------------------------------- +; Mouse Driver Routine (Ver 1 .00) +;--------------------------------------------------------------------------------- + +.RAMSECTION ".reg_mouse" BANK 0 SLOT 1 + +snes_mouse db ; for lib use. Tells the system to initialize mouse usage +mouseConnect dsb 2 ; Mouse connection ports (D0=4016, D0=4017) + +mouseSpeedSet dsb 2 ; Mouse speed setting +mouse_sp dsb 2 ; Mouse speed + +mouseButton dsb 2 ; Mouse button trigger +mousePressed dsb 2 ; Mouse button turbo + +mouse_y dsb 2 ; Mouse Y direction +mouse_x dsb 2 ; Mouse X direction + +mouse_sb dsb 2 ; Previous switch status + +connect_st dsb 2 + +.ENDS + + .BASE BASE_0 .SECTION ".pads0_text" SUPERFREE @@ -119,7 +144,9 @@ scanPads: lda REG_JOY1L ; read joypad register #1 bit #$0F ; catch non-joypad input beq + ; (bits 0-3 should be zero) - lda.b #$0 + sep #$20 + lda #$0 + rep #$20 +: sta pad_keys ; store 'current' state eor pad_keysold ; compute 'down' state from bits that and pad_keys ; have changed from 0 to 1 @@ -128,7 +155,9 @@ scanPads: lda REG_JOY2L ; read joypad register #2 bit #$0F ; catch non-joypad input beq + ; (bits 0-3 should be zero) - lda.b #$0 + sep #$20 + lda #$0 + rep #$20 +: sta pad_keys+2 ; store 'current' state eor pad_keysold+2 ; compute 'down' state from bits that and pad_keys+2 ; have changed from 0 to 1 @@ -583,4 +612,215 @@ NoScope: plp ; return from input check rts +.ENDS + +;--------------------------------------------------------------------------------- + +;* mouse_read + +;--------------------------------------------------------------------------------- + +;* If this routine is called every frame, then the mouse status will be set +;* to the appropriate registers. +;* INPUT +;* None (Mouse key read automatically) +;* OUTPUT +;* Connection status (mouse_con) D0=1 Mouse connected to Joyl +;* D1=1 Mouse connected to Joy2 +;* Switch (mousePressed,1) D0=left switch turbo +;* D1=right switch turbo +;* Switch (mouseButton,1) D0=left switch trigger +;* D1=right switch trigger +;* Mouse movement (ball) value +;* (mouse_x) D7=0 Positive turn, D7=1 Negative turn +;* D6-D0 X movement value +;* (mouse_y) D7=0 Positive turn, D7=1 Negative turn +;* D6-D0 X movement value + +;--------------------------------------------------------------------------------- + +.SECTION ".mouse_text" SUPERFREE + +;--------------------------------------------------------------------------------- +; void mouseRead(void) +mouseRead: + php + sep #$30 + phb + phx + phy + + lda #$00 ; Set Data Bank to 0 + pha + plb + +_10: + lda REG_HVBJOY + and #$01 + bne _10 ; Automatic read ok? + + ldx #$01 + lda REG_JOY2L ; Joy2 + jsr mouse_data + + lda connect_st+1 + beq _20 + + jsr speed_change + stz connect_st+1 + + bra _30 + +_20: + dex + lda REG_JOY1L ; Joy1 + + jsr mouse_data + + lda connect_st + beq _30 + + jsr speed_change + stz connect_st + +_30: + ply + plx + plb + plp + rtl + +mouse_data: + + sta tcc__r0 ; (421A / 4218 saved to reg0) + and.b #$0F + cmp.b #$01 ; Is the mouse connected? + beq _m10 + + stz mouseConnect,x ; No connection. + + stz mouseButton,x + stz mousePressed,x + stz mouse_x,x + stz mouse_y,x + + rts +_m10: + lda mouseConnect,x ; When mouse is connected, speed will change. + bne _m20 ; Previous connection status + ; (mouse.com judged by lower 1 bit) + lda #$01 ; Connection check flag on + sta mouseConnect,x + sta connect_st,x + rts +_m20: + rep #$10 + ldy #16 ; Read 16 bit data. + sep #$10 +_m30: + lda REG_JOYA,x + + lsr a + rol mouse_x,x + rol mouse_y,x + dey + bne _m30 + + stz mousePressed,x + + rol tcc__r0 + rol mousePressed,x + rol tcc__r0 + rol mousePressed,x ; Switch turbo + + lda mousePressed,x + eor mouse_sb,x ; Get switch trigger + bne _m40 + + stz mouseButton,x + + rts +_m40: + lda mousePressed,x + sta mouseButton,x + sta mouse_sb,x + + rts + +;--------------------------------------------------------------------------------- +; void MouseSpeedChange(u8 port) +MouseSpeedChange: + php + sep #$30 + phb + phx + phy + + lda #$00 ; Set Data Bank to 0 + pha + plb + + lda 8,s ; Set port + tax + + jsr speed_change + + ply + plx + plb + plp + rtl + +speed_change: + php + sep #$30 + + lda mouseConnect,x + beq _s25 + + lda #$10 + sta tcc__r0h +_s10: + lda #$01 + sta REG_JOYA + lda REG_JOYA,x ; Speed change (1 step) + stz REG_JOYA + + lda #$01 ; Read speed data. + sta REG_JOYA ; Shift register clear. + lda #$00 + sta REG_JOYA + + sta mouse_sp,x ; Speed register clear. + + ldy #10 ; Shift register read has no meaning +_s20: + lda REG_JOYA,x + dey + bne _s20 + + lda REG_JOYA,x ; Read speed + + lsr a + rol mouse_sp,x + + lda REG_JOYA, x + + lsr a + rol mouse_sp,x + lda mouse_sp,x + + cmp mouseSpeedSet,x ; Set speed or not? + + beq _s30 + + dec tcc__r0h ; For error check + bne _s10 +_s25: + lda #$80 ; Speed change error. + sta mouse_sp,x +_s30: + plp + rts + .ENDS \ No newline at end of file diff --git a/snes-examples/pads/mouse/Makefile b/snes-examples/pads/mouse/Makefile new file mode 100644 index 000000000..28f6ac0d1 --- /dev/null +++ b/snes-examples/pads/mouse/Makefile @@ -0,0 +1,30 @@ +ifeq ($(strip $(PVSNESLIB_HOME)),) +$(error "Please create an environment variable PVSNESLIB_HOME by following this guide: https://github.com/alekmaul/pvsneslib/wiki/Installation") +endif + +include ${PVSNESLIB_HOME}/devkitsnes/snes_rules + +.PHONY: bitmaps all + +#--------------------------------------------------------------------------------- +# ROMNAME is used in snes_rules file +export ROMNAME := mouse + +all: bitmaps $(ROMNAME).sfc + +clean: cleanBuildRes cleanRom cleanGfx + +#--------------------------------------------------------------------------------- +pvsneslibfont.pic: pvsneslibfont.bmp + @echo convert font with no tile reduction ... $(notdir $@) + $(GFXCONV) -s 8 -o 2 -u 16 -p -t bmp -i $< + +cursor.pic: cursor.png + @echo convert sprites ... $(notdir $@) + $(GFXCONV) -s 16 -o 48 -u 16 -p -t png -i $< + +buttons.pic: buttons.png + @echo convert graphics ... $(notdir $@) + $(GFXCONV) -s 8 -o 7 -u 16 -p -e 1 -m -t png -i $< + +bitmaps : pvsneslibfont.pic cursor.pic buttons.pic diff --git a/snes-examples/pads/mouse/buttons.png b/snes-examples/pads/mouse/buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..c2be1d02ed8b21ad6714412480f829d5c279a001 GIT binary patch literal 5806 zcmeHLc|4R|-#?Uy%2FhXX;4~bHI^9-*~yaIa?_&BhQZ7*Gt7*lX;GGTdr2xnDqBQU zDoM5$WJ%T%(qbpudue;$_j&I7d7jVxdH#Ez^O?D>bDi`3ZQtMToO6AyaCh(KMSD6s&#!uQlEK(~dSMz%%(G3{Ft!4~Y+87< zQ*Zi!{mRO>l0bb4xEfj3Yz$Il0G2I}6$4mFFp$Dc5Cs|l>{3x)DJ}FC0s6GF+ZTYq zm+Ir9pg_}cqv+NvVC%Zd72)9dGT<6_Wkn>&b_bf3XTmrl+2?`#*-O>Y!2L52Uf7^O zT_B?f+%L;WIf_V(fzs0!W?z7WmWbx@=q&zAm)&b?9Rc`~OO1SYHrh#yx%O7sn%!Poq^XeEAqeX)ORk^FULfbnSRIUcZo_|5~qwus=V2PH8$a z>_p^ToMF~O5fN~tZq#flujINC_@oF51|wr{tx2XW6~3B5oqMVR8jOWKnR{yQzcXaaN;sYXkNAuo6v+a$Cry`=nDwl|<$aWl-%ERVHv$yP8 zClld+-cV(*9XUPBvx$^hANh`)VSn7hx~xc!E?HZ3HbPy}Dt1MjE9u{j7suc?L`3F_2kJ^VF(sKpImZ3JMO^};Io$VKD zWXl#9%MTpgnSRV%PZZ%NTKiC}P_(f_VT*8&qVPRhlI6bINCx}R)HO_pER2W03R8P% z=CL-!5-oSIY;CxuB-|{z!hx#oa41^MxnfU>%A^YZWTF{zEwO@_BE8By#Ka(3v2ts3 zx{CMFmP@K&G60Zqvfti zh)dKQS@v+Lu_`J0OG1Tuzub**rl|oYHr}{eLqT>^SU?%2Y`AP!nMjwiTzJ{qgs9z? z2UGMMl<12yqHjgjn-Wa=*N#S&S5R|xn$HawEz^*ykYvjW^e1H|agzjraQdWinxg&c z4YSewh-inc8Of_t5-;ygTjEfj;qByjO<6m7<7MR4*x!6I81-{7d-5Slg(bd z^vd*#xnYyHc52Z(6J~rZp^q^SpPw-?6|~?sZ~~XIhSRQ+rNv^ObW-=d^HFw1;t-+S|Ry*yxk1 zjy-$Y5$%7{kI6Bxd2zmrXtsqm6J5TcF|DNG+_iV98m~6K@_uJx@>T+oi?HQ_Rcv zKzNw+?CjY;ynlGn@G%7&sqK+w3fc;~2&>rLRotozv5nX5H?7Zf%Jk06e3hP`mtPi? z7Vr$$g=?h0q-)oGYC`*#Fxb9IzF&Ru1rG|u3J?XT0h@uYk2=i(Ex`r6+-KQY`3E|Z zJJGK%m0qgp)V0`Tafy=OUDH?HH(Tdo!@4lbK03N&@VJ}SCqho5apEgNzJ4$}&_7mR zmmpmnU#Na(z^~{Ljq|85wKejlsf%i({LS^d+l%qV8(L2m&h#_8lRkw!5B9n`X){>e zk}#uUt|EHsuFBoKFFV5X#;W^AaU(1EulNRo*fBXlgJ5aUuAnr5>QG20<+Iv2zGpc0 zefh3({qD%gMH32Bfm8H}n$gUmeFLnw7rWX!43#=oWUF`Bz%Xb{KgW(W_f+;)WW7IC z8<=p{H_$>xO%t2GvDYfwIeSYXV&T$+HM#h=ovZ8cFY$;=GL_PAR)5v3-s1aP)2Yss zFWF!Ezof}7leJbOsO>l-r6z5DFMKF`V`LDzk$jWQ+;_{HYs?KEd9BzUKNR2QTHHj- zap~fAsr%m;d^^!Qac3e&5Heg)t8D4FO>p|J6L-s}|+&70`yro8Ws#wlkZm?1iUJ!Qlu}T+v&^_0JEf}(ou&C^b?sR%qA5ky6 zc)Np!AVDF%K>s5n$m{FuNci#i<5z9Ad60YjGmhfiTF#_ijEQSd%ZrtN8nm(q(Q?Pj zNku)Y$~^bI=k1M6k_nfs>6dn28K_E#al9~$)Fq62B?TqnvV3wHx<(_#hi8WGyBWK} zcfY(>@7H%NHMpuI?xWku&D(dj-FwJ4>x?)UBeF^Q`sEwj_KrFp3^o!x_|SmKd@VUD z>7p=}wb-@JKE**Dbtmst@W)R9M*_|Uy!nup)qZc5laoHd4iC06d-}wI)c20H`d-Gg z2iauk=qK#^TsLJa{y3aj$OatA+!5<%Hi`kK<5G6^0d~k8#51 zBi>+&zwi9M*Ey<;1FZ)helZ=js)?edd8J8iw@s`yBnFxXdc5_mY@Qtp{U}}gIH|Z< zw(Ui*LGScqso9ma0YSW^d%gaHWg54wpP)FX+q?bmy=;9~A26^!?c&J*eV*>#fTEV5 zn$exRo>eC~HWITg-tFAi{m^!{X4CDS*8U>m_}Cl$#k`=;5ucX5sVW>F3aOnL6yKyO zr>bD+u+M4Gb=<$^S*)S%C}BKlVEE&QAi2r6M)$MlCJl4v2K|%2Y#63LPJZA%bGrL^ zIBBla=UER?nUCCOVBjzk`4y$V$F*dl(En+BQlZyO z7{$`T7J#6200@r&@D&;o_5u)q2B6;^075(fEBzAh{I&&v1;F0M$!reHLG9_&r%_Q+ zo}QlO=H`&df7^c<_zz*A=1AL8DAdJ%mOD5ANG+fLi-2>9iU2Iip*y*9U2Sa$6cz(X zqO!;|B%k5;jhHQld_NM!hsK4GX`XZ@5&pUOJ{(4;65%e|wrE>F6Pg#@GKfuc46<{g z1o=?#RJfr5Yzvg-!S4(pgN{ zyhak46~HCJAy>c0!0`K}mdW|S6T}#bPx3=ykm&iCz5%I}UpT)2w(mFNR0@jbOJmTO zTn>cA{K7&s+1mbs|Djq2;}@F4H4B71`Vre7qB%|iKN`w`#$g4pDKxV{$fDX$$Naol zTo%WR^(S%sn*J4yAHjr8BXL=5Cl<^1XQu3bYJp*KNGwd#h0dh1c$^LMR(=T3Oi5fC z5e{Vyhd@I=tP_+qEervpjX-M?(CF__Tc{AIBrfT1z*I8V-X;V6}Cq2%Hv-m)-f(gr)#kOTp=UIls{&(C8`r5)~dC+~K ziNE{mGGFN53XWh&=RjE%{8&1UH2)txUpnktjS)zc`DH+aQ|9wegDChuO#cH4|1}D} z%k#WwkkWrp7vEtVmIs$dV$+N~A-ex*-J$->c@8P?AG?mz(IV?Gz~qUeG&o> zZ8->x4q01Q7f;pG($@VM`k%P2{i{mc%!F$YlPvlj#+CqIh~Ib+?}E|Xb%e-jaPNLr{^p%k~o`RWthmyYW<9?va&M?7@O zQ~r7NzW0mwzncpe(T**r_0g^`inRpZ*UdMVS?!kt!g<8mV+c87+rC!kwju|h0JH3V zY5B}S!bm0?TY9!^eN?(+*EKDHB0?^|8JZjIedl1n=6N~mi8U$Q^s291bt+B6rhuB*| zri%T|Qt97cRX*>kwHcbg9T9OCbzOYITJy;hH?o-gp%~YM(&(}^s(Ca~A9*;(S^D{{ zJ5A|E-He#iX`>%DzhKx+6)jmCs;InJW+$)0(Ts1uPN*I(en$3*Tfq_nUs5P|XMkSdz9>H7L3K+NEzCsw((&G_JicMpTHB-B6Ak^Hmq$;ZF%)ku zUlTWA4L`=$zVf!=qTZv+My}6ho*yQJv>fi=lkk z^?qHxqjV61O4$CDHKaS5JVEi&kZN$Lx}bKasCRaF*6K`rbS`eEm0Chw#pVM zluB+1-DQ`(lBBXrw&$nC`@YX}KhM+W`Q!cTIiLA$=X}riy3Y5y&h?qk33u3LwNzR~ z8UV1=#+u{^J>}*uDGBJVjgWPM9t%87?M(s5IU_Sgkpw{6mSJx0z;m=RgV|V^>tXPE zdI&5M1Auk-WhW1^(|aZ2c>9Q%ZJ031mhGr01#>hL3CWDB3gHU}ONYML`H7AU3tx>H+^+%DU$5}emlqR$@7DjCCjT>cy%Yz!=2vq=|2 zGsI|H6^Furx{)4IZM{H3nhZNEA>0y+kO?0-BMv$z2M7A0(J$f)I;)vm0AMvOINoJ2 zb;x05=xJ;Ceo(DhjxM2Exl5lxPxi z%E0xioQ#v0)EFo|Yh^J2q;$lzPex@0yxi%swgwV(AeSb3dp?RR$y$56Y>ms_y8(#? z`sOzrnvN|#_Fnw1)H^!8a>2_dAW}yH2rd0dLfM+}*LcH1g5fKJ7Q(^&v{{uYQP?Tb z>;;poM`B{&Sna6AWM1(N74S(J6by=DZm&tCFBLXSqb@#G1NCOYp3ME#kGmjk$f0IE z?j9E|UGm-}FT)H?-#_AQp3+zO4>qT$f(j87(*_Pc^U`W?IJ0GDbZ44A-51<79Nch$O81lrP(!}t3YD&`4y{yaHV{x zO!QFvQ)MwAl)^bk>UkbDRz51(B-AJr8U`FzuR87!cErFLm|2I~oi#^p4&C9fKr36m zz)Z3K`0lh5mImSoj(E)@$wKkQP9-DZK4sxMv^3jwwW%ET5y?4B&rKK$ZwS+PWZ}Lx z#2T$|xNL2>wKUu!s=|?`>v$weV@JilWVH!3{ONcL+DhidQctbjN7c+Oy~yiT98qc!8C(5v@ z)yI}ST56_Fi5iHj(CkyV8O|aZV`5^>sSzbZQ)oZ@kZ@NrNrb3!4A80rsH-VcV1PZ54o24o{tllsa z6%Y~SxFtPtb#nYwm((SW<>_8zrwmoysEt>V*JFP3PG{C-)`|5Q*k5+vHk@ej;-zP% zXY_5$mcSPCmQ94qERrDQM6K3H^vKq)l&=;+>eEE?qm(C|7zO369M{Zc6XBNX|7&*`2cM?Y&Bw9T^$v8F%``>krmT*I&!n zxx=b1&CA`(NcV6HH{UD&wU?l-ylz+Dvc9CgxW1IWMfIq3S;kr2D%=!~q!Ow!iK}6Z z0G>64AwtI1@n`mJ~pN=Zu(3o0We=*~2idMtM2CtX*QbtWx8^>z5HMS?WU7fZ* zkw{Hhek(FF&-Pt$O$B+3Jf8k2{fW~VyOJzX-|qL8y~r1BsjpHDucv0MOk7|4>Xu*| zn{?&c=aehgA6U#r&18!`bB#G%<|=x~IOOSd`tG}tL)LnE%9e~FR$evb|>PdP8&9pP@? zv%BZu@WJ7Q!zYyNWVVYelysH!5jHU{&-l+S$28t>*t9;AoavRB*^ri>mtPi?>h~Pi zjca7QWa!p@YC`)IGr2x0K3{$C1rG}(3lIgUe!Kqek9y61Ex`qX+~?U@`G-0ayU?$a zN|UO)^sP2oB~kNVSHG`%KU2HYj(vHCdwg`s;K{u@p9neeX7LS#e8XU_zi*78K0&r9 zwovn4Kj-daI`45|N~`D=X{UOl;;r>A9Yy$}4XvjOr~6p16F!Cf8SHs|!fvptC2m^H zQce6!iCRhCz^?GTv8ujN+{lW6h5+M1?3hAeec;ldJwd5~>O&!2)Xy5@_@3dIcjbG^ z4PT2U7JgBh^q*vWsUFQ7I?&I4bEUhZ(?q3nMYd+A9Snok<~Vh(xv#drBJ16m8vnQw zAAc)34Q*`N#$KE39oa^Ohy_dI*5u;fbgiz%zr-Vwa$AEzu2{}mZoD!uyddoO6SZ#cplhxbH*m-y!m6?-s*C)*E}~9;@peb8 zz&NGY0>h8YAkVKeBjG1wPhPj%>h9L#n|>U(x8+>QmFNrg8hJ5_PlHz8MYP=WB&%s= zJ+sVx=W%CalXTowTSk)0wf<*u(N33#k@|#j&xD`^T$XoEefOwn(eU)}gS}?XaF>_& z>p1T-Qi7iqU--E9^yclm+wVULu;_|794)p<_QutlTlbGT9S$}PeE6Xrlle+|RC=e< zSk_|aT8CsuP1L=-hTxB%{EqpZ_iOu*n$>ZChL@A}g&Q7hWAXG4N6P!R?A73zRTUKYNMK>%4QF>@)KQ3j2;vp;#KtYAil(OBeL!wTZ7WwET4R0-ey)ZOQIh} z-+X0Xz;2z%*_hw=d;WI6+GTBPJ_w52Hnao=Uue8l-WF73>wl<8qnRgQm$vt)dZr}haL@(Ms2Di>8YNn(%bFhYfOm#mj3Qc{bx93 zw#)l@4^cG$dBE7%aYXbLWw_6|_)FK$to=onRI5e%D)(=j`u*$H$@-Z_oqc!Cgq|XX zL{7L*F$WDl3Kq5VIs_qM6KI2k$#YXVLy>P&3!a-^QQt<}W;eB5B6fJ{gvS8*3Uvv40q{cu(B}#OAr^p@ocMdc837;x9PG#zvtSl#2?+@h@>d#! z|BX8fHs<^a7{Wk!#V!Cu3x5&+U)X;Y`2SSk)Cav>$lhX(^)4O&GRx;KF>o3o=$yi>L9E zfkfv~xeN}U!Dhkc7%6USKRyu-x%zz#OwK$li}yn(NHJ6Zg@eK%(Q|A12BcBvaU4Ic z&o|>VDvItyXVO`G9)!irVObVnDgGuqAqc|*&Z`SPX2{tSqpTeTjZAe5oF(W&3Ph31pkRKK|h{+v&P=2P_C(HM*Y z1%c6@o2rYWBHY|Cc!Zvgo*r69hlbY2V1L@*&SgMbh~o2~^UOzxV9xeobM4u*IhEnC z|LM1ZPFuKacZLr%@DHahbBX>f;Rx0Y9u(EUA6v(X?)&4-hXMPRV+0CyZW|Ec)VcW6 zY49K2jK7fZ*ChB(EAXU4r2ir>zQcHIcfNqarJH&{a{t@BL;W-7c@+PD?fS1p|1Vwt z$1MF%T>l{})sw>VphHC!1)p0CYOeZx4+`q<KdsT%qUj)*TPB1 yia8afC{^RTAOrO3iWp;8r5gqtRJ%?M^oZ4(Dxp!6rqEd*05%reNVm*fkNge(_*HcP literal 0 HcmV?d00001 diff --git a/snes-examples/pads/mouse/data.asm b/snes-examples/pads/mouse/data.asm new file mode 100644 index 000000000..fa89e6199 --- /dev/null +++ b/snes-examples/pads/mouse/data.asm @@ -0,0 +1,28 @@ +.include "hdr.asm" + +.section ".rodata1" superfree + +snesfont: +.incbin "pvsneslibfont.pic" + +snespal: +.incbin "pvsneslibfont.pal" + +cursorsprite: +.incbin "cursor.pic" +cursorsprite_end: + +cursorpal: +.incbin "cursor.pal" + +buttonsmap: +.incbin "buttons.map" + +buttonstiles: +.incbin "buttons.pic" +buttonstiles_end: + +buttonspal: +.incbin "buttons.pal" + +.ends diff --git a/snes-examples/pads/mouse/hdr.asm b/snes-examples/pads/mouse/hdr.asm new file mode 100644 index 000000000..9cf154d2b --- /dev/null +++ b/snes-examples/pads/mouse/hdr.asm @@ -0,0 +1,46 @@ +;==LoRom== ; We'll get to HiRom some other time. + +.MEMORYMAP ; Begin describing the system architecture. + SLOTSIZE $8000 ; The slot is $8000 bytes in size. More details on slots later. + DEFAULTSLOT 0 ; There's only 1 slot in SNES, there are more in other consoles. + SLOT 0 $8000 ; Defines Slot 0's starting address. + SLOT 1 $0 $2000 + SLOT 2 $2000 $E000 + SLOT 3 $0 $10000 +.ENDME ; End MemoryMap definition + +.ROMBANKSIZE $8000 ; Every ROM bank is 32 KBytes in size +.ROMBANKS 8 ; 2 Mbits - Tell WLA we want to use 8 ROM Banks + +.SNESHEADER + ID "SNES" ; 1-4 letter string, just leave it as "SNES" + + NAME "LIBSNES MOUSE INPUT " ; Program Title - can't be over 21 bytes, + ; "123456789012345678901" ; use spaces for unused bytes of the name. + + SLOWROM + LOROM + + CARTRIDGETYPE $00 ; $00 = ROM only $02 = ROM+SRAM, see WLA documentation for others + ROMSIZE $08 ; $08 = 2 Mbits, see WLA doc for more.. + SRAMSIZE $00 ; $00 = No Sram, $01 = 16 kbits, see WLA doc for more.. + COUNTRY $01 ; $01 = U.S. $00 = Japan, that's all I know + LICENSEECODE $00 ; Just use $00 + VERSION $00 ; $00 = 1.00, $01 = 1.01, etc. +.ENDSNES + +.SNESNATIVEVECTOR ; Define Native Mode interrupt vector table + COP EmptyHandler + BRK EmptyHandler + ABORT EmptyHandler + NMI VBlank + IRQ EmptyHandler +.ENDNATIVEVECTOR + +.SNESEMUVECTOR ; Define Emulation Mode interrupt vector table + COP EmptyHandler + ABORT EmptyHandler + NMI EmptyHandler + RESET tcc__start ; where execution starts + IRQBRK EmptyHandler +.ENDEMUVECTOR diff --git a/snes-examples/pads/mouse/mouse.c b/snes-examples/pads/mouse/mouse.c new file mode 100644 index 000000000..daddf1618 --- /dev/null +++ b/snes-examples/pads/mouse/mouse.c @@ -0,0 +1,421 @@ +/*--------------------------------------------------------------------------------- + + + snes mouse demo + -- alekmaul + + Mouse support by DigiDwrf + + +---------------------------------------------------------------------------------*/ +#include + +#ifndef MOUSE_SPEED +#define MOUSE_SPEED + +#define slow 0 +#define normal 1 +#define fast 2 + +#endif + +extern char snesfont, snespal, cursorsprite, cursorsprite_end, cursorpal, buttonsmap, buttonstiles, buttonstiles_end, buttonspal; +char hex_string[4]; + +// Init some variables +u16 p1_mouse_x = 0x80; +u16 p1_mouse_y = 0x70; +u16 p2_mouse_x = 0x80; +u16 p2_mouse_y = 0x70; + +u8 odd = 0; + +bool mc_mem[2] = {false}; +bool printed[2] = {false}; +bool mouseDown_L[2] = {false}; +bool mouseDown_R[2] = {false}; +bool mouseDown_LR[2] = {false}; +bool speedset[2] = {true}; + +//--------------------------------------------------------------------------------- +int main(void) +{ + snes_mouse = true; // Let's tell the system we're using mouse bios + + // we set mouse speed, or it will just output a random speed. We can change it later manually + mouseSpeedSet[0] = slow; + mouseSpeedSet[1] = slow; + + // Initialize SNES + consoleInit(); + + // Init cursors sprite + oamInitGfxSet(&cursorsprite, (&cursorsprite_end - &cursorsprite), &cursorpal, 48 * 2, 0, 0x0000, OBJ_SIZE16_L32); + + // Initialize text console with our font + consoleSetTextVramBGAdr(0x6800); + consoleSetTextVramAdr(0x3000); + consoleSetTextOffset(0x0100); + consoleInitText(0, 16 * 2, &snesfont, &snespal); + + // Draw a wonderful text :P + consoleDrawText(11, 1, "MOUSE TEST"); + + WaitForVBlank(); // Let's make sure we read mouse for the first time + + if (mouseConnect[0] == false) + consoleDrawText(3, 5, "NO MOUSE PLUGGED ON PORT 0"); + else + { + dmaCopyVram(&buttonsmap + 0x60, 0x6188, 0x0A); // SLOW button pressed + dmaCopyVram(&buttonsmap + 0xA0, 0x61A8, 0x0A); // SLOW button pressed + dmaCopyVram(&buttonsmap + 0x4A, 0x618D, 0x16); // released buttons + dmaCopyVram(&buttonsmap + 0x8A, 0x61AD, 0x16); // released buttons + consoleDrawText(4, 5, "MOUSE PLUGGED ON PORT 0"); + } + + if (mouseConnect[1] == false) + consoleDrawText(3, 17, "NO MOUSE PLUGGED ON PORT 1"); + else + { + dmaCopyVram(&buttonsmap + 0x60, 0x6308, 0x0A); // SLOW button pressed + dmaCopyVram(&buttonsmap + 0xA0, 0x6328, 0x0A); // SLOW button pressed + dmaCopyVram(&buttonsmap + 0x4A, 0x630D, 0x16); // released buttons + dmaCopyVram(&buttonsmap + 0x8A, 0x632D, 0x16); // released buttons + consoleDrawText(4, 17, "MOUSE PLUGGED ON PORT 1"); + } + + // Init background + bgSetGfxPtr(0, 0x2000); + bgSetGfxPtr(1, 0x4000); + bgSetMapPtr(0, 0x6800, SC_32x32); + bgSetMapPtr(1, 0x6000, SC_32x32); + + // Draw buttons for speed change + bgInitTileSet(1, &buttonstiles, &buttonspal, 1, (&buttonstiles_end - &buttonstiles), 16 * 2, BG_16COLORS, 0x4000); + + // Now Put in 16 color mode + setMode(BG_MODE1, 0); + bgSetDisable(2); + + // Wait for nothing :P + setScreenOn(); + + while (1) + { + odd++; + // Optimize Draw text by printing new text just once + if (mouseConnect[0] != mc_mem[0]) + printed[0] = true; + mc_mem[0] = mouseConnect[0]; + + // Update display with current mouse + if (mouseConnect[0] == false) + { + if (printed[0]) + { + WaitForVBlank(); + consoleDrawText(3, 5, "NO MOUSE PLUGGED ON PORT 0"); + consoleDrawText(11, 7, " "); + consoleDrawText(7, 10, " "); + printed[0] = false; + } + oamSetVisible(0, OBJ_HIDE); // Hide 1p cursor + } + else + { + // We transform raw acceleration values into coordinates for OAM. Firt bit tell us mouse direction and the rest tell us how much fast it goes. + if (mouse_x[0] & 0x80) + p1_mouse_x -= mouse_x[0] & 0x7F; + else + p1_mouse_x += mouse_x[0] & 0x7F; + if (mouse_y[0] & 0x80) + p1_mouse_y -= mouse_y[0] & 0x7F; + else + p1_mouse_y += mouse_y[0] & 0x7F; + + // And set some boundaries + if (p1_mouse_x > 0xFF00) + p1_mouse_x = 0; + if (p1_mouse_x > 0xFF) + p1_mouse_x = 0xFF; + if (p1_mouse_y > 0xFF00) + p1_mouse_y = 0; + if (p1_mouse_y > 0xEF) + p1_mouse_y = 0xEF; + + oamSet(0, p1_mouse_x, p1_mouse_y, 3, 0, 0, 0, mouseConnect[1]); + + if (printed[0]) + { + WaitForVBlank(); + consoleDrawText(3, 5, " MOUSE PLUGGED ON PORT 0 "); + consoleDrawText(11, 7, "X: Y:"); + printed[0] = false; + } + + if (mouseConnect[1] == false) + odd = 1; + + if ((odd & 0x01) && (mouseButton[0] == false)) + { + sprintf(hex_string, "%02X", p1_mouse_x); + consoleDrawText(13, 7, hex_string); + sprintf(hex_string, "%02X", p1_mouse_y); + consoleDrawText(19, 7, hex_string); + } + + // mousePressed works as turbo switch, it will be 1 until it gets released, and then it goes back to 0. Good for dragging or writing. + switch (mousePressed[0]) + { + case mouse_L: + if (mouseDown_L[0] == false) + { + consoleDrawText(7, 10, "LEFT BUTTON PRESSED "); + mouseDown_L[0] = true; + mouseDown_R[0] = false; + mouseDown_LR[0] = false; + } + break; + case mouse_R: + if (mouseDown_R[0] == false) + { + consoleDrawText(7, 10, "RIGHT BUTTON PRESSED"); + mouseDown_L[0] = false; + mouseDown_R[0] = true; + mouseDown_LR[0] = false; + } + break; + case mouse_L + mouse_R: + if (mouseDown_LR[0] == false) + { + consoleDrawText(7, 10, "BOTH BUTTONS PRESSED"); + mouseDown_L[0] = false; + mouseDown_R[0] = false; + mouseDown_LR[0] = true; + } + break; + } + } + + // Optimize Draw text by printing new text just once + if (mouseConnect[1] != mc_mem[1]) + printed[1] = true; + mc_mem[1] = mouseConnect[1]; + + if (mouseConnect[1] == false) + { + if (printed[1]) + { + WaitForVBlank(); + consoleDrawText(3, 17, "NO MOUSE PLUGGED ON PORT 1"); + consoleDrawText(11, 19, " "); + consoleDrawText(7, 22, " "); + printed[1] = false; + } + oamSetVisible(4, OBJ_HIDE); // Hide 2p cursor + } + else + { + // We transform raw acceleration values into coordinates for OAM. Firt bit tell us mouse direction and the rest tell us how much fast it goes. + if (mouse_x[1] & 0x80) + p2_mouse_x -= mouse_x[1] & 0x7F; + else + p2_mouse_x += mouse_x[1] & 0x7F; + if (mouse_y[1] & 0x80) + p2_mouse_y -= mouse_y[1] & 0x7F; + else + p2_mouse_y += mouse_y[1] & 0x7F; + + // And set some boundaries + if (p2_mouse_x > 0xFF00) + p2_mouse_x = 0; + if (p2_mouse_x > 0xFF) + p2_mouse_x = 0xFF; + if (p2_mouse_y > 0xFF00) + p2_mouse_y = 0; + if (p2_mouse_y > 0xEF) + p2_mouse_y = 0xEF; + + oamSet(4, p2_mouse_x, p2_mouse_y, 3, 0, 0, 0, mouseConnect[0] << 1); + + if (printed[1]) + { + WaitForVBlank(); + consoleDrawText(3, 17, " MOUSE PLUGGED ON PORT 1 "); + consoleDrawText(11, 19, "X: Y:"); + printed[1] = false; + } + + if (mouseConnect[0] == false) + odd = 0; + + if (((odd & 0x01) == 0) && (mouseButton[1] == false)) + { + sprintf(hex_string, "%02X", p2_mouse_x, p2_mouse_y); + consoleDrawText(13, 19, hex_string); + sprintf(hex_string, "%02X", p2_mouse_y); + consoleDrawText(19, 19, hex_string); + } + + // mousePressed works as turbo switch, it will be 1 until it gets released, and then it goes back to 0. Good for dragging or writing. + switch (mousePressed[1]) + { + case mouse_L: + if (mouseDown_L[1] == false) + { + consoleDrawText(7, 22, "LEFT BUTTON PRESSED "); + mouseDown_L[1] = true; + mouseDown_R[1] = false; + mouseDown_LR[1] = false; + } + break; + case mouse_R: + if (mouseDown_R[1] == false) + { + consoleDrawText(7, 22, "RIGHT BUTTON PRESSED"); + mouseDown_L[1] = false; + mouseDown_R[1] = true; + mouseDown_LR[1] = false; + } + break; + case mouse_L + mouse_R: + if (mouseDown_LR[1] == false) + { + consoleDrawText(7, 22, "BOTH BUTTONS PRESSED"); + mouseDown_L[1] = false; + mouseDown_R[1] = false; + mouseDown_LR[1] = true; + } + break; + } + } + + WaitForVBlank(); + + // mouseButton works as a one frame value, so it gets released shortly after pressing the button. Good for clicking stuff that need to be called once, like buttons. + if (mouseConnect[0]) + { + if (mouseButton[0] & mouse_L) + { + // Let's choose speed setting + if ((p1_mouse_y > 0x5E) && (p1_mouse_y < 0x6C)) + { + if ((p1_mouse_x > 0x44) && (p1_mouse_x < 0x64)) + { + mouseSpeedSet[0] = slow; + speedset[0] = true; + MouseSpeedChange(0); // Let's tell the mouse we want to change speed. mouseSpeedSet[] has to be populated first. + } + if ((p1_mouse_x > 0x6C) && (p1_mouse_x < 0x94)) + { + mouseSpeedSet[0] = normal; + speedset[0] = true; + MouseSpeedChange(0); // Let's tell the mouse we want to change speed. mouseSpeedSet[] has to be populated first. + } + if ((p1_mouse_x > 0x9C) && (p1_mouse_x < 0xBC)) + { + mouseSpeedSet[0] = fast; + speedset[0] = true; + MouseSpeedChange(0); // Let's tell the mouse we want to change speed. mouseSpeedSet[] has to be populated first. + } + } + } + + if (speedset[0]) + { + dmaCopyVram(&buttonsmap + 0x40, 0x6188, 0x20); // released buttons + dmaCopyVram(&buttonsmap + 0x80, 0x61A8, 0x20); // released buttons + + switch (mouseSpeedSet[0]) + { + case slow: + dmaCopyVram(&buttonsmap + 0x60, 0x6188, 0x0A); // SLOW button pressed + dmaCopyVram(&buttonsmap + 0xA0, 0x61A8, 0x0A); // SLOW button pressed + break; + case normal: + dmaCopyVram(&buttonsmap + 0x6A, 0x618D, 0x0C); // NORMAL button pressed + dmaCopyVram(&buttonsmap + 0xAA, 0x61AD, 0x0C); // NORMAL button pressed + break; + case fast: + dmaCopyVram(&buttonsmap + 0x76, 0x6193, 0x0A); // FAST button pressed + dmaCopyVram(&buttonsmap + 0xB6, 0x61B3, 0x0A); // FAST button pressed + break; + } + speedset[0] = false; + } + + if (mousePressed[0] == false) + dmaFillVram(&buttonsmap, 0x6940, 0x40); // wipe text + } + else if (speedset[0] == false) + { + dmaFillVram(&buttonsmap + 0x40, 0x6188, 0x20); // remove buttons + dmaFillVram(&buttonsmap + 0x80, 0x61A8, 0x20); // remove buttons + speedset[0] = true; + } + + if (mouseConnect[1]) + { + if (mouseButton[1] & mouse_L) + { + // Let's choose speed setting + if ((p2_mouse_y > 0xBE) && (p2_mouse_y < 0xCC)) + { + if ((p2_mouse_x > 0x44) && (p2_mouse_x < 0x64)) + { + mouseSpeedSet[1] = slow; + speedset[1] = true; + MouseSpeedChange(1); // Let's tell the mouse we want to change speed. mouseSpeedSet[] has to be populated first. + } + if ((p2_mouse_x > 0x6C) && (p2_mouse_x < 0x94)) + { + mouseSpeedSet[1] = normal; + speedset[1] = true; + MouseSpeedChange(1); // Let's tell the mouse we want to change speed. mouseSpeedSet[] has to be populated first. + } + if ((p2_mouse_x > 0x9C) && (p2_mouse_x < 0xBC)) + { + mouseSpeedSet[1] = fast; + speedset[1] = true; + consoleMesenBreakpoint(); + MouseSpeedChange(1); // Let's tell the mouse we want to change speed. mouseSpeedSet[] has to be populated first. + } + } + } + + if (speedset[1]) + { + dmaCopyVram(&buttonsmap + 0x40, 0x6308, 0x20); // released buttons + dmaCopyVram(&buttonsmap + 0x80, 0x6328, 0x20); // released buttons + + switch (mouseSpeedSet[1]) + { + case slow: + dmaCopyVram(&buttonsmap + 0x60, 0x6308, 0x0A); // SLOW button pressed + dmaCopyVram(&buttonsmap + 0xA0, 0x6328, 0x0A); // SLOW button pressed + break; + case normal: + dmaCopyVram(&buttonsmap + 0x6A, 0x630D, 0x0C); // NORMAL button pressed + dmaCopyVram(&buttonsmap + 0xAA, 0x632D, 0x0C); // NORMAL button pressed + break; + case fast: + dmaCopyVram(&buttonsmap + 0x76, 0x6313, 0x0A); // FAST button pressed + dmaCopyVram(&buttonsmap + 0xB6, 0x6333, 0x0A); // FAST button pressed + break; + } + speedset[1] = false; + } + + if (mousePressed[1] == false) + dmaFillVram(&buttonsmap, 0x6AC0, 0x40); // wipe text + } + else if (speedset[1] == false) + { + dmaFillVram(&buttonsmap + 0x40, 0x6308, 0x20); // remove buttons + dmaFillVram(&buttonsmap + 0x80, 0x6328, 0x20); // remove buttons + speedset[1] = true; + } + } + return 0; +} \ No newline at end of file diff --git a/snes-examples/pads/mouse/pvsneslibfont.bmp b/snes-examples/pads/mouse/pvsneslibfont.bmp new file mode 100644 index 0000000000000000000000000000000000000000..71bc2193705ac527d98aa6fc83cc62ef408bcbf1 GIT binary patch literal 3190 zcmbu9L6+1o5JS@s7A#nFZoxU&bDg>Vp#N1)(o6;xxI3|3mP#te$;CUPU-Dd`EC0kE&t1*^u{{qCYcE?gmJ_$?KlQ z$_9JrS3xf;ullQg&>2%JIna3I2i82qG8;RJ=Qyh3WYo4t>W%7N1IMdCY*H1Tbs%x; zfc?@}bl3}i0PGn6UKbf4OxJoqw%+ENe8W94XS}h@;~Brq`P;h%ctNx-(p8brr8Upe zZV!ZgTsfO#)%1!jzrLbT4*TyYtI4CJNoOCTpJ2ZT!<-8Vcd9>akDa{>V*5B-$_V7)#wPysG{7;_O`738K0+*M0o_{ky%);>PBYpk;fb+^eJUw64 zf(D+o#lv=6@*mG-lBa{h1!1|AyYyKK0L2rrko4sP2O~GPA`+wiTc(n7)*h7AOeEHq z(bb`Q!RTOX zdbzmi;YT+<s%Smm)rWWeSz*^_KmzXZu!@8y3D{tx_+^T5$$)|pJ l^X9k41Sz+TqSL_8aWm9&vEqbp+nMNQIg8|?%Q0uaegh|&OWObd literal 0 HcmV?d00001