Users browsing this thread: 1 Guest(s)
Patch: allowing use of "reserved" palette colors for player characters

#3
Posts: 45
Threads: 4
Thanks Received: 7
Thanks Given: 1
Joined: Jul 2013
Reputation: 4
Status
None
Oops! Sorry about the mistake. I actually gave the wrong location to paste the code. It should be 3100FD. I actually gave the correct address when I pasted the long jump statement from C1, but the wrong one when I told you where to paste the new function. (The reason I got mixed up is that the address I originally gave is actually the start of MY new code, but there is also code duplicated from the original function in C1.)

About how the sprite data is stored. This actually took a long time to figure out. There are useful docs on http://wiki.superfamicom.org/snes/show/HomePage, but even after reading the docs there I was still a bit confused.

(edited this description for clarity, typos regarding bit/byte, &c)

- OK, so, each pixel needs four bits to store its color index. But, those four bits aren't in the same byte.

- Each byte stores basically a "row" of binary / two-color graphics data. 8 pixels long by 1 pixel high.

- A byte for one row is followed immediately by another byte for the same row, but containing the second "bitplane". The bits/pixels in the first byte, with the corresponding bits/pixels in the second byte, can each hold a two-bit color value (four possible colors).

- This repeats for 8 rows, meaning a single 8 x 8 FOUR-COLOR graphics tile takes up 16 bytes.

Here's a diagram, representing bytes as boxes, showing rows (R1 / R2 / &c...), as well as bitplanes "A" and "B".

Code:
$00      $01       $02        $03      $04       $05       $06       $07
_______  _______   _______   _______   _______   _______   _______   _______
|     |  |     |   |     |   |     |   |     |   |     |   |     |   |     |
| R1  |  | R1  |   | R2  |   | R2  |   | ... |   |     |   |     |   |     |
| A   |  | B   |   | A   |   | B   |   |     |   |     |   |     |   |     |
_______  _______   _______   _______   _______   _______   _______   _______

  $08      $09       $0A        $0B      $0C       $0D       $0E       $0F
_______  _______   _______   _______   _______   _______   _______   _______
|     |  |     |   |     |   |     |   |     |   |     |   |     |   |     |
| R5  |  | R5  |   | ... |   |     |   |     |   |     |   | R8  |   | R8  |
| A   |  | B   |   |     |   |     |   |     |   |     |   | A   |   | B   |
_______  _______   _______   _______   _______   _______   _______   _______

- OK, so, that's a four-color image. Now you might think a 16-color image would just have 4 bitplanes in a row, A B C D. But no. It turns out it has 16 bytes for one four-color tile, then starts again with another 16 bytes holding bitplanes C and D of the same four-color tile. It's as if it's two separate 8x8 pixel tiles in a row, each with 2 bits of color depth. But when they're interpreted as 4-bit art, they're displayed as one tile with 4 bits of color depth.

Code:
$00      $01       $02        $03      $04       $05       $06       $07
_______  _______   _______   _______   _______   _______   _______   _______
|     |  |     |   |     |   |     |   |     |   |     |   |     |   |     |
| R1  |  | R1  |   | R2  |   | R2  |   | ... |   |     |   |     |   |     |
| A   |  | B   |   | A   |   | B   |   |     |   |     |   |     |   |     |
_______  _______   _______   _______   _______   _______   _______   _______

  $08      $09       $0A        $0B      $0C       $0D       $0E       $0F
_______  _______   _______   _______   _______   _______   _______   _______
|     |  |     |   |     |   |     |   |     |   |     |   |     |   |     |
| R5  |  | R5  |   | ... |   |     |   |     |   |     |   | R8  |   | R8  |
| A   |  | B   |   |     |   |     |   |     |   |     |   | A   |   | B   |
_______  _______   _______   _______   _______   _______   _______   _______

  $10      $11       $12       $13       $14       $15       $16       $17
_______  _______   _______   _______   _______   _______   _______   _______
|     |  |     |   |     |   |     |   |     |   |     |   |     |   |     |
| R1  |  | R1  |   | R2  |   | R2  |   | ... |   |     |   |     |   |     |
| C   |  | D   |   | C   |   | D   |   |     |   |     |   |     |   |     |
_______  _______   _______   _______   _______   _______   _______   _______

  $18      $19       $1A       $1B       $1C       $1D       $1E       $1F
_______  _______   _______   _______   _______   _______   _______   _______
|     |  |     |   |     |   |     |   |     |   |     |   |     |   |     |
| R5  |  | R5  |   | ... |   |     |   |     |   |     |   | R8  |   | R8  |
| C   |  | D   |   |     |   |     |   |     |   |     |   | C   |   | D   |
_______  _______   _______   _______   _______   _______   _______   _______

And that's how a 16-color graphics tile is stored. Which makes the bit manipulation weird and cumbersome. This is why there are parts of my code where I'm reading offset 0, followed by offset 1, followed by offset 16, followed by offset 17 (to get the four bitplanes for the same pixel of the same row of the same tile).

Hope this helps, and I hope you get the code working once you paste it in the right place. It's working for me with snes9x debug version.



So, I'm including some more notes on how my code works, since the "big picture" comments might be too scarce, and the labels might be not descriptive enough.

I'm also including my notes on how I think it can be sped up / how I plan to speed it up next revision.

There are basically four sections to it.

Section one, which starts with label load_battle_graphics_new:

This takes place after some original-game code (not written by me) loads the graphics data from the ROM into $2000 bytes of space in RAM.

It goes systematically through every pixel in every frame of the character sprite, calculates which palette entry that pixel uses (based on all four bitplanes), and "checks off" that palette color as used, if it has been used.

Section two, which starts with label lbg_calculate_replacement_colors:

Just stores, in a different format, four bits of information, containing an unused color (from the set of 12 which are usable in the unaltered rom), and a corresponding "expanded" color (from the last 4, normally unusable), where the second should replace the first.

Section three, which starts with label lbg_pixel_changing_loop_pre:

Goes through all the graphics tile data AGAIN, and does the replacement, in a similar bit-by-bit way to section 1.

Section four, which starts with label lbg_new_switch_palette:

This takes place after some more code which was part of the original function. This just replaces the palette colors. Section three replaced the graphics data, this does the palette data.

Now,

efficiency:
- Parts two and four probably take very little time, so it's one and three that we need to worry about.

Pertaining to part 1, where we read which colors are used:
- Unfortunately, there are no shortcuts we can take here in general. It has to go through every pixel to "prove" a particular color is unused.
- If all of the first 12 colors get filled, we could stop then, because then nothing can possibly get switched out. But that won't always happen even for the original sprites. And it's the only case where we can stop early.
- Actually, we could stop after ANY 12 colors are used at least once, and just assume the remaining ones are unused. This would result in unpredictable behavior in cases where the sprite actually uses more than 12 colors, but it should work if the sprite artist follows the "contract".
- The information we get here, once complete, only takes up 16 bits of space. If there is any significant free RAM, we could cache it, and then it only has to be done once per sprite each time the game is loaded. (The only free RAM I know of is in the location that gets stored to SRAM.)
- There might be a faster way to do the bit manipulation?
- Could it be sped up if I combine it with the code present in the original function, where the tile data is originally loaded?

Pertaining to part 3, where we dynamically change the sprite data:
- The change only potentially has to be done if the sprite uses one of the originally unusable, last four palette values / colors. This could be sped up (for some sprites more than others) if we do a quick check on each row of graphics data to see if any pixels in that row use those values. We could just LOGICAL-AND the last bitplane with the second-last bitplane, to check. Then pixel changing has to be done for that row if the result is non-zero (pixels that use the last four colors have both the last two bitplanes "on").
- Again, I'm not sure if my bit-manipulation code is inefficient here. I've only done a little bit of ASM coding before (in classes) so I'm not the perfect expert at doing this kind of bit prodding in the fewest CPU cycles.

If I make the above changes, I think that will significantly speed things up, but I don't know if can make it fast enough that it will be without a noticeable delay.
  Find
Quote  



Messages In This Thread
RE: Patch: allowing use of "reserved" palette colors for player characters - by Eggers - 08-10-2013, 01:59 PM

Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite