Homebrew Textures block format

cebolleto

Well-Known Member
OP
Member
Joined
Mar 5, 2010
Messages
204
Trophies
2
Age
44
XP
2,874
Country
For a few days I have been trying to load textures into memory without luck

Looking into the code of 3dscraft I found a script named texconv.py which seems to do the job. I have translated that into C++ code and it seems to work, but there are a few issues:
- Textures are upside down
- Only square textures seems to be loaded properly

Could anyone explain how textures are supposed to be stored into memory?
Also just for curiosity I'd like to understand why the orders of pixels in the GPU is this weird...

Thanks!
 
  • Like
Reactions: Margen67

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,059
Trophies
1
XP
3,348
Country
United States
For a few days I have been trying to load textures into memory without luck

Looking into the code of 3dscraft I found a script named texconv.py which seems to do the job. I have translated that into C++ code and it seems to work, but there are a few issues:
- Textures are upside down
- Only square textures seems to be loaded properly

Could anyone explain how textures are supposed to be stored into memory?
Also just for curiosity I'd like to understand why the orders of pixels in the GPU is this weird...

Thanks!
the width and height appear to be reversed in libctru. That still leaves stuff upside down. I was wondering if that has something to do with the rotated frame buffer.
 

cebolleto

Well-Known Member
OP
Member
Joined
Mar 5, 2010
Messages
204
Trophies
2
Age
44
XP
2,874
Country
Thanks, that almost did the job... I am still having issues with some resolutions
Does anyone know why the 3ds uses this format? I imagine it adds some kind of optimization but cannot image what...
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,059
Trophies
1
XP
3,348
Country
United States
Thanks, that almost did the job... I am still having issues with some resolutions
Does anyone know why the 3ds uses this format? I imagine it adds some kind of optimization but cannot image what...
The dimensions need to be powers of two. I have not had issues within those constraints. If you are referring to the block format I think I saw something somewhere about increasing cache hits when reading the texture.
 

themperror

Well-Known Member
Member
Joined
Aug 12, 2009
Messages
181
Trophies
1
XP
377
Country
Netherlands
For a few days I have been trying to load textures into memory without luck

Looking into the code of 3dscraft I found a script named texconv.py which seems to do the job. I have translated that into C++ code and it seems to work, but there are a few issues:
- Textures are upside down
- Only square textures seems to be loaded properly

Could anyone explain how textures are supposed to be stored into memory?
Also just for curiosity I'd like to understand why the orders of pixels in the GPU is this weird...

Thanks!


Textures should always be a power of 2 in any dimension, 8x8, 16x16,32x32,64x64,128x128, 256x256, 512x512 (higher probably won't be needed on the 3ds (also considering speed)), in OpenGL and DirectX they CAN be rectangular, in the old days they had to be square though.. so 512x256 was allowed, But I don't know if it's allowed on the 3ds.

Textures are normally loaded in VRAM, in case of CPU rendering it's just a block of linear memory. so an array with all pixels in there will suffice.
 

neobrain

-
Member
Joined
Apr 25, 2014
Messages
306
Trophies
0
XP
740
Country
Textures are stored upside-down in memory indeed, i.e. the v=1 coordinate corresponds to the first data row in memory at the texture source address, whereas the v=0 coordinate corresponds to the last row in memory.

The same applies to framebuffers, fyi.
 

minexew

ayy lmao
Member
Joined
Mar 16, 2013
Messages
228
Trophies
1
XP
305
Country
Does anyone know why the 3ds uses this format? I imagine it adds some kind of optimization but cannot image what...

It's called the "native PICA format" and it either significantly simplifies the hardware design or helps a lot with cache utilization and thus performance (2nd possibility seems more likely IMO because the PICA uses some kind of block-based rendering).
Can't think of any other reason why they would use it.
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,059
Trophies
1
XP
3,348
Country
United States
Textures should always be a power of 2 in any dimension, 8x8, 16x16,32x32,64x64,128x128, 256x256, 512x512 (higher probably won't be needed on the 3ds (also considering speed)), in OpenGL and DirectX they CAN be rectangular, in the old days they had to be square though.. so 512x256 was allowed, But I don't know if it's allowed on the 3ds.

Textures are normally loaded in VRAM, in case of CPU rendering it's just a block of linear memory. so an array with all pixels in there will suffice.
Rectangle textures are allowed. My experience has been that GPU_SetTexture has the width and the height reversed.
 

cebolleto

Well-Known Member
OP
Member
Joined
Mar 5, 2010
Messages
204
Trophies
2
Age
44
XP
2,874
Country
Sorry I am still having problems with this... I can load square textures and rectangle textures but only if theis high is bigger then their width. When the width is bigger (64x32 for example) it doesn't look ok

Could anyone post the C++ code? That would be very helpful
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,059
Trophies
1
XP
3,348
Country
United States
I am sure this could be optimized but it take an 8 bit source and converts it to 16 bit. But it does show the proper tile ordering. It also flips the texture vertically. There is also a fair bit of dead code in there. Primarily for cross compiling for windows. I can confirm that it works with wide and narrow textures. There is a scale call but it just ensures power of 2 dimensions.

https://github.com/elhobbs/spectre3ds/blob/master/source/sys_textures.cpp#L329
 

cebolleto

Well-Known Member
OP
Member
Joined
Mar 5, 2010
Messages
204
Trophies
2
Age
44
XP
2,874
Country
I have been taking a look, but still the same problem. It doesn't seem to work with textures that are 32x64 or 64x32
 

cebolleto

Well-Known Member
OP
Member
Joined
Mar 5, 2010
Messages
204
Trophies
2
Age
44
XP
2,874
Country
Yes, I know... I was already swapping the width and height when calling GPU_SetTexture. The weird thing is that I also need to do it when calling parseTileTrans16 which is not what you had there
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,059
Trophies
1
XP
3,348
Country
United States
Yes, I know... I was already swapping the width and height when calling GPU_SetTexture. The weird thing is that I also need to do it when calling parseTileTrans16 which is not what you had there
That is bizarre. I do not do that and it works fine for me. I am curious. Do you have any code that I could look at to see how you are using this?
 

cebolleto

Well-Known Member
OP
Member
Joined
Mar 5, 2010
Messages
204
Trophies
2
Age
44
XP
2,874
Country
No, yeah... you were right... after cleaning my code a bit it turned out I was swapping width and height on a previous call and so I had to swap again
Now everything makes sense

Thanks a lot for your help elhobbs. Now I can continue working on this :)
 

cebolleto

Well-Known Member
OP
Member
Joined
Mar 5, 2010
Messages
204
Trophies
2
Age
44
XP
2,874
Country
Sorry, I forgot to post the final code for this for anyone who can need it
Code:
void ReorderImageData(u8* src, u8* palette, u8* dst, int width, int height, void(copyFunc)(u8*, u8*, int, u8*, int))
{
    static int tile_order[] = {
         0,  1,  8,  9,  2,  3, 10, 11,
        16, 17, 24, 25, 18, 19, 26, 27,
         4,  5, 12, 13,  6,  7, 14, 15,
        20, 21, 28, 29, 22, 23, 30, 31,

        32, 33, 40, 41, 34, 35, 42, 43,
        48, 49, 56, 57, 50, 51, 58, 59,
        36, 37, 44, 45, 38, 39, 46, 47,
        52, 53, 60, 61, 54, 55, 62, 63
    };


    int idx = 0;
    int i, j;
    for(int y = 0; y < height; y += 8)
    {
        for(int x = 0; x < width; x += 8)
        {
            for(int k = 0; k < 64; ++ k)
            {
                i = (tile_order[k] % 8);
                j = (tile_order[k] - i) / 8;

                int src_idx = (height - (y + j) - 1) * width + (x + i);

                copyFunc(src, palette, src_idx, dst, idx);
       
                idx ++;
            }
        }
    }
}

where copyFunc is a pointer to a function similiar to these
Code:
void copyRGB(u8* src, u8* palette, int src_idx, u8* dst, int dst_idx)
{
    dst[dst_idx * 3 + 0] = src[src_idx * 3 + 2];
    dst[dst_idx * 3 + 1] = src[src_idx * 3 + 1];
    dst[dst_idx * 3 + 2] = src[src_idx * 3 + 0];
}

void copyRGBA(u8* src, u8* palette, int src_idx, u8* dst, int dst_idx)
{
    dst[dst_idx * 4 + 0] = src[src_idx * 4 + 3];
    dst[dst_idx * 4 + 1] = src[src_idx * 4 + 2];
    dst[dst_idx * 4 + 2] = src[src_idx * 4 + 1];
    dst[dst_idx * 4 + 3] = src[src_idx * 4 + 0];
}
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
  • Skelletonike @ Skelletonike:
    I've drank 3 expressos and 75cl of energy drinks
  • Sicklyboy @ Sicklyboy:
    I
    switched things up today and had a java monster
    +1
  • Skelletonike @ Skelletonike:
    and I've been listening to old rock and metal >.>
    +1
  • Skelletonike @ Skelletonike:
    Couldn't play much last night since my pinky got sore and the Steam Deck and Switch both felt uncomfortable

    .-.
  • Sicklyboy @ Sicklyboy:
    Depends on where you set the threshold for "old" but I've been on a big System Of A Down kick the last few days lol
  • Skelletonike @ Skelletonike:
    that's part of the classics
    +1
  • Skelletonike @ Skelletonike:
    by old I mean pre 1970

    -2010
    +1
  • Sicklyboy @ Sicklyboy:
    Given their first studio album is nearly 30 years old I'd consider it "old" at this point :( as much as it pains me to say so
    +1
  • Skelletonike @ Skelletonike:
    I started listening to them when I was in middle school, Slipknot, Korn, System of a Down, Linkin Park (papercut was still new), etc
  • Skelletonike @ Skelletonike:
    my badass creative mp3
    +1
  • Skelletonike @ Skelletonike:
    with a massive 25
    6mb
    +1
  • Sicklyboy @ Sicklyboy:
    Same to all 4 of those :rofl:
  • Skelletonike @ Skelletonike:
    That's the one I had I think, it was blue and white, white part could be a pen by itself which was handy
  • Sicklyboy @ Sicklyboy:
    god damn I haven't seen one of those things in a hot minute
  • Skelletonike @ Skelletonike:
    Eventually upgraded to a 512mb from another brand (wasn't so good though, forgot about it)
  • Skelletonike @ Skelletonike:
    In high school, I got an Ipod Nano 5th gen
  • Skelletonike @ Skelletonike:
    still have it, still works
  • Sicklyboy @ Sicklyboy:
    My first mp3 player was a 4th gen ipod w/ click wheel, 20GB. Thing was slick as hell back then and I wish I still had it today. Kicker was when I got it, we still had win98 on our home PC, minimum requirements for itunes was winXP, and my parents wouldn't upgrade 😭
  • AncientBoi @ AncientBoi:
    Mine was the first laptop I had.
  • Sicklyboy @ Sicklyboy:
    akljdaskldjalskdajkls insane wtf https://www.youtube.com/watch?v=VuDTixfKsCQ
  • Skelletonike @ Skelletonike:
    original Ipods had massive storage, it was pornographic
  • Skelletonike @ Skelletonike:
    I never used itunes, always used one of those programs to bypass it, just drag and drop
  • Sicklyboy @ Sicklyboy:
    I didn't know the other programs at the time :( honestly not even sure if any existed yet at that point
  • Skelletonike @ Skelletonike:
    I just googled and drag and drop seemed to be possible at the time
    Skelletonike @ Skelletonike: I just googled and drag and drop seemed to be possible at the time