Page 1 of 1
Managing X and Y coords in memory best practice
Posted: Mon Jan 08, 2024 1:54 am
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
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?
Re: Managing X and Y coords in memory best practice
Posted: Mon Jan 08, 2024 6:47 am
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:
Re: Managing X and Y coords in memory best practice
Posted: Mon Jan 08, 2024 11:55 pm
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.
Re: Managing X and Y coords in memory best practice
Posted: Tue Jan 09, 2024 5:48 pm
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.
Re: Managing X and Y coords in memory best practice
Posted: Tue Jan 09, 2024 6:20 pm
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.
Re: Managing X and Y coords in memory best practice
Posted: Tue Jan 09, 2024 7:22 pm
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.
Re: Managing X and Y coords in memory best practice
Posted: Wed Jan 10, 2024 2:56 am
by kelli217
I think it might be better to use HSTART and HSTOP for the reduction...
Re: Managing X and Y coords in memory best practice
Posted: Thu Jan 11, 2024 2:48 am
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.
Re: Managing X and Y coords in memory best practice
Posted: Wed Jan 17, 2024 9:43 pm
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)