Managing X and Y coords in memory best practice

All aspects of programming on the Commander X16.
Post Reply
cosmicr
Posts: 35
Joined: Tue Nov 14, 2023 4:29 am

Question Managing X and Y coords in memory best practice

Post by cosmicr »

Go easy on me, I'm still learning 65c02 assembly. Okay, so the default screen res with no scaling is 640x480.

You can scale the screen by using the formula

Code: Select all

scale = 128*res / 640
I have been using the common resolution of 320x240x16 colours.

This means that the X values are an array of 320 4-bit values (160 bytes) and the Y is an array of 240 values.

So what is the best practice for storing the X and Y coordinates? It would need 17 bits, (9 for the X, 8 for the Y). I have been using 3 bytes, but it's incredibly annoying to have to do 16-bit maths on the X value every time there is an operation.

It would be great if there was some kind of bit-packing technique or clever shifting trick to allow for using only 2 bytes.

As an example, 8086 (16-bit) assembly has a 20-bit memory address register that only uses 3 bytes (rather than 4), since the high 4 bits set the segment, and the lower 16-bits set the offset. Only a couple of shifting operations needed.

It's obviously not the same, but it would be good to know if someone has already looked at this problem.

Some of the options I have thought of are:
- Reduce the precision of X, to use only 8 bits.
- Reduce the precision of Y, to use 7 bits
- Create two types of "drawing" functions, one where you know X will be less than 256, and another where it will be higher. I think a few older games did this.
- one subroutine, but have it "decide" if X>256 before continuing at the expense of a tiny bit of performance.
- segment the screen into two areas?

Or am I going about this the wrong way altogether?
TomXP411
Posts: 1785
Joined: Tue May 19, 2020 8:49 pm

Re: Managing X and Y coords in memory best practice

Post by TomXP411 »

This is what macros are for. Just do the work once, then use a macro when you need to repeat it.

So something like

add16: CLC LDA #addend ADC x_coord; add value to low byte of x_coord BCC add16_done inc x_coord+1 ; stash the carry in the high byte of x_coord add16_done:

becomes something like

add16 .macro result, addend CLC LDA #addend ADC result; add value to low byte of x_coord BCC add16_done inc result+1; stash the carry in the high byte of x_coord add16_done: .endmacro

and then you just use it later in your code like
#add16 x_coord, 2

(this is the tass64 syntax. It may be different in other compilers.)

And if you just need to increment a value, it's even simpler:
inc x_coord bne inc16_done inc x_coord+1 inc16_done:
cosmicr
Posts: 35
Joined: Tue Nov 14, 2023 4:29 am

Re: Managing X and Y coords in memory best practice

Post by cosmicr »

Thanks for the reply - unfortunately that's not what I was after, I'm already familiar with macros - in fact they're kind of counterproductive to what I want to achieve.

Sorry I wasn't clear enough. I'm looking for a way to optimise and reduce the amount of memory used, rather than make it easier to code - ie use only 2 bytes for X and Y coordinates. What is the best method for this? Are any of my ideas sound? I presume this is a common problem that has already been solved.
TomXP411
Posts: 1785
Joined: Tue May 19, 2020 8:49 pm

Re: Managing X and Y coords in memory best practice

Post by TomXP411 »

The answer is: there is not some kind of bit-packing technique or clever shifting trick to allow for using only 2 bytes. You just have to do the math. Any method of packing (x,y) into a 16-bit value is more complicated than a simple 16 bit add.

If you're just trying to save space, then pack the high bit of 8 X values into a single packed byte.

That basically involves using ROR to get the high bit of X into the Carry flag, then ROL to get it into your pack byte, something like...

CLC
ROR X+1 ;get bit 0 of the high byte of X into the Carry flag
ROL pack_byte ; push the carry bit back in to the pack byte

However, there's no method of packing (320,240) into 2 bytes that isn't hideously more complex than simple 16 bit adds, especially when the high bit if your X coordinate is only 0 or 1.
DragWx
Posts: 345
Joined: Tue Mar 07, 2023 9:07 pm

Re: Managing X and Y coords in memory best practice

Post by DragWx »

Instead of trying to eliminate your X position's 9th bit, try finding a way to repurpose the 7 unused bits of your MSB. For example, if you need flags to store which direction your actor is facing, that's a good place to store them.

Otherwise, if you really want to make your X position 8 bits, you could reduce the size of your playfield to 256x240. On TVs, some of the 320x240 is lost to overscan anyway.
Ed Minchau
Posts: 503
Joined: Sat Jul 11, 2020 3:30 pm

Re: Managing X and Y coords in memory best practice

Post by Ed Minchau »

If you do as DragWx suggests, that's an HSCALE value of $33 to get 256 pixels across the screen. Actually only 255 would be shown, but this means your tile map would only need to be 32 tiles wide.

Otherwise I would just use the 8 most significant bits of the X value. Suppose the high byte is in A and the low byte in X:

LSR A
TXA
ROR A

This puts the 8 most significant bits in A.
kelli217
Posts: 535
Joined: Sun Jul 05, 2020 11:27 pm

Re: Managing X and Y coords in memory best practice

Post by kelli217 »

I think it might be better to use HSTART and HSTOP for the reduction...
cosmicr
Posts: 35
Joined: Tue Nov 14, 2023 4:29 am

Re: Managing X and Y coords in memory best practice

Post by cosmicr »

DragWx wrote: Tue Jan 09, 2024 6:20 pm Instead of trying to eliminate your X position's 9th bit, try finding a way to repurpose the 7 unused bits of your MSB. For example, if you need flags to store which direction your actor is facing, that's a good place to store them.
Thanks that's a good idea - I have a plot pixel macro, I could put the colour in the upper 7 bits (although that would be at the expense of a few extra cycles, so it's a balancing act). I'll have to think about it.

I've been looking at some older source code for VGA MS-DOS games, it looks like most don't worry about using a 16 bit int for the X coordinate. I guess that's because it was at least a 16-bit cpu then.
maikaione
Posts: 2
Joined: Wed Jan 17, 2024 3:50 pm

Re: Managing X and Y coords in memory best practice

Post by maikaione »

I'm not at a computer I can test this on, but here's an idea. Although it seems like a lot of work/cpu time to save 7 bits.

If you imposed a constraint where the x-coord could only increase or decrease by 2 at a time and assume the LSB is always 0, you can free up a bit.

if the true X coord is $0B6 (0000 1011 0110), you could store it as $5B (0101 1011).
If the True coord were 302 ($12E, 0001 0010 1110), you'd store it as $97 (1001 0111)

When you go to send the coordinates to the VERA, do something like this:

Code: Select all

; Assuming the true x coordinate is $B6 so we have $5B stored in XCoord

lda #XCoord			; A = 0101 1011
clc				; Clear the Carry Bit
rol				; 0 < 1011 0110 -- A = $B6
sta $9F23			; Store that in the VERA Data port

lda #0				;lda #0 (Carry flag will still be clear from rol)
bcc :+				; so follow the branch
lda #1				; skip this
:
sta $9F23			; store the next byte of x coord data in the Vera data port. (0 in this case)


and with the other example:

Code: Select all

; Assuming the true x coordinate is $12E so we have $97 stored in XCoord

lda #XCoord			; A = 1001 0111
clc				; Clear the Carry Bit
rol				; 1 < 0010 1110 -- A = $2E
sta $9F23			; Store that in the VERA Data port

lda #0				;lda #0 (Carry flag will still set from the rol)
bcc :+				; so don't branch
lda #1				; load 1 into a
:
sta $9F23			; store the next byte of x coord data in the Vera data port.   (1 in this case)

Last edited by maikaione on Wed Jan 17, 2024 9:49 pm, edited 1 time in total.
Post Reply