Users browsing this thread: 1 Guest(s)
Monster assembling code (c#) *SOLVED*

#1
Posts: 3,970
Threads: 279
Thanks Received: 236
Thanks Given: 58
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
I'm trying to mimic part of Terii Senshi's FF3se code in C# to assemble monsters. However I ran into a bug that I am unable to fix at the moment.

Here's part of my C# function. The graphics data, mold and palette seems to be right. However I get a weird result, an oversized guard due to some spaces on the x axis and I cannot pinpoint what is doing this. (I suck) Finger

Any help would be appreciated!

[Image: Capture_zpshl52pm64.png]

Code:
private WriteableBitmap createBitmap(Monster monster, byte[] graphicsData)
        {
            int moldPtr = 0;
            int graphPtr = 0;
            byte[] tile = new byte[64];
            byte[] moldData;
            byte[] graphics;
            BitmapPalette bPal;
            Color[] pal;
            WriteableBitmap wBmp;
            Int32Rect rect;

            // if monster is 8 colors, get the right palette.
            if (monster.numColors == 8)
            {
                pal = this.monsPals.ElementAt(monster.palette);                
            }
            // if monster is 16 colors, build the palette based on monster palette and next palette.
            // Seems to be good in the guard example
            else
            {
                pal = new Color[16];
                Color[] pal1 = this.monsPals.ElementAt(monster.palette);
                Color[] pal2 = this.monsPals.ElementAt(monster.palette + 1);

                for(int j = 0; j < 8; j++)
                {
                    pal[j] = pal1[j];
                    pal[j + 8] = pal2[j];
                }    
            }

            // Apply transparency to first color of palette.
            pal[0].A = 0;

            // Used by WriteableBitmap constructor
            bPal = new BitmapPalette(pal);

            // if size is 64x64
            if(monster.size == 0)
            {
                // create new bitmap
                wBmp = new WriteableBitmap(64, 64, 96, 96, PixelFormats.Indexed4, bPal);

                // Get mold data (this is correct in the guard example)
                moldData = ByteUtils.GetBytes(this.molds8, monster.mold * 64, 64);

                for(int y = 0; y < 8; y++)
                {
                    for(int x = 0; x < 8; x++)
                    {
                        // if there's a tile present in the 8x8 mold array
                        if(moldData[moldPtr++] == 1)
                        {
                            if(monster.numColors == 16)
                            {
                                // Get the graphics of the tile
                                graphics = ByteUtils.GetBytes(graphicsData, graphPtr, 32);
                                graphPtr += 32;
                            }
                            else
                            {
                                graphics = ByteUtils.GetBytes(graphicsData, graphPtr, 24);
                                graphPtr += 24;
                            }

                            // Get a 8x8 indexed tile
                            tile = Graphics.loadTile(graphics, monster.numColors);
                            
                            // (x position, y position, width, height)
                            rect = new Int32Rect(x * 8, y * 8, 8, 8);

                            // write the pixel on the main bitmap
                            // (rectangle to update, pixel array, stride, input buffer offset)
                            wBmp.WritePixels(rect, tile, 8, 0);
                        }
                    }
                }
            }

the loadTile() function:

Code:
public static byte[] loadTile(byte[] graphics, int colors)
        {
            byte[] tile = new byte[64];
            int i = 0;
            byte c;
            

            for(int y = 0; y < 8; y++)
            {
                c = graphics[i++];

                tile[y * 8 + 7] += (byte)((c & 0x01) >> 0);
                tile[y * 8 + 6] += (byte)((c & 0x02) >> 1);
                tile[y * 8 + 5] += (byte)((c & 0x04) >> 2);
                tile[y * 8 + 4] += (byte)((c & 0x08) >> 3);
                tile[y * 8 + 3] += (byte)((c & 0x10) >> 4);
                tile[y * 8 + 2] += (byte)((c & 0x20) >> 5);
                tile[y * 8 + 1] += (byte)((c & 0x40) >> 6);
                tile[y * 8 + 0] += (byte)((c & 0x80) >> 7);

                c = graphics[i++];

                tile[y * 8 + 7] += (byte)((c & 0x01) >> 1);
                tile[y * 8 + 6] += (byte)((c & 0x02) >> 0);
                tile[y * 8 + 5] += (byte)((c & 0x04) >> 1);
                tile[y * 8 + 4] += (byte)((c & 0x08) >> 2);
                tile[y * 8 + 3] += (byte)((c & 0x10) >> 3);
                tile[y * 8 + 2] += (byte)((c & 0x20) >> 4);
                tile[y * 8 + 1] += (byte)((c & 0x40) >> 5);
                tile[y * 8 + 0] += (byte)((c & 0x80) >> 6);
            }

            for (int y = 0; y < 8; y++)
            {
                c = graphics[i++];

                tile[y * 8 + 7] += (byte)((c & 0x01) >> 2);
                tile[y * 8 + 6] += (byte)((c & 0x02) >> 1);
                tile[y * 8 + 5] += (byte)((c & 0x04) >> 0);
                tile[y * 8 + 4] += (byte)((c & 0x08) >> 1);
                tile[y * 8 + 3] += (byte)((c & 0x10) >> 2);
                tile[y * 8 + 2] += (byte)((c & 0x20) >> 3);
                tile[y * 8 + 1] += (byte)((c & 0x40) >> 4);
                tile[y * 8 + 0] += (byte)((c & 0x80) >> 5);

                if (colors == 16)
                {
                    c = graphics[i++];

                    tile[y * 8 + 7] += (byte)((c & 0x01) >> 3);
                    tile[y * 8 + 6] += (byte)((c & 0x02) >> 2);
                    tile[y * 8 + 5] += (byte)((c & 0x04) >> 1);
                    tile[y * 8 + 4] += (byte)((c & 0x08) >> 0);
                    tile[y * 8 + 3] += (byte)((c & 0x10) >> 1);
                    tile[y * 8 + 2] += (byte)((c & 0x20) >> 2);
                    tile[y * 8 + 1] += (byte)((c & 0x40) >> 3);
                    tile[y * 8 + 0] += (byte)((c & 0x80) >> 4);
                }
            }

            return tile;
        }
    }

Terii's Senshi code:

Code:
void Monster::createBitmap(BYTE *ptr)
    {
    int x,y,i;
    BYTE tile[64];
    BYTE *moldPtr;

    if(ptr == NULL)
        ptr = monsters.image[imageNum].graphicsData;

    mold = monsters.image[imageNum].mold;
    size = monsters.image[imageNum].size;
    numColors = monsters.image[imageNum].numColors;

    if(size == 0)
        {
        pic.createBlank(64,64);

        for(i = 0;i < numColors;i++)
            {
            pic.setColor(i,monsters.monsPals[palette][i]);
            }
        
        moldPtr = &(monsters.molds8[mold * 64]);

        for(y  = 0;y < 8;y++)
            {
            for(x = 0;x < 8;x++)
                {
                if(*(moldPtr++) == 1)
                    {
                    loadTile(ptr,tile,numColors);
                    pic.copyTile(tile,x,y);
                    if(numColors == 16)
                        ptr += 32;
                    else
                        ptr += 24;
                    }
                }
            }
        }

**************************************
void loadTile(BYTE *ptr,BYTE *tile,BYTE colors)
    {
    int y;
    BYTE c;

    ZeroMemory(tile,64);

    for(y = 0;y < 8;y++)
        {
        c = *(ptr++);

        tile[7 + y * 8] += (c & 0x01) >> 0;
        tile[6 + y * 8] += (c & 0x02) >> 1;
        tile[5 + y * 8] += (c & 0x04) >> 2;
        tile[4 + y * 8] += (c & 0x08) >> 3;
        tile[3 + y * 8] += (c & 0x10) >> 4;
        tile[2 + y * 8] += (c & 0x20) >> 5;
        tile[1 + y * 8] += (c & 0x40) >> 6;
        tile[0 + y * 8] += (c & 0x80) >> 7;
        
        c = *(ptr++);

        tile[7 + y * 8] += (c & 0x01) << 1;
        tile[6 + y * 8] += (c & 0x02) >> 0;
        tile[5 + y * 8] += (c & 0x04) >> 1;
        tile[4 + y * 8] += (c & 0x08) >> 2;
        tile[3 + y * 8] += (c & 0x10) >> 3;
        tile[2 + y * 8] += (c & 0x20) >> 4;
        tile[1 + y * 8] += (c & 0x40) >> 5;
        tile[0 + y * 8] += (c & 0x80) >> 6;
        }
    for(y = 0;y < 8;y++)
        {
        c = *(ptr++);

        tile[7 + y * 8] += (c & 0x01) << 2;
        tile[6 + y * 8] += (c & 0x02) << 1;
        tile[5 + y * 8] += (c & 0x04) >> 0;
        tile[4 + y * 8] += (c & 0x08) >> 1;
        tile[3 + y * 8] += (c & 0x10) >> 2;
        tile[2 + y * 8] += (c & 0x20) >> 3;
        tile[1 + y * 8] += (c & 0x40) >> 4;
        tile[0 + y * 8] += (c & 0x80) >> 5;
        
        if(colors == 16)
            {
            c = *(ptr++);

            tile[7 + y * 8] += (c & 0x01) << 3;
            tile[6 + y * 8] += (c & 0x02) << 2;
            tile[5 + y * 8] += (c & 0x04) << 1;
            tile[4 + y * 8] += (c & 0x08) >> 0;
            tile[3 + y * 8] += (c & 0x10) >> 1;
            tile[2 + y * 8] += (c & 0x20) >> 2;
            tile[1 + y * 8] += (c & 0x40) >> 3;
            tile[0 + y * 8] += (c & 0x80) >> 4;
            }
        }
    }
********************************************
BYTE Bitmap::copyTile(BYTE *tile,int x,int y)
    {
    BYTE *ptr;
    int x2,y2;
    if(((x * 8) >= (width - 7)) || ((y * 8) >= (height - 7)))
        return 1;

    ptr = &(pixels[x * 8 + (y * 8) * width]);
    for(y2 = 0; y2 < 8;y2++)
        {
        for(x2 = 0;x2 < 8;x2++)            
            {
            *(ptr++) = *(tile++);
            }
        ptr += width - 8;
        }
    
    return 0;
    }
  Find
Quote  

#2
Posts: 127
Threads: 8
Thanks Received: 21
Thanks Given: 12
Joined: Jan 2012
Reputation: 13
Status
None
You seem to have a number of right shifts where there should be left shifts.

Example:
Code:
tile[y * 8 + 7] += (byte)((c & 0x01) >> 1);

this line has a wrong shift (right shift, should be left) according to Senshi's code:

Code:
tile[7 + y * 8] += (c & 0x01) << 1;

There are more left shifts you have written as right shifts.

Edit: btw, the tool looks really nice, nice work.
  Find
Quote  
[-] The following 1 user says Thank You to m06 for this post:
  • madsiur (06-23-2015)

#3
Posts: 3,970
Threads: 279
Thanks Received: 236
Thanks Given: 58
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
(06-23-2015, 01:53 PM)m06 Wrote: You seem to have a number of right shifts where there should be left shifts.

Thanks. That's what happen when you blindly do copy paste.Finger

However, my guard looks almost exactly the same... I'll look more into it.
  Find
Quote  

#4
Posts: 127
Threads: 8
Thanks Received: 21
Thanks Given: 12
Joined: Jan 2012
Reputation: 13
Status
None
I think the order of your arithmetic operations is wrong aswell.

If y = 2

You write: y * 8 + 7

Your result is: 23

Senshi writes: 7 + y * 8

Senshi's result is: 72

This is happens because programming languages process arithmetics from left to right and not in order of priority as is taught in math (in math both should result in 23).

You can think of it like this:

You: ((y * 8) + 7)
Senshi: ((7 + y) * 8)
  Find
Quote  

#5
Posts: 3,970
Threads: 279
Thanks Received: 236
Thanks Given: 58
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
(06-23-2015, 03:58 PM)m06 Wrote: I think the order of your arithmetic operations is wrong aswell.

Thanks! I did changed that like you suggested. I found out the oversizing of the monster was the result of my preview window resizing it automatically. Now the sprite is the good size, but there's still some lines on it:

[Image: Capture_zpsievudysi.png]

Edit: prioritizing the addition first will get an exception because if y = 7, (7 + 7) * 8 is higher than 64 (112) . So the right way is 7 * 8 + 7, 63, the last index of the tile array.

Edit2: I will try applying the byte shift to the whole addition, something like this:

tile[7 + y * 8] = (byte)((tile[7 + y * 8] + (c & 0x01)) >> 0);

Edit3: ^this was a bad idea
  Find
Quote  

#6
Posts: 3,970
Threads: 279
Thanks Received: 236
Thanks Given: 58
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
I implemented a method that writes each pixels individually instead of WritePixels() and the output is good:

[Image: Capture_zpscakaverj.png]

It's a bit slower I think but unless someone come with the proper way to use WritePixels() with a rectangle, we can consider this case closed.
  Find
Quote  

#7
Posts: 127
Threads: 8
Thanks Received: 21
Thanks Given: 12
Joined: Jan 2012
Reputation: 13
Status
None
Senshi's byte accessing is really weird. I guess you were doing it correctly before.

It looks like you are doing things correctly, and the bug looks very strange.

One thing I could think of is if the stride is wrong. If each pixel is 2 bytes in the final image the stride should be 16 I guess.

For some dynamic stride:
Code:
wBmp.WritePixels(rect, tile, 8, 0);

change to:

wBmp.WritePixels(rect, tile, 8 * (wBmp.Format.BitsPerPixel/8), 0);
  Find
Quote  
[-] The following 1 user says Thank You to m06 for this post:
  • madsiur (06-23-2015)

#8
Posts: 3,970
Threads: 279
Thanks Received: 236
Thanks Given: 58
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
I think you may be right (wrong stride and/or format) but I tried changing the stride to 16 and it cause an exception. But anyway, since my WriteableBitmap library can only manage the Pbgra32 format, I have to use the method I described in my previous post. I'm glad the part of assembling a sprite is over me now, I should be able to manage the rest alone (hopefully).
  Find
Quote  

#9
Posts: 127
Threads: 8
Thanks Received: 21
Thanks Given: 12
Joined: Jan 2012
Reputation: 13
Status
None
I'm glad you have a working solution Smile

I suggest trying the dynamic version I posted, it's derived from this tutorial I found:
http://www.i-programmer.info/programming...ml?start=1
  Find
Quote  



Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite