Page 1 of 1

DKC1 editor?

PostPosted: February 26th, 2020, 1:17 pm
by rainbowsprinklez
I'm working on a low level dkc editor... Does anybody know how to go from snes tile to image in c#? I already have an object mover. I am not interested in cameras, bananas, etc. Right now I have it so levels will break if you aren't careful. This doesn't properly order objects. This is essentially a glorified hex editor.

Re: DKC1 editor?

PostPosted: February 26th, 2020, 5:02 pm
by Kingizor
Tiles are either 2bpp, 4bpp or 8bpp (bpp = bits per plane). For 2bpp you basically have 8 pairs of bytes, so 16 bytes in all. The bits in the 1st byte would be the low bit of the resulting shade for each pixel in the top row of the resulting tile, then the 2nd byte would contain the second lowest bit. 3rd and 4th bytes would be the same for the second row, and so on. For 2bpp, you only have that one set of 16 bytes. For 4bpp, you have another 16 bytes so 32 in all, and for 8bpp you have 4x16=64.

NES does a single bit of the resulting shade in 8 bytes, then the next bit in the following 8 bytes which is a lot more natural. The SNES does it in pairs of bits and bytes because VRAM accesses are always in words. GB also does it the SNES way, but I'm not clear on the details.

Bitplanes are quite confusing and not at all easy to grasp. Some documents and explanations are exceptionally bad, which doesn't help. It finally clicked for me when I saw a diagram in a fairly old document titled "SNES Graphics Information" by a fellow called Qwertie.

Anyway, once you have the shade for a particular pixel in that 8x8 tile, you get the real colour by using the value as a lookup in the associated palette.

In some circumstances the colour isn't known, so some programs (e.g. Tile viewers) will show the shade as greyscale rather than guess a colour.

Here's a small C program that converts a few predefined tiles to greyscale images:

Spoiler!
Code: Select all
#include <stdio.h>

void snes2shade (unsigned char *tile, unsigned char *img, int depth) {
    int i,j,k;

    for (i = 0; i < 8; i++) { /* Each row */
    for (j = 0; j < 8; j++) { /* Each column */
        img[i*8+j] = 0;
        for (k = 0; k < depth/2; k++) {
            img[i*8+j] |= (((tile[i*2+k*16  ] >> (7 - j)) & 1) << (k*2  ))
                       |  (((tile[i*2+k*16+1] >> (7 - j)) & 1) << (k*2+1));
        }
    }
    }
}

/* Output a Greyscale Netpbm type image */
int output_pgm (unsigned char *img, char *name, int depth) {
    FILE *out = fopen(name, "wb");
    int i;

    if (out == NULL) {
        puts("Failed to open output file.");
        return 1;
    }

    fprintf(out, "P5\n%d %d\n%d\n", 8, 8, (1 << depth)-1);

    for (i = 0; i < 64; i++)
        fputc(img[i], out);

    fclose(out);
    return 0;
}

int main (void) {

    /* Some predefined tiles */
    unsigned char bpp2[] = {
        0x01,0x7E,0x02,0xBD,0x04,0xDB,0x08,0xE7,
        0x10,0xE7,0x20,0xDB,0x40,0xBD,0x80,0x7E
    };
    unsigned char bpp4[] = {
        0x00,0x00,0x4A,0x02,0x00,0x40,0x60,0x62,
        0x02,0x10,0x48,0x08,0x00,0x40,0x00,0x00,
        0x00,0x00,0x02,0x0A,0x00,0x10,0x22,0x02,
        0x42,0x12,0x40,0x08,0x44,0x04,0x00,0x00
    };
    unsigned char bpp8[] = {
        0x55,0x33,0x55,0x33,0x55,0x33,0x55,0x33,
        0x55,0x33,0x55,0x33,0x55,0x33,0x55,0x33,
        0x0F,0x00,0x0F,0xFF,0x0F,0x00,0x0F,0xFF,
        0x0F,0x00,0x0F,0xFF,0x0F,0x00,0x0F,0xFF,
        0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,
        0x00,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    };

    /* A buffer to keep our image data */
    unsigned char img[64];

    snes2shade(bpp2, img, 2);
    output_pgm(img, "2bpp.pgm", 2);

    snes2shade(bpp4, img, 4);
    output_pgm(img, "4bpp.pgm", 4);

    snes2shade(bpp8, img, 8);
    output_pgm(img, "8bpp.pgm", 8);

    return 0;
}


The relevant part is the 'snes2shade' function. It's a bit tricky to look at like most image processing functions.

The tile data is passed to the function. This will either be 2bpp (16 bytes), 4bpp (32 bytes) or 8bpp (64 bytes). The "depth" variable indicates which, either 2, 4 or 8. A 64-byte buffer called "img" to store the output is also passed. 64 = 8x8. Again, if you wanted to apply a specific palette, you would use the values here as a lookup.

The calculations... We have "i" to indicate rows and "j" for columns. These apply to both the input and the output. The "k" variable does a few things relating to depth. First we extract the relevant bit from the tile data, then shift it and place it in the image.

It's not the easiest thing to explain, but maybe some of it is helpful. :dixiecry:

Re: DKC1 editor?

PostPosted: February 26th, 2020, 11:05 pm
by rainbowsprinklez
Thank you very much! Hey. Anything is a help when I'm looking at this https://i.imgur.com/vmIC8qi.png :facepalm:

Re: DKC1 editor?

PostPosted: February 26th, 2020, 11:38 pm
by Kingizor
Hey, don't knock fullsnes. :bleak:

But yes that is quite confusing. At first I thought that grid was referring to rows and columns, but it's referring to planes. It was enough to make me think I had made a serious miscalculation, but no it does match up somehow.

Definitely not the worst I've seen though. There is one particularly horrible bitplane document that lurks in my memory. It's almost certainly cursed, because anyone who looks at it will instantly and completely forget how any of this works, so you would have to relearn all this from scratch. It happened to me once. The best I can do is warn you about it, but if you come across it it's already too late. Just don't blindly google bitplane documentation if you can help it.

The Qwertie document I mentioned has a nice little diagram. The SNES word pairing makes it a tiny bit trickier than it could be, but it's not too bad.

The kids these days are into YouTubes and things like that, so maybe there is a really concise explanation out there that we don't know about. *o*

Re: DKC1 editor?

PostPosted: February 27th, 2020, 1:33 am
by rainbowsprinklez
Thanks again! I'm realizing more and more I should just keep it low-level :P It works, somewhat, there's just a lot more features to add. Yes, it is still low-level :P Glorified hex editor.

Re: DKC1 editor?

PostPosted: February 27th, 2020, 4:05 am
by Kingizor
Ahem, turns out there was at least one small bug in that code preventing it from working. I think I made a small change before I posted it that looked as though it wouldn't make any difference but it actually did. I could have sworn it was working at that point, but oh well. Should be fine now, maybe. :?

It would have made sense to test it against some known good data instead of making sure it matched my own made up data, but oh well. Guessing is more fun anyway. :krool:

Re: DKC1 editor?

PostPosted: February 27th, 2020, 8:22 am
by rainbowsprinklez
I agree! Hey, if it runs fine in your head, what's the issue? :P

Also, I never said this yet, but a very special thank you to Simion32. I couldn't have done this without your object list! That thing has helped me SO much. Sometimes I forget that it is thanks to you I started down this path! :banana:

Re: DKC1 editor?

PostPosted: June 3rd, 2020, 10:56 am
by rainbowsprinklez
Kingizor! I'm late by a few months in mentioning this, but this clicked for me! This https://sneslab.net/wiki/Graphics_Format#4bpp helped.

Spoiler!
Image


Phew!