Jump to content
IGNORED

Emulator Glitch Help on Keystone Koppers


wavemotion

Recommended Posts

Greetings programs!

 

This community has always been super helpful and I'm in need of a little push in the right direction.

 

My A7800DS emulator (for the DS/DSi) is based on ProSystem. I know that emulator has been problematic with accuracy but in the past year I've worked hard to rectify many of the small glitches to the point where it's generally been really solid (with thanks to @raz0red and the Wii port of the same as he figured out some of the glitch areas).

 

The one remaining known glitch is on @Muddyfunster's amazing Keystone Koppers. Let me make it clear that it's not his program that's buggy - it's my emulator... but after looking at the Maria documents online, trying to understand the various graphics modes, background and transparency handling... I'm still not able to rectify this glitch shown in the image below. 

 

All other graphics look basically correct - including the player sprite. But you can see the black box around the robber... at first I thought maybe Kangaroo mode was screwed up in my emulation but the game doesn't appear to be using that. I thought it might have been one of the odd quirks of 320 mode where both halves of the pixel must be 0 for transparency to work - but this game appears to be using the more standard 160 mode. 

And so after having exhausted my skills in this area I'm hopeful that someone will have a clue or breadcrumb that might push me in the right direction. Even the smallest of clues can go a long way to finding a needle in a haystack!  I'd love to know what's being done in a possibly unusual manner for this particular sprite to let me focus in on that area of emulation. 

image.thumb.png.64c5c08f141e435667a4464784af3a7a.png

 

Kindest regards for any help anyone might provide - random guesses are always welcome :)

 

 

  • Like 1
Link to comment
Share on other sites

11 minutes ago, llabnip said:

All other graphics look basically correct - including the player sprite. But you can see the black box around the robber... at first I thought maybe Kangaroo mode was screwed up in my emulation but the game doesn't appear to be using that. I thought it might have been one of the odd quirks of 320 mode where both halves of the pixel must be 0 for transparency to work - but this game appears to be using the more standard 160 mode. 

And so after having exhausted my skills in this area I'm hopeful that someone will have a clue or breadcrumb that might push me in the right direction. Even the smallest of clues can go a long way to finding a needle in a haystack!  I'd love to know what's being done in a possibly unusual manner for this particular sprite to let me focus in on that area of emulation.

 

The game is fully 160 Mode, no 320 elements are used and Kangaroo mode is not used.

 

The Robber sprite is a 160B sprite (this was just because the colours needed were in multiple palettes), with green in the image below indicating the transparent index. The Kop sprite is also 160B but I notice there are no issues with that in the emulation. The same glitch appears to be present in JS7800 and other prosystem based emulators.

 

image.png.b327da8a5ab83983285790f14aa7e82a.png

 

Sorry I can't be of more help with hardware side of the discussion.

 

 

  • Like 1
Link to comment
Share on other sites

Best guess off the top of my head, is the transparent index for the robber in the game is mapped to one of the alternate transparent indexes, and the emulator isn't handling the other transparent indexes correctly.

 

Assuming the maria object is using pallete 0, the value->color mapping for any 160A pixel (which is 2 bits) breaks down like this...

0=transparent

1=P0C1

2=P0C2

3=P0C3

 

Assuming the maria object is using pallete 0, the value->color mapping for any 160B pixel (which is 4 bits) breaks down like this...

0=transparent

1=P0C1

2=P0C2

3=P0C3

4=transparent

5=P1C1

6=P1C2

7=P1C3

8=transparent

... etc.

 

So for transparency, you want to skip the pixel update if (value&3)==0, rather than value==0. If I'm right with my guess, that is.

 

  • Like 2
Link to comment
Share on other sites

Hugely appreciate the detailed responses guys!

 

I spent the day all over that 160B handling and I can't see anything obviously wrong.  And it is interesting that the Kop sprite is right but the Robber is not.  

 

When we grab the color, we do properly mask off the lower bits for the transparency check. Without this, other artifacts appear on some games.  

 

static inline byte maria_GetColor(byte data) 
{
  return (data & 3) ? memory_ram[BACKGRND | data] : memory_ram[BACKGRND];
}

 

I'll keep looking and experimenting! 

  • Like 2
Link to comment
Share on other sites

For the write-mode graphic modes, you should only be using the top bit of the palette. I'm not that familiar with your source, but I think I have this right...

 

static inline void _maria_StoreCells4(byte data) 
{
  if((maria_horizontal) < MARIA_LINERAM_SIZE) 
  {
    byte *ptr = &(maria_lineRAM[maria_horizontal]);
#ifdef KANGAROO_MODE_SUPPORTED
    if (memory_ram[CTRL] & 4)
    {
        if (data & 0x03) *ptr-- = (maria_palette & 0x10) | (data & 0x03); else *ptr-- = 0;
        data = data >> 2;
        if (data & 0x03) *ptr-- = (maria_palette & 0x10) | (data & 0x03); else *ptr-- = 0;
        data = data >> 2;
        if (data & 0x03) *ptr-- = (maria_palette & 0x10) | (data & 0x03); else *ptr-- = 0;
        data = data >> 2;
        if (data) *ptr = (maria_palette & 0x10) | (data); else *ptr = 0;
    }
    else
#endif        
    {
        if (data & 0xC0) *ptr++ = (maria_palette & 0x10) | ((data & 0xC0) >> 6); else ptr++;
        if (data & 0x30) *ptr++ = (maria_palette & 0x10) | ((data & 0x30) >> 4); else ptr++;
        if (data & 0x0C) *ptr++ = (maria_palette & 0x10) | ((data & 0x0C) >> 2); else ptr++;
        if (data & 0x03) *ptr++ = (maria_palette & 0x10) | (data & 0x03); 
    }
  }
  maria_horizontal += 4;
}

 

i.e. all references to "maria_palette" in the original h_maria_StoreCells4() should be "(maria_palette & 0x10)"

 

...my guess now is the 160B robber object has a palette index that's neither 0 nor 4, but some other number.

  • Like 1
Link to comment
Share on other sites

Herculean effort here @RevEng and much appreciated no matter the outcome!

 

I tried your suggestion and there was no change to the Robber sprite but all the other colors got very trippy - like a Grateful Dead concert circa '79.  

 

I think the write mode store already had that correct:

 

// ----------------------------------------------------------------------------
// StoreCell - write mode
// ----------------------------------------------------------------------------
static inline void maria_StoreCellWide(byte data) 
{
  if(maria_horizontal < MARIA_LINERAM_SIZE) 
  {
      if (data)
      {
          byte *ptr = (byte *)&maria_lineRAM[maria_horizontal];
          if (data & 0xF0)  // high
          {
              *ptr = (maria_palette & 0x10) | (data >> 4);
          }
          if (data & 0x0F)  // low
          {
            ptr++;
            *ptr = (maria_palette & 0x10) | (data & 0x0F);
          }
      }
  }

...

 

Link to comment
Share on other sites

1 hour ago, llabnip said:

I think the write mode store already had that correct:

Yeah, my bad. I mixed up your write and non-write functions.

 

1 hour ago, Muddyfunster said:

Mike, in the source, the robber only uses palette 0.

Thanks!

 

47 minutes ago, Eagle said:

@Muddyfunster is the Robber in indirect mode?

Nope. It's just a regular sprite.

 

2 minutes ago, Ecernosoft said:

Then why 160B?

Palette 0 for 160B really means P0+P1+P2+P3.

  • Like 2
Link to comment
Share on other sites

Try this update...

 

// ----------------------------------------------------------------------------
// StoreCell - write mode
// ----------------------------------------------------------------------------
static inline void maria_StoreCellWide(byte data) 
{
  if(maria_horizontal < MARIA_LINERAM_SIZE) 
  {
      if (data)
      {
          byte *ptr = (byte *)&maria_lineRAM[maria_horizontal];
          if (data & 0xcc)  // high
          {
              *ptr = (maria_palette & 0x10) | (data & 0x0c) | (data >> 6); // P2 D3 D2 D7 D6
          }
          if (data & 0x33 )  // low
          {
            ptr++;
            *ptr = (maria_palette & 0x10) | ((data & 0x03) << 2) | ((data & 0x30) >> 4); // P2 D1 D0 D5 D4
          }
      }
  }

 

 

[edit 1 - updated to fix the nibble tests too]

[edit 2 - had to fix the nibble test again. ugh.]

 

  • Like 1
Link to comment
Share on other sites

Another valiant effort, Rev.  This code is called by a transposition function which does a table-look-up to transpose those funky bit patterns into something I can blaze through... so I don't have to do too much bit twiddling and gain the speed I need on the older Nintendo DS (67Mhz processor).

 

I made your changes with the change in nibble tests (checking 0xCC and 0x33) and undid my table-lookup and while it runs about 25% slower, it produces the exact same results:  Kop looks great but Robber has the black around it.

A good confirmation that the look-up transposition table is working... though I was pretty sure I didn't screw that up as other ProSystem based emulators have the same glitch (and they would have done the code closer to your fine example).

Link to comment
Share on other sites

4 minutes ago, llabnip said:

Another valiant effort, Rev.  This code is called by a transposition function which does a table-look-up to transpose those funky bit patterns into something I can blaze through.

Ah, my lack of familiarity with your source strikes again. When I saw the "missing" transposition, I thought I had it.

 

Ok, back to the analysis.

  • Like 1
Link to comment
Share on other sites

56 minutes ago, RevEng said:

I know it's not being used in the game, but is the glitch still present if kangaroo mode is compile-time disabled in your source?

Yes... it doesn't matter if Kangaroo mode is enabled or disabled... and I did verify that the Roo-mode bit is never enabled in this game.

 

So I don't know if this will help or not... but I dumped out the maria_palette as well as the actual color byte (pre-transformation - so basically the data as you would have it for your most recent bit-shifting algorithm and not muddied by my table lookup).

 

I don't have a pause feature for my crude debugging but I tried to capture 200 bytes of robber vs kop.

 

In the first picture you can see the robber is on screen but not the cop. In the second you can see both.

 

The bytes are in HEX and arranged in vertical columns. The upper leftmost byte is the palette followed by the data byte directly under it. This streams in pairs until all 200 bytes are shown.  Something to note is that the robber colors shift from the white to some blue once the Kop shows up... maybe a clue.


Again, I can't thank you guys enough for the effort!

image.thumb.png.d0e97201cae5ae7512e2ba09d69d4586.pngimage.thumb.png.b165ab13f7ec4eb21f4471c18f2292fe.png

Edited by llabnip
Link to comment
Share on other sites

I have a new working theory...

 

Every time we grab the background color for 160B I just use blue instead. 

 

And lo-and-behold... the robber background is blue.

image.png.2b1b6dbc3c8cb7e4d2794e2d63549c88.png

 

Which makes me think that the Maria code is operating fine - but the background is actually black at the point of the 160b robber being drawn. Which may come down to the infamous cycle in-accuracy of ProSystem. Maybe on a real system the timing is such that the background register would have been written sooner/later or... well... something.  I also can't explain why the Kop background is NOT also blue... perplexing.

Edited by llabnip
Link to comment
Share on other sites

// ----------------------------------------------------------------------------
// StoreCell - write mode
// ----------------------------------------------------------------------------
static inline void maria_StoreCellWide(byte data) 
{
  if(maria_horizontal < MARIA_LINERAM_SIZE) 
  {
      if (data)
      {
          byte *ptr = (byte *)&maria_lineRAM[maria_horizontal];
          if (data & 0xB0)  // high
          {
              *ptr = (maria_palette & 0x10) | (data >> 4);
          }
          if (data & & 0x0B)  // low
          {
            ptr++;
            *ptr = (maria_palette & 0x10) | (data & 0x0F);
          }
      }
  }

...

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...