Mode 2 Graphics

Discuss all aspects of programming here. From 8-bit through to modern architectures.
User avatar
FourthStone
Posts: 387
Joined: Thu Nov 17, 2016 2:29 am
Location: Melbourne, Australia

Mode 2 Graphics

Postby FourthStone » Wed Jan 18, 2017 2:21 am

Hi all,

I am looking for assembly code to index mode 2 colours in interleaved pixel format (apologies if this is not the correct terminology).

Mode 2 pixels are interleaved as follows:
Mode2Pixels.PNG
(3.97 KiB) Not downloaded yet


I am trying to calculate colours for both pixels on the fly with assembly and I'm sure I've see code around somewhere but cannot find it right now... my routine starts off with colour 1 (red), performs some drawing, then I need to increment the colour to 2 (green) do more drawing, then continue to increment and drawing up to colour 7 (white).

The decimal sequence for the left and right bits looks like this and I don't full understand how to get the increment working properly:
Mode2Pixels2.PNG


Once I've got the two values I can join them easily enough... I've thought about using a small table look up but just want to know if there's a quick way to get the interleaved pixel colour values quickly from the equivalent 0-7 colour values? And in reverse I guess?

Hope this makes sense :?

User avatar
simonm
Posts: 164
Joined: Mon May 09, 2016 2:40 pm
Contact:

Re: Mode 2 Graphics

Postby simonm » Wed Jan 18, 2017 10:44 am

Yes, a table makes perfect sense for this.
Maybe even two - one lookup table for converting a colour index to left hand pixel data and one for converting a colour index to the right hand pixel data.
Store your pre-calculated interleaved pixel data in the tables, and index into them with your colour id in X or Y

You could write some bit shift code to unpack a colour index to screen data, but a table will be faster/easier to code in this case.

User avatar
FourthStone
Posts: 387
Joined: Thu Nov 17, 2016 2:29 am
Location: Melbourne, Australia

Re: Mode 2 Graphics

Postby FourthStone » Wed Jan 18, 2017 11:12 am

Thanks for the reply, I ended up trying the table and it seems to work for what I needed. Good to know I wasn't missing an obvious opcode or simpler method.

The table contains 8 values for the right pixel colour data and the left side is decoded with an ASL (don't care about the top 2 bits for now), I do this in a pre-loop configuration phase and save the required left and right pixel data for two colours in ZP. Then the two colours can be combined in any order or with a border colour... there's probably a cleaner way to do it, e.g. a full 16 colour table wouldn't take much ram, but it is working for now and it's super fast, I'll post up the code for optimisation idea's when it's done.

Cheers again :D

User avatar
tricky
Posts: 1823
Joined: Tue Jun 21, 2011 8:25 am
Contact:

Re: Mode 2 Graphics

Postby tricky » Wed Jan 18, 2017 1:01 pm

I think for the fastest possible solution, you need two tables, each with 256 entries. The first table would have at index N, the colour for the incremented first colour ORed with the original second colour. The second table would be the same, but the other way around.
If I have misunderstood, then just a 128 entry table with the 16 possible colour value entries filled in, with each having the value for the next colour. For the left colour, you can do what you do now and lsr, do the lookup and then asl.
EDIT: probably the smallest colour to index code would be:

Code: Select all

; A is left pixel, (pixel AND &AA) or right pixel (ASL A : AND #&AA)
ASL A : ROL &70 ; &70 is just a temp location, preferably in zero page
ASL A : ASL A : ROL &70
ASL A : ASL A : ROL &70
ASL A : ASL A
LDA &70 : ROL A : AND #&0F ; A is now colour index

User avatar
FourthStone
Posts: 387
Joined: Thu Nov 17, 2016 2:29 am
Location: Melbourne, Australia

Re: Mode 2 Graphics

Postby FourthStone » Wed Jan 18, 2017 9:41 pm

This is what I have so far, the loop repeats 7 times and it determines two starting colours. The first colour parsed as A% is static, the second colour is indexed with the loop and starts at 0 unless the first colour is 0 to which the secondary colour is set to 1. At this point the code looks up the colour pixel data for C1 and C2 and stores the data in ZP as both left and right. So far so good.

The code can combine the colours with an ORA in either combination e.g. C1C2 or C2C1 or C2C2 and also combined with a border colour which is fixed so I don't calculate the border pixel colour data up front.

The only thing I am not so happy with at the moment is the amount of code I am using to draw the menu as the code is a big unrolled loop... the reason for this is that I am drawing 8 different patterns as part of a palette selection menu and the depending on the starting colour there are literally hundreds of possible pattern/colours to draw.

The menu code (which is only 1/4 of what I need) is taking up so much ram I can't fit the rest of the drawing program in memory, what a pickle... I was thinking I could compile the code and store it in sideways ram as I have about 2k available after using up the rest for other functions and also when saving the screen data to draw the menu I am already switching in that bank of sideways ram. Or maybe I can compile and store lower in ram but not sure where... still working it all out.

Code: Select all

  220   .cols: EQUB &00:EQUB &01:EQUB &04:EQUB &05:EQUB &10:EQUB &11:EQUB &14:EQUB &15
  230   .drawmenu
  240   LDY#0:STA ci1:TAX:LDA cols,x:STA rom1:ASL A:STA rom3:BNE colok1:LDY#1:.colok1:STY ci2:LDA cols,Y:STA rom2:ASL A:STA rom4:LDA#&50:STA dst:LDA#&30:STA dst+1:LDA#&D0:STA src:LDA#&32:STA src+1:LDX#7:STX patc
  250   .pat1r1:LDY#3:LDA#63:STA (dst),Y:INY:LDA#42:ORA rom2:STA (dst),Y:INY:STA (dst),Y:INY:STA (dst),Y:INY:STA (dst),Y
  260   LDY#0:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:LDA#63:STA (src),Y
  270   LDA dst:CLC:ADC#8:STA dst:LDA dst+1:ADC#0:STA dst+1:LDA src:CLC:ADC#8:STA src:LDA src+1:ADC#0:STA src+1:LDX#2
  280   .pat1r2:LDY#3:LDA#63:STA (dst),Y:INY:LDA rom3:ORA rom2:STA (dst),Y:INY:LDA rom2:ORA rom4:STA (dst),Y:INY:STA (dst),Y:INY:STA (dst),Y
  290   LDY#0:LDA rom3:ORA rom2:STA (src),Y:INY:LDA rom2:ORA rom4:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:LDA rom3:ORA rom2:STA (src),Y:INY:LDA rom2:ORA rom4:STA (src),Y:INY:LDA#63:STA (src),Y
  300   LDA dst:CLC:ADC#8:STA dst:LDA dst+1:ADC#0:STA dst+1:LDA src:CLC:ADC#8:STA src:LDA src+1:ADC#0:STA src+1:DEX:BNE pat1r2
  340   .pat1r4:LDY#3:LDA#42:STA (dst),Y:INY:STA (dst),Y:INY:STA (dst),Y:INY:STA (dst),Y:INY:STA (dst),Y
  348   LDY#0:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y
  349   LDA dst:CLC:ADC#8:STA dst:LDA dst+1:ADC#0:STA dst+1:LDA src:CLC:ADC#8:STA src:LDA src+1:ADC#0:STA src+1 
  351   .pat1r5:LDY#3:LDA#63:STA (dst),Y:INY:LDA#42:ORA rom2:STA (dst),Y:INY:STA (dst),Y:INY:STA (dst),Y:INY:STA (dst),Y
  352   LDY#0:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:LDA#63:STA (src),Y
  353   LDA dst:CLC:ADC#8:STA dst:LDA dst+1:ADC#0:STA dst+1:LDA src:CLC:ADC#8:STA src:LDA src+1:ADC#0:STA src+1:LDX#2
  354   .pat1r6:LDY#3:LDA#63:STA (dst),Y:INY:LDA rom3:ORA rom2:STA (dst),Y:INY:INY:STA (dst),Y:INY:LDA rom2:ORA rom4:STA (dst),Y:DEY:DEY:STA (dst),Y
  355   LDY#0:LDA rom3:ORA rom2:STA (src),Y:INY:INY:STA (src),Y:INY:INY:STA (src),Y:INY:INY:LDA#63:STA (src),Y:DEY:LDA rom2:ORA rom4:STA (src),Y:DEY:DEY:STA (src),Y:DEY:DEY:STA (src),Y
  356   LDA dst:CLC:ADC#8:STA dst:LDA dst+1:ADC#0:STA dst+1:LDA src:CLC:ADC#8:STA src:LDA src+1:ADC#0:STA src+1:DEX:BNE pat1r6
  360   .pat1r8:LDY#3:LDA#42:STA (dst),Y:INY:STA (dst),Y:INY:STA (dst),Y:INY:STA (dst),Y:INY:STA (dst),Y
  361   LDY#0:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y:INY:STA (src),Y 
  362   LDX patc:DEX:BEQ donemenu:STX patc
  370   LDA dst:CLC:ADC#8:STA dst:LDA dst+1:ADC#0:STA dst+1:LDA src:CLC:ADC#&8:STA src:LDA src+1:ADC#0:STA src+1
  380   LDY ci2:INY:CPY ci1:BNE colok3:INY:.colok3:STY ci2:LDA cols,Y:STA rom2:ASL A:STA rom4:JMP pat1r1
  390   .donemenu
  400   RTS


Art03.png

SteveF
Posts: 429
Joined: Fri Aug 28, 2015 8:34 pm

Re: Mode 2 Graphics

Postby SteveF » Wed Jan 18, 2017 10:51 pm

FourthStone wrote:The menu code (which is only 1/4 of what I need) is taking up so much ram I can't fit the rest of the drawing program in memory, what a pickle... I was thinking I could compile the code and store it in sideways ram as I have about 2k available after using up the rest for other functions and also when saving the screen data to draw the menu I am already switching in that bank of sideways ram. Or maybe I can compile and store lower in ram but not sure where... still working it all out.


Looking good so far anyway!

A few thoughts which may or may not help here:
  • Since you're targetting the Master, could you use shadow mode 2 to free up some main RAM for your program? The sideways RAM screen save/restore code should cope with this fine, and you can use the same technique (the OSBYTE calls to make the shadow RAM accessible to direct memory reads/writes) when you start updating the screen memory directly. However, you need to be sure that the machine code which pages in the shadow RAM instead of main RAM is located below &3000 (or above &8000), otherwise it will crash when it pages in the shadow RAM. If you're allocating memory with DIM code% 256, that memory will come after the end of the BASIC program and if the program's big enough to need shadow RAM, that memory will be above &3000. So you'd probably need to locate the machine code either in sideways RAM, or somewhere low in memory like &900.
  • If you have a fixed location for the machine code - let's say &900 for the sake of argument - you can assemble it and *SAVE it in advance, then just *LOAD it in in the main program. This saves a lot of RAM as you don't need to have the source code in memory at the same time as the program which uses the machine code. (As a variant on this, you can have a loader which assembles the code at &900 then CHAINs the main program. *SAVE then *LOAD will be slightly faster, but having the loader do the assembly might be more convenient while you're developing.)
  • You can probably get away with using &900-&AFF for machine code, but that might not be enough. You could instead/also assemble it to run at &E00, and raise PAGE so the BASIC programs starts above it. (Perhaps !BOOT does PAGE=&1100:CHAIN "LOADER", then LOADER assembles the code at &E00-&10FF, then CHAINs "MAINPROG".) However, if you've got some sideways RAM free (and you have banks 6 and 7 completely unused, IIRC, never mind the 2K free in one of banks 4/5) that might well be best.
  • If (and I suspect this isn't the case) all your menus are identical patterns but different colours, you could draw the menu just once in a loader and save it in sideways RAM, then when you want to display it swap the screen RAM with the relevant sideways RAM and adjust the menu colours to the appropriate ones.

User avatar
FourthStone
Posts: 387
Joined: Thu Nov 17, 2016 2:29 am
Location: Melbourne, Australia

Re: Mode 2 Graphics

Postby FourthStone » Wed Jan 18, 2017 11:23 pm

Thanks Steve, I find it so helpful to share these discussions with others as I usually pick up the bits I need to move forward :D

I'm using shadow ram for the undo function so that takes that out of the picture for now. You're right though about using another bank as so far I am only using banks 4 and 5 for the undo and menu buffers. So 20k undo plus 10k menu buffers leaving 2k for code...I could use another bank if the program grows (and grows!) I think I should be able to get it all in 2k but then again, I might move a lot of the drawing functions into asm as well... hehe lofty goals, but interesting project and loving doing asm again. Once it's drawn I can flip back to basic to do the mouse and screen updates, it's only the drawing of the colour patterns that I'm trying to speed up.

I think you've nailed it with the compile and load approach, once I compile and remove the asm listing from the main program I think I will have enough ram left for the rest of the basic functions. Of if not I can move it lower into somewhere not required for the app to function.

If (and I suspect this isn't the case) all your menus are identical patterns but different colours, you could draw the menu just once in a loader and save it in sideways RAM, then when you want to display it swap the screen RAM with the relevant sideways RAM and adjust the menu colours to the appropriate ones.


I tried working with this approach but I wasn't sure how I could swap the colours without corrupting the rest of the picture which is still visible below the menu.

Thanks again, I've got some idea's to work with and I'll see if I can get the rest of the menu drawn and compiled to test with *LOAD from the main app.

User avatar
tricky
Posts: 1823
Joined: Tue Jun 21, 2011 8:25 am
Contact:

Re: Mode 2 Graphics

Postby tricky » Wed Jan 18, 2017 11:27 pm

N.B. I have just remembered that you are using a master, this is for a Model B, and will need changing (*640 table seems to be missing on master, or not pointed to by (&E0),Y*2). Give it a try in BBC mode and see what you think of the lag.

I've been playing with a kind of mouse cursor, but I'm not sure quite where I am going!
The code below and on the attached disc adds an interrupt handler and EORs the colour of the pixel at the cursor with 15.
The code is rather rude and assumes it can have &70..&79 and &C00..&CFF inclusive.
The code currently checks for changes in ADVAL(1), ADVAL(2) and the buttons in ADVAL(0). When it finds a change, it adds the new values to a small internal buffer and moves the "cursor" (pixel). The idea was that you would be able to pull the values from the buffer (currently 15 sets of values) and store them in a larger app side queue, whilst the cursor would have minimal lag and the app could catch up when the mouse stopped.
I haven't implemented retrieving the values, so all you get is a moving single pixel cursor.
You would also need to CALL disable_crsr, then draw, then CALL enable_cursor again (capturing would continue) to avoid corrupting the picture.
Once init has been called, you don't need the rest of the code, so you could do something like:

Code: Select all

CHAIN "MOUSE"
E% = enable_cursor
D% = disable_cursor
NEW
CHAIN "ART"
And the only memory you would lose would be the addresses listed above, which I don't think should affect your program (haven't checked which addresses you are using, but you could move my variables around).

Code: Select all

   10MODE 2
   20D% = &C00
   30crsr_enable = &70
   40buffer_next = &71
   50buffer_last = &72
   60adval0      = &73
   70adval1      = &74
   80adval2      = &76
   90crsr_addr   = &78
  100FOR A% = 0 TO 2 STEP 2
  110P% = D%
  120[OPT A%
  130.interrupt
  140  PHP
  150  CMP #4 : BNE no_change
  160  LDA &FE4B : EOR adval0 : AND #&30 : BNE moved
  170  LDA &2B6 :  : SBC adval1 : LDA &2BA : SBC adval1+1 : BEQ same1 : EOR #&FF : BNE moved : .same1
  180  LDA &2B7 : SEC : SBC adval2 : LDA &2BB : SBC adval2+1 : BEQ no_change : EOR #&FF : BEQ no_change
  190.moved
  200  TXA : PHA
  210  LDA crsr_enable : BEQ no_undraw : JSR eor_crsr : .no_undraw
  220  LDX buffer_next : INX : INX : INX : BNE no_wrap : LDX #(init - D%) : .no_wrap : STX buffer_next
  230  LDA &2B6 : STA adval1 : LDA &2BA : STA adval1+1 : LSR A : LSR A : SEC : ADC adval1+1 : ROR A : EOR #&FF : SEC : ADC #159 : STA D%+0,X ; XXXXXXXX 0..159
  240  LDA &2B7 : STA adval2 : LDA &2BB : STA adval2+1                                              : EOR #&FF                  : STA D%+1,X ; YYYYYYYY 0..255
  250  LDA &FE4B : AND #&30 : STA adval0                                                                                        : STA D%+2,X ; 00BB0000
  260  LDA crsr_enable : BEQ no_draw : JSR eor_crsr : .no_draw
  270  PLA : TAX
  280.no_change
  290  LDA #4
  300  PLP
  310.continue
  320  JMP &220
  330.enable_crsr
  340  LDA crsr_enable : BNE done : INC crsr_enable : BNE eor_crsr
  350.disable_crsr
  360  LDA crsr_enable : BEQ done : DEC crsr_enable
  370.eor_crsr
  380  TYA : PHA
  390  LDX buffer_next
  400  LDA D%+0,X : AND #1 : PHA : EOR D%+0,X : ASL A : STA crsr_addr : LDA #&30 / 4 : ROL A : ASL crsr_addr : ROL A : STA crsr_addr+1
  410  LDA D%+1,X : LSR A : LSR A : ORA #&01 : TAY : LDA (&E0),Y : CLC : ADC crsr_addr : STA crsr_addr : DEY : LDA (&E0),Y : ADC crsr_addr+1 : STA crsr_addr+1
  420  LDA D%+1,X : AND #7 : TAY : PLA : TAX : LDA &362,X : EOR (crsr_addr),Y : STA (crsr_addr),Y
  430  PLA : TAY
  440.done
  450  RTS
  460]
  470  IF (256 - (P% AND &FF)) MOD 3 <> 0 P% = P% + 1
  480  IF (256 - (P% AND &FF)) MOD 3 <> 0 P% = P% + 1
  490[OPT A%
  500.init
  510  LDA #(init - D%) : STA buffer_next : STA buffer_last
  520  SEI
  530  LDA &220 : STA continue+1
  540  LDA &221 : STA continue+2
  550  LDA #interrupt MOD 256 : STA &220
  560  LDA #interrupt DIV 256 : STA &221
  570  CLI
  580  RTS
  590]
  600NEXT A%
  610PRINT "Code ";~D%;"..";~(done+1)
  620PRINT "Buffering ";(256-(init AND &FF))/3;" points"
  630*FX 16 2
  640CALL init
  650*FX 14 4
  660CALL enable_crsr
Attachments
mouse.zip
BBC version, *640 table seems to be missing on master!
(1.19 KiB) Downloaded 12 times

User avatar
tricky
Posts: 1823
Joined: Tue Jun 21, 2011 8:25 am
Contact:

Re: Mode 2 Graphics

Postby tricky » Wed Jan 18, 2017 11:40 pm

You could use a similar approach to the one I described with assembling and then NEW and CHAIN to get your menu code loaded.
I think the polite way might be to move PAGE up and then assemble under it, so that you can NEW (may need to reset PAGE again) and CHAIN the next bit - I should probably do that above rather than stealing the user defined character set buffer. This is the sort of thing that I haven't looked at for 30 years and why I just steal everything ;)
For the final version, move PAGE and then *LOAD the menu and any other ASM bits.

User avatar
FourthStone
Posts: 387
Joined: Thu Nov 17, 2016 2:29 am
Location: Melbourne, Australia

Re: Mode 2 Graphics

Postby FourthStone » Thu Jan 19, 2017 12:22 am

This is really great! :D Nice and smooth, hardly any lag, very impressive :mrgreen:

Every time I read some of your code I pick up something new, I didn't know there is a *640 table stored at &E0 on model b :shock: ??

I've got a few VDU chars for custom fonts so I might have to shift if somewhere else, although that's one of the things I love about the beeb, I can just do it in another way if need be :o

I tried reading &73 while clicking all the mouse buttons but nothing is changing, is this the right address for checking button clicks?

I'm thinking the pointer could just be a simple cross hair, the center needs to be the current mouse addr, the arms of the pointer need to be clipped for screen bounds... this might add a bit of code but not too much hopefully. Now you've written the core of the driver and calc routine I will have a play with it to see if I can add the cursor part.

Now I'm going to see if I can work out how you did the math =D>

User avatar
tricky
Posts: 1823
Joined: Tue Jun 21, 2011 8:25 am
Contact:

Re: Mode 2 Graphics

Postby tricky » Thu Jan 19, 2017 7:55 am

It was all a bit of a quick hack last night.
The curious way of seeing if the position has changed is to stop noise in the ADC causing the cursor to jump around.
I only store the crsr position in pixels and was going to multiply by 8x and 4y to return the position in a plot friendly way. The idea was to call an unwritten function to return if there was any unread data and expand it into X%, Y% and B% if there was. This would compare buffer_next (write offset from interrupt to buffer_last (read). If they are the same, no data, otherwise last+=3, wrapped as next and expand out the data.
I suspect the *640 table is still around, I've never used it before, and it is probably about the same amount of code as *2 + *1/2 with masks.

SteveF
Posts: 429
Joined: Fri Aug 28, 2015 8:34 pm

Re: Mode 2 Graphics

Postby SteveF » Thu Jan 19, 2017 8:11 pm

tricky wrote:The curious way of seeing if the position has changed is to stop noise in the ADC causing the cursor to jump around.


This might not be strictly necessary here, as I think the program is designed for use with BeebEm's "analogue mousestick" and I'd guess (I haven't checked) that since it's not real hardware, there isn't actually any noise. Then again, it's probably good to keep options open for alternative input devices in the future anyway.

User avatar
tricky
Posts: 1823
Joined: Tue Jun 21, 2011 8:25 am
Contact:

Re: Mode 2 Graphics

Postby tricky » Thu Jan 19, 2017 10:35 pm

Using an emulator was another thing that I had forgot when writing it!
Here is a tweaked version (probably my last) with the *640 done in code and with the function added for retrieving the new position if there is one.
With the init code, this version overruns the NMI code, so is more than just rude!

Code: Select all

   20 MODE 2
   30 D% = &C00
   40 crsr_enable = &70
   50 buffer_next = &71
   60 buffer_last = &72
   70 adval0      = &73
   80 adval1      = &74
   90 adval2      = &76
  100 crsr_addr   = &78
  110 FOR A% = 0 TO 2 STEP 2
  120 P% = D%
  130 [OPT A%
  140 .interrupt
  150   PHP
  160   CMP #4 : BNE no_change
  170   LDA &FE40 : AND #&30 : CMP adval0 : STA adval0 : BNE moved
  180   LDA &2B6 : SBC adval1 : LDA &2BA : SBC adval1+1 : BEQ same1 : EOR #&FF : BNE moved : .same1
  190   LDA &2B7 : SEC : SBC adval2 : LDA &2BB : SBC adval2+1 : BEQ no_change : EOR #&FF : BEQ no_change
  200 .moved
  210   TXA : PHA
  220   LDA crsr_enable : BEQ no_undraw : JSR eor_crsr : .no_undraw
  230   LDX buffer_next : JSR advance_x : STX buffer_next
  240   LDA &2B6 : STA adval1 : LDA &2BA : STA adval1+1 : LSR A : LSR A : SEC : ADC adval1+1 : ROR A : EOR #&FF : SEC : ADC #159 : STA D%+0,X ; XXXXXXXX 0..159
  250   LDA &2B7 : STA adval2 : LDA &2BB : STA adval2+1                                              : EOR #&FF                  : STA D%+1,X ; YYYYYYYY 0..255
  260   LDA adval0                                                                                                               : STA D%+2,X ; 00BB0000
  270   LDA crsr_enable : BEQ no_draw : JSR eor_crsr : .no_draw
  280   PLA : TAX
  290 .no_change
  300   LDA #4
  310   PLP
  320 .continue
  330   JMP &220
  340 .enable_crsr
  350   LDA crsr_enable : BNE done : INC crsr_enable : BNE eor_crsr
  360 .disable_crsr
  370   LDA crsr_enable : BEQ done : DEC crsr_enable
  380 .eor_crsr
  390   TYA : PHA
  400   LDX buffer_next
  410   LDA D%+1,X : AND #&F8 : LSR A : STA crsr_addr+1 : LSR A : LSR A : ADC crsr_addr+1 : ADC #&30*2 : LSR A : STA crsr_addr+1 : PHP
  420   LDA D%+0,X : AND #&FE : ASL A : ROL crsr_addr : ASL A : ROL crsr_addr
  430   PLP : BCC even_line : ADC #127 : .even_line : PHA : LDA crsr_addr : AND #3 : ADC crsr_addr+1 : STA crsr_addr+1 : PLA : STA crsr_addr
  440   LDA D%+1,X : AND #7 : TAY : LDA D%+0,X : LSR A : LDA #&AA : BCC lh_pixel : LSR A : .lh_pixel : EOR (crsr_addr),Y : STA (crsr_addr),Y
  450   PLA : TAY
  460 .done
  470   RTS
  480 .read_mouse
  490   LDX buffer_last : CPX buffer_next : BEQ done : JSR advance_x : STX buffer_last
  500   LDA D%+1,X : EOR #&FF : TAY
  510   LDA D%+2,X : PHA
  520   LDA D%+0,X : TAX : PLA : CLC : RTS
  530 .advance_x
  540   INX : INX : INX : BNE no_wrap : LDX #(init - D%) : .no_wrap : RTS
  550 ]
  560   IF (256 - (P% AND &FF)) MOD 3 <> 0 P% = P% + 1
  570   IF (256 - (P% AND &FF)) MOD 3 <> 0 P% = P% + 1
  580 [OPT A%
  590 .init
  600   LDA #(init - D%) : STA buffer_next : STA buffer_last
  610   SEI
  620   LDA &220 : STA continue+1
  630   LDA &221 : STA continue+2
  640   LDA #interrupt MOD 256 : STA &220
  650   LDA #interrupt DIV 256 : STA &221
  660   CLI
  670   RTS
  680 ]
  690 NEXT A%
  700 PRINT "Code ";~D%;"..";~(no_wrap+1)
  710 PRINT "init ";~init;"..";~(P%-1)
  720 PRINT "Buffering ";(256-(init AND &FF))/3;" points"
  730 *FX 16 2
  740 CALL init
  750 *FX 14 4
  760 CALL enable_crsr
  770 REPEAT
  780 U%=USR(read_mouse)
  790 IF 0=(U% AND &1000000) PRINTTAB(0,4);"X ";(U% AND &FF00)*8DIV&100;" Y ";(U% AND &FF0000)*4DIV&10000;" B ";(U% AND &30)DIV&10;"     "
  800 UNTIL FALSE

Copy and paste in to beebem or use the attached .ssd, should work on beeb or master.
The loop at the end checks for data and if there was any IF 0=(U% AND &1000000), displays it.
There was mention of the right and centre mouse buttons, but beebem only supports left and the beeb only has two on the joystick port.
With a bit of hacking, beebem should be able to hook the mouse wheel up to ADVAL(3) and possibly the middle mouse button to ADVAL(4); if you do this, all the ADC reads would need to by 8bit to fit into a frame, instead of the 2 current ones taking a whole frame (or you have doubled the lag).
The code only needs 1 page after init has been called and could go in any page really, whatever space is left in the page after .init is used for position and button recording.
Attachments
mouse.zip
(1.41 KiB) Downloaded 10 times


Return to “programming”

Who is online

Users browsing this forum: No registered users and 1 guest