AntonioND / nitro-engine

3D engine for the Nintendo DS
154 stars 12 forks source link

2D mode: sprites height not set correctly #19

Closed jonko0493 closed 1 year ago

jonko0493 commented 1 year ago

First of all, thanks so much for making this library; it's been a huge boon to the project I'm working on so far. Fair warning that I'm not sure this is actually a bug with NE -- I may just be holding something wrong, but I was hoping to get help either way.

I'm attempting to use the 3D engine to display 2D textures using nitro-engine. I have a 256x256 texture that is transparent below pixel 192.

logo_aqi

I converted this texture to a DS texture, first using a tool I wrote and then using your tool to confirm it wasn't something I was doing while preparing the texture. I am displaying the texture with the following code:

void displayBgAsTex(GraphicInfo &bgInfo, Globals &globals)
{
    GraphicImage bgTex = loadPixels(bgInfo.name);
    Palette bgPal = loadPalette(bgInfo.name);

    if (globals.bgTex[0])
    {
        NE_Palette *oldPalette = globals.bgTex[0]->mat->palette;
        NE_Material *oldMaterial = globals.bgTex[0]->mat;
        NE_SpriteDelete(globals.bgTex[0]);
        NE_MaterialDelete(oldMaterial);
        NE_PaletteDelete(oldPalette);
        globals.bgTex[0] = NULL;
    }

    NE_Material *material = NE_MaterialCreate();
    NE_Palette *palette = NE_PaletteCreate();

    NE_PaletteLoad(palette, (u16 *)bgPal.palette, bgPal.numColors, bgInfo.format);
    NE_MaterialTexLoad(material, bgInfo.format, bgInfo.width, bgInfo.height, NE_TEXGEN_OFF, (void *)bgTex.pixels);
    NE_MaterialSetPalette(material, palette);

    globals.bgTex[0] = NE_SpriteCreate();
    NE_SpriteSetPos(globals.bgTex[0], 0, 0);
    NE_SpriteSetSize(globals.bgTex[0], bgInfo.width, bgInfo.height);
    NE_SpriteSetPriority(globals.bgTex[0], 256);
    NE_SpriteSetMaterial(globals.bgTex[0], material);
}

which is called by a script which does the appropriate thing for rendering the texture

void Draw3DScene()
{
    NE_2DViewInit();
    NE_SpriteDrawAll();
}

...

NE_Process(Draw3DScene);

In my main function, I do all the appropriate setup:

irqEnable(IRQ_HBLANK);
irqSet(IRQ_VBLANK, NE_VBLFunc);
irqSet(IRQ_HBLANK, NE_HBLFunc);
NE_Init3D();
NE_SwapScreens();
Globals globals = loadStaticFiles();

so i think I'm doing everything correctly.

The bgInfo class reads in the width and height from a file I prepared; both of those values are set to 256.

However, in-game, it looks like this: image

And the 3D rendering screen in no$ seems to indicate that the lower texcoords are being set to 252 rather than 256:

image

So... weird!

Hoping you can help figure out what's going on. I can provide the ROM if needed!

Thanks!

AntonioND commented 1 year ago

That's very strange indeed... Can you try to draw the quad like in this example and see what happens? https://github.com/AntonioND/nitro-engine/blob/93817c200e95894b233a8945f54de4b99e9d2eec/examples/other/polygon_textured/source/main.c

There is some special handling when it comes to drawing 2D sprites because the texture mapping is a bit weird https://github.com/AntonioND/nitro-engine/blob/93817c200e95894b233a8945f54de4b99e9d2eec/source/NE2D.c#L398 but it should increase the size by a bit, not reduce it.

jonko0493 commented 1 year ago

Thanks for your reply!

This is the no$ output from doing it that way:

image

And here's the code just so you can double check me:

New loading code:

void displayBgAsTex(GraphicInfo &bgInfo, Globals &globals)
{
    GraphicImage bgTex = loadPixels(bgInfo.name);
    Palette bgPal = loadPalette(bgInfo.name);
    iprintf("Loaded palette and texture\n");

    if (globals.bgMaterial[0])
    {
        iprintf("Previous texture detected, deleting\n");
        NE_Palette *oldPalette = globals.bgMaterial[0]->palette;
        NE_Material *oldMaterial = globals.bgMaterial[0];
        // NE_SpriteDelete(globals.bgTex[0]);
        NE_MaterialDelete(oldMaterial);
        NE_PaletteDelete(oldPalette);
        globals.bgMaterial[0] = NULL;
    }

    NE_Material *material = NE_MaterialCreate();
    iprintf("Material created\n");
    NE_Palette *palette = NE_PaletteCreate();
    iprintf("Palette created\n");

    NE_PaletteLoad(palette, (u16 *)bgPal.palette, bgPal.numColors, bgInfo.format);
    iprintf("Palette loaded\n");
    NE_MaterialTexLoad(material, bgInfo.format, bgInfo.width, bgInfo.height, NE_TEXGEN_OFF, (void *)bgTex.pixels);    
    iprintf("Material texture loaded\n");
    NE_MaterialSetPalette(material, palette);
    iprintf("Material palette set\n");

    globals.bgMaterial[0] = material;
}

Executor code:

NE_Camera *camera;
NE_Material *material;

void Draw3DScene()
{
    // NE_2DViewInit();
    // NE_SpriteDrawAll();

    NE_CameraUse(camera);

    // This set material's color to drawing color (default = white)
    NE_MaterialUse(material);

    // In general you should avoid using the functions below

    // Begin drawing
    NE_PolyBegin(GL_QUAD);

        NE_PolyTexCoord(0, 0);   // Texture coordinates
        NE_PolyVertex(-1, 1, 0); // Send new vertex

        NE_PolyTexCoord(0, 256);
        NE_PolyVertex(-1, -1, 0);

        NE_PolyTexCoord(256, 256);
        NE_PolyVertex(1, -1, 0);

        NE_PolyTexCoord(256, 0);
        NE_PolyVertex(1, 1, 0);

    // Apparently this command is ignored by the GPU
    NE_PolyEnd();
}

...

    camera = NE_CameraCreate();

    NE_CameraSet(camera,
        0, 0, 2,
        0, 0, 0,
        0, 1, 0);

...

            material = globals.bgMaterial[0];
            NE_Process(Draw3DScene);

and same setup in my main function.

Lemme know if you need anything else!

AntonioND commented 1 year ago

Can you create a minimal example of a program that shows this bug? Just the absolute minimum you can have to show a sprite and cause the bug.

jonko0493 commented 1 year ago

For sure, I'll whip something up tonight!

jonko0493 commented 1 year ago

@AntonioND I've reproduced the bug in this minimal sample here: https://github.com/jonko0493/MinimalNitroEngineBug

You can see here that the texture is four pixels smaller shorter than it should be in no$: image

jonko0493 commented 1 year ago

Apologies for the hacky makefiles, i'm not great with make lol. But here's a copy of the nds file that this generates as well:

MinimalSample.zip

AntonioND commented 1 year ago

I've been doing tests, and I think there is some subtle bug with the 2D projection. I need to keep looking into it.

AntonioND commented 1 year ago

Yeah, it looks like the problem is the "<< 12" I add to my projection matrix. It makes some vertices not end up in the right coordinates of the screen. https://github.com/AntonioND/nitro-engine/blob/93817c200e95894b233a8945f54de4b99e9d2eec/source/NE2D.c#L267-L291

If I remove all of the "<< 12" of that function, the coordinates work as expected. However... a the comment of that function says, if I try to rotate any sprite after I remove the shifts, the accuracy is much worse, and it looks pretty bad.

I need to find an actual fix for this that doesn't break rotated sprites...

AntonioND commented 1 year ago

@jonko0493 can you test with the current master? I've pushed a fix here: https://github.com/AntonioND/nitro-engine/commit/193a50c9398f71aa3eb8d726a9351dda854b24ea

jonko0493 commented 1 year ago

Very nice! That does seem to have fixed it.

image

Thanks so much for this! Weird bug, but very glad you figured it out!

AntonioND commented 1 year ago

No problem! :)