GAMELEGEND 2023-02-23 21:54 (Edited)
I have been learning about drawing one pixel to the screen, so I made a test program where you use the gamepad to move a white pixel around character #1, and I was wondering if there was any way to improve this program.
McPepic 2023-02-24 00:34
So I was messing around with modifying bits and I made this:
GAMELEGEND 2023-02-24 01:13 (Edited)
Well I found out how the square made out of different cells work.
GAMELEGEND 2023-02-24 01:31 (Edited)
@McPepic How do you get the program skip over the last 2 addresses of a character?
McPepic 2023-02-24 01:58
Why the last 2 addresses specifically? That only controls the high bit for the last 2 rows of the character.
GAMELEGEND 2023-02-24 02:14 (Edited)
I meant to type 8.
The pixel stays white so that means that it skips the last 8 addresses, correct? unless I screwed up my test programs
McPepic 2023-02-24 02:23
If you looked at the subprogram I made, you can set the color. Since the color is a 2 bit value (0 to 3), you can just have the color be 1 (if that color maps to white in the palette of the current cell).
nathanielbabiak 2023-02-25 04:10 (Edited)
I find it a bit cumbersome to "convert between units". In your upload, the units would be (x,y) coordinates, and you want to convert that to a memory address.
This was the first upload to pre-calculate that specific conversion. Your upload will obviously need to use your algorithm to calculate the addresses, but the idea is the same: just make a global 2D array.
This idea - by itself - won't really effect your code.
BUT, BUT... BUT! This idea will simplify the algorithmic coordinate-->address so much that you'll be able to work much more comfortably with the surrounding code. It'll let you "focus on other things", so to speak. (And, it's much faster and will use fewer tokens, another benefit.) Just make sure to initialization the global 2D array before you use it.
Personally, I use the above idea often. I like to pretend that I have an array that "magically" converts what I need. Then I can focus on how I'd use that array (or even how its inputs/outputs might need to change, based on focusing). Writing the conversion algorithms is typically time consuming, so I leave it for last (because the specific inputs/outputs might change).
nathanielbabiak 2023-02-25 04:17 (Edited)
As far as extending your upload, maybe try adding a global variable
CURR_COLOR, which tracks the user's desired draw-color?
GLOBAL CURR_COLOR CURR_COLOR=2
In the main loop, try:
IF BUTTON TAP(0,0) THEN CURR_COLOR=CURR_COLOR XOR 1 IF BUTTON TAP(0,1) THEN CURR_COLOR=CURR_COLOR XOR 2
So now the question is, how should the pixel-drawing algorithm be modified to check CURR_COLOR? (...McPepic's upload in this thread seems to have this capability...)
GAMELEGEND 2023-02-25 05:11
Wow now this some interesting stuff.
GAMELEGEND 2023-03-01 21:13 (Edited)
After I was done experimenting with that Starfield program, I created this.
This stuff is not as confusing to me as I thought it would be actually, I only got confused 2 or 3 times.
nathanielbabiak 2023-03-02 02:48
Yeah Rilden's character pattern makes the addressing scheme super simple. Honestly if you only need 2 colors (rather than 4) it's probably best to use it.
GAMELEGEND 2023-03-02 04:37
What do you do if you need 4 colors?
GAMELEGEND 2023-03-02 23:12 (Edited)
So I used Bresenham's algorithm; Well I think I did it's been a while since I looked at it, and Bresenham's algorithm draws lines SO fast, but is there a way to speed it up even more?
nathanielbabiak 2023-03-03 03:59 (Edited)
If you need 4 colors, please see this reference I just posted. Feel free to comment on either forum post if you've got questions.
nathanielbabiak 2023-03-03 04:12 (Edited)
As far as line drawing, do you want to make one of your own "from scratch" (i.e., learn) or do you just want the fastest one that's known for this console?
GAMELEGEND 2023-03-03 04:15 (Edited)
Both especially the first one
I absolutely love learning about this stuff!
nathanielbabiak 2023-03-03 04:31 (Edited)
There's two major modifications to the line-drawing algorithm that we'll want to make to get the fastest possible result on this console. I'll add more in subsequent posts if I think of any, and then my next post will be the fastest-published version yet.
Take advantage of the console's single-clock-cycle cost for floating point operations. This means forget Bresenham and simply plot the line with a DDA
Move as many instructions as possible outside the loop. It's a waste of clock cycles to repeat the same instructions every iteration when you can pre-determine their outcome. Pre-calculate as many values as you can. Thoroughly understand the system's CPU Cycles
GAMELEGEND 2023-03-03 04:33 (Edited)
I did DDA before I did Bresenham and it used less clock cycles, but it did not draw lines as fast but I am going to try it again.
nathanielbabiak 2023-03-03 04:37 (Edited)
This is the "fastest published" code... now that it's published here.
it's hard-coded to toggle the old pixel's state. You'd want to hard-code variations for turning pixels "on" and "off", rather than inserting
IF ... THEN inside any of the loops.
A few notes:
The instructions inside the loop are incredibly simple (fast!) to minimize iterative clock cycles
It starts at the center of the floating-point pixel coordinate, not the corner of the coordinate. (This is shown visually here)
It takes integer arguments, not floats.
SUB P_LINE_XOR( PX1, PY1, PX2, PY2 ) TX1 = PX1 + 0.5 TY1 = PY1 + 0.5 TX2 = PX2 + 0.5 TY2 = PY2 + 0.5 IF ABS( TY2 - TY1 ) < ABS( TX2 - TX1 ) THEN IF TX2 < TX1 THEN SWAP TX1, TX2 SWAP TY1, TY2 END IF SLOPE = ( TY2 - TY1 ) / ( TX2 - TX1 ) FOR TX1 = TX1 TO TX2 POKE P_ADR( TX1, TY1 ), PEEK( P_ADR( TX1, TY1 ) ) XOR P_X2S( TX1 ) ADD TY1, SLOPE NEXT TX1 ELSE IF TY2 - TY1 THEN IF TY2 < TY1 THEN SWAP TX1, TX2 SWAP TY1, TY2 END IF SLOPE = ( TX2 - TX1 ) / ( TY2 - TY1 ) FOR TY1 = TY1 TO TY2 POKE P_ADR( TX1, TY1 ), PEEK( P_ADR( TX1, TY1 ) ) XOR P_X2S( TX1 ) ADD TX1, SLOPE NEXT TY1 ELSE POKE P_ADR( TX1, TY1 ), PEEK( P_ADR( TX1, TY1 ) ) XOR P_X2S( TX1 ) END IF END SUB
GAMELEGEND 2023-03-03 04:46 (Edited)
ELSE IF TY2 - TY1
Oh! I can't believe that I didn't think about that.
I always put an equals sign.
nathanielbabiak 2023-03-03 04:47 (Edited)
Haha! It wasn't meant to be tricky, I honestly wrote it that way as a hint. A few lines below, the slope is calculated. It uses that exact same expression as the denominator, so it needs to be non-zero to avoid a div-by-zero error.
nathanielbabiak 2023-03-03 05:04 (Edited)
I'm really confused by what you wrote. Clock cycles should pretty much correspond to the speed that the line plots. (Rather than one version having less CC and one version plotting lines faster.)
Do you have an copy of the other algorithm you wrote? I can take a peek and maybe figure out where the code's slow.
GAMELEGEND 2023-03-03 05:06
It confused me too.
GAMELEGEND 2023-03-03 05:07
I will have to rewrite the program because I used the same file for both algorithms.
nathanielbabiak 2023-03-03 05:10 (Edited)
Sounds good. Try testing your algorithms with the cycle counter too.
You can even break apart your code into snippets and use it with the cycle counter. It can give a really good, intuitive understanding of how long stuff takes to execute. It can measure much more "finely" than the debug CPU percentage.
GAMELEGEND 2023-03-03 05:14 (Edited)
At first, I thought that I had a WAIT VBL somewhere when doing the DDA algorithm because the difference in line drawing speed was noticeable but there was no WAIT VBL.
I did use the cycle counter for the algorithms.
I love that program
GAMELEGEND 2023-03-03 05:31
well as I was rewriting the code I found the problem(s) and now it draws lines quicker then the other algorithm.
GAMELEGEND 2023-03-03 05:38
If counted correctly then it almost fills the entire screen about 2 seconds faster than the other algorithm!
GAMELEGEND 2023-03-03 05:48 (Edited)
I think that maybe it was drawing lines faster but more time passed between each line because I increased dx and/or dy by 1 if they equaled 0 because I was getting a division by zero error.