Homebrew Citro3D - Loading png into C3D_Tex

PrintHello

Active Member
OP
Newcomer
Joined
Feb 10, 2016
Messages
37
Trophies
0
Age
28
XP
149
Country
Solved! See below for details

I'm trying to write a simple GPU-based text renderer that will load a png file on the SD card into a C3D_Tex and display it on the screen.

I've tried using libpng from the precompiled portlibs, and a png loader PicoPNG but both of them produce a texture like this:

aIJ5zK9.png


Mostly copy paste from the textured cube example
Code:
std::streamsize size, size_2;
    std::vector<unsigned char> buffer, image, bin_image;

    std::ifstream file("sdmc:test_game/test.png");
    if (file.seekg(0, std::ios::end).good()) size = file.tellg();
    if (file.seekg(0, std::ios::beg).good()) size -= file.tellg();

    std::ifstream file_2("sdmc:test_game/test.bin");
    if (file_2.seekg(0, std::ios::end).good()) size_2 = file_2.tellg();
    if (file_2.seekg(0, std::ios::beg).good()) size_2 -= file_2.tellg();

    //read contents of the file into the vector
    if (size > 0)
    {
        buffer.resize((size_t)size);
        file.read((char*)(&buffer[0]), size);
    }
    else buffer.clear();

    if (size_2 > 0)
    {
        bin_image.resize((size_t)size_2);
        file_2.read((char*)(&bin_image[0]), size_2);
    }
    else buffer.clear();

    unsigned long w, h;
    int error = decodePNG(image, w, h, buffer.empty() ? 0 : &buffer[0], (unsigned long)buffer.size());
    if (error != 0) {
        char info[30];
        sprintf(info, "error:%i", error);
        util::debug_print(info);
    }

    /* Upload to shader */
  
    C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);

    // Initialize the render target
    C3D_RenderTarget* target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
    C3D_RenderTargetSetClear(target, C3D_CLEAR_ALL, CLEAR_COLOR, 0);
    C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);

    static const util::vertex vertex_list[] =
    {
        // First face (PZ)
        // First triangle
        { { -0.5f, -0.5f, +0.5f },{ 0.0f, 0.0f },{ 0.0f, 0.0f, +1.0f } },
        { { +0.5f, -0.5f, +0.5f },{ 1.0f, 0.0f },{ 0.0f, 0.0f, +1.0f } },
        { { +0.5f, +0.5f, +0.5f },{ 1.0f, 1.0f },{ 0.0f, 0.0f, +1.0f } },
        // Second triangle
        { { +0.5f, +0.5f, +0.5f },{ 1.0f, 1.0f },{ 0.0f, 0.0f, +1.0f } },
        { { -0.5f, +0.5f, +0.5f },{ 0.0f, 1.0f },{ 0.0f, 0.0f, +1.0f } },
        { { -0.5f, -0.5f, +0.5f },{ 0.0f, 0.0f },{ 0.0f, 0.0f, +1.0f } }
    };

    DVLB_s* vshader_dvlb;
    shaderProgram_s program;
    int uLoc_projection, uLoc_modelView;
    int uLoc_lightVec, uLoc_lightHalfVec, uLoc_lightClr, uLoc_material;
    C3D_Mtx projection;
    C3D_Mtx material =
    {
        {
            { { 0.0f, 0.2f, 0.2f, 0.2f } }, // Ambient
            { { 0.0f, 0.4f, 0.4f, 0.4f } }, // Diffuse
            { { 0.0f, 0.8f, 0.8f, 0.8f } }, // Specular
            { { 1.0f, 0.0f, 0.0f, 0.0f } }, // Emission
        }
    };

    // Load the vertex shader, create a shader program and bind it
    vshader_dvlb = DVLB_ParseFile((u32*)vshader_shbin, vshader_shbin_size);
    shaderProgramInit(&program);
    shaderProgramSetVsh(&program, &vshader_dvlb->DVLE[0]);
    C3D_BindProgram(&program);

    uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection");
    uLoc_modelView = shaderInstanceGetUniformLocation(program.vertexShader, "modelView");
    uLoc_lightVec = shaderInstanceGetUniformLocation(program.vertexShader, "lightVec");
    uLoc_lightHalfVec = shaderInstanceGetUniformLocation(program.vertexShader, "lightHalfVec");
    uLoc_lightClr = shaderInstanceGetUniformLocation(program.vertexShader, "lightClr");
    uLoc_material = shaderInstanceGetUniformLocation(program.vertexShader, "material");

    // Configure attributes for use with the vertex shader
    C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
    AttrInfo_Init(attrInfo);
    AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position
    AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=texcoord
    AttrInfo_AddLoader(attrInfo, 2, GPU_FLOAT, 3); // v2=normal

    // Compute the projection matrix
    Mtx_PerspTilt(&projection, C3D_AngleFromDegrees(80.0f), C3D_AspectRatioTop, 0.01f, 1000.0f, false);

    // Create the VBO (vertex buffer object)
    void* vbo_data = linearAlloc(sizeof(vertex_list));
    memcpy(vbo_data, vertex_list, sizeof(vertex_list));

    // Configure buffers
    C3D_BufInfo* bufInfo = C3D_GetBufInfo();
    BufInfo_Init(bufInfo);
    BufInfo_Add(bufInfo, vbo_data, sizeof(util::vertex), 3, 0x210);

    C3D_Tex png_texture;
    // Load the texture and bind it to the first texture unit
    C3D_TexInit(&png_texture, 128, 128, GPU_TEXCOLOR::GPU_RGBA8);
    C3D_TexUpload(&png_texture, &image[0]);
    C3D_TexSetFilter(&png_texture, GPU_LINEAR, GPU_NEAREST);
    C3D_TexBind(0, &png_texture);

    // Configure the first fragment shading substage to blend the texture color with
    // the vertex color (calculated by the vertex shader using a lighting algorithm)
    // See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
    C3D_TexEnv* env = C3D_GetTexEnv(0);
    C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0);
    C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
    C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE);

    while (true) {

        C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
        C3D_FrameDrawOn(target);
      
        C3D_Mtx modelView;
        Mtx_Identity(&modelView);
        Mtx_Translate(&modelView, 0.0, 0.0, -2.0, true);

        // Update the uniforms
        C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection);
        C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView);
        C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_material, &material);
        C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightVec, 0.0f, 0.0f, -1.0f, 0.0f);
        C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightHalfVec, 0.0f, 0.0f, -1.0f, 0.0f);
        C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr, 1.0f, 1.0f, 1.0f, 1.0f);

        // Draw the VBO
        C3D_DrawArrays(GPU_TRIANGLES, 0, sizeof(vertex_list) / sizeof(util::vertex));

        C3D_FrameEnd(0);

    }

Both the Tex and the png have the same dimensions (128x128). I've used the png to bin converter tool and loaded the bin as the texture and that still shows up this garbled mess. Strangely the kitten.bin from the examples does load properly so I have no clue what it would be, probably something simple :sleep:.

I've had a look at sfillib and it seems to do what I want but according to the github page it is deprecated.

Any help is appreciated

Cheers
 
Last edited by PrintHello,

bee395

Member
Newcomer
Joined
Jun 26, 2016
Messages
16
Trophies
0
Age
25
XP
94
Country
Netherlands
When I replace the kitten.bin with the logo.bin (from the Cirto3d test project) I get a good looking image. But when when I convert the logo64.png to a bin format, which should be the same, I get the same garbled mess. So I think it's something to do with the file format.
You can maybe fix it with C3D_SafeDisplayTransfer but I'm not really sure.

It's maybe easier to look at the gpusprites example, since they use a pngconverter so you don't have to worry about different bin formats.

https://github.com/devkitPro/3ds-examples/blob/master/graphics/gpu/gpusprites/source/main.c#L182
 
  • Like
Reactions: PrintHello

PrintHello

Active Member
OP
Newcomer
Joined
Feb 10, 2016
Messages
37
Trophies
0
Age
28
XP
149
Country
upload_2017-7-23_21-1-12.png

It's upside down and flipped horizontally but that did it :lol: Thanks!
Here's the code for anyone else who comes across the thread (I made a new array to store the rgba to tiled format texture, and coped the rest from the link)
Code:
std::streamsize size;
    std::vector<unsigned char> buffer, image;

    std::ifstream file("sdmc:test_game/test.png");
    if (file.seekg(0, std::ios::end).good()) size = file.tellg();
    if (file.seekg(0, std::ios::beg).good()) size -= file.tellg();

    //read contents of the file into the vector
    if (size > 0)
    {
        buffer.resize((size_t)size);
        file.read((char*)(&buffer[0]), size);
    }
    else buffer.clear();

    unsigned long w, h;
    int error = decodePNG(image, w, h, buffer.empty() ? 0 : &buffer[0], (unsigned long)buffer.size());
    if (error != 0) {
        char info[30];
        sprintf(info, "error:%i", error);
        util::debug_print(info);
    }

    u8 *gpusrc = (u8*) linearAlloc(w*h * 4);
    u8 *img_fix = (u8*)linearAlloc(w*h * 4);

    // GX_DisplayTransfer needs input buffer in linear RAM
    u8* src = &image[0]; u8 *dst = gpusrc;
    

    // lodepng outputs big endian rgba so we need to convert
    for (int i = 0; i< w * h; i++) {
        int r = *src++;
        int g = *src++;
        int b = *src++;
        int a = *src++;

        *dst++ = a;
        *dst++ = b;
        *dst++ = g;
        *dst++ = r;
    }

    /* Upload to shader */
    
    C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);

    // Initialize the render target
    C3D_RenderTarget* target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
    C3D_RenderTargetSetClear(target, C3D_CLEAR_ALL, CLEAR_COLOR, 0);
    C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);

    static const util::vertex vertex_list[] =
    {
        // First face (PZ)
        // First triangle
        { { -0.5f, -0.5f, +0.5f },{ 0.0f, 0.0f },{ 0.0f, 0.0f, +1.0f } },
        { { +0.5f, -0.5f, +0.5f },{ 1.0f, 0.0f },{ 0.0f, 0.0f, +1.0f } },
        { { +0.5f, +0.5f, +0.5f },{ 1.0f, 1.0f },{ 0.0f, 0.0f, +1.0f } },
        // Second triangle
        { { +0.5f, +0.5f, +0.5f },{ 1.0f, 1.0f },{ 0.0f, 0.0f, +1.0f } },
        { { -0.5f, +0.5f, +0.5f },{ 0.0f, 1.0f },{ 0.0f, 0.0f, +1.0f } },
        { { -0.5f, -0.5f, +0.5f },{ 0.0f, 0.0f },{ 0.0f, 0.0f, +1.0f } }
    };

    DVLB_s* vshader_dvlb;
    shaderProgram_s program;
    int uLoc_projection, uLoc_modelView;
    int uLoc_lightVec, uLoc_lightHalfVec, uLoc_lightClr, uLoc_material;
    C3D_Mtx projection;
    C3D_Mtx material =
    {
        {
            { { 0.0f, 0.2f, 0.2f, 0.2f } }, // Ambient
            { { 0.0f, 0.4f, 0.4f, 0.4f } }, // Diffuse
            { { 0.0f, 0.8f, 0.8f, 0.8f } }, // Specular
            { { 1.0f, 0.0f, 0.0f, 0.0f } }, // Emission
        }
    };

    // Load the vertex shader, create a shader program and bind it
    vshader_dvlb = DVLB_ParseFile((u32*)vshader_shbin, vshader_shbin_size);
    shaderProgramInit(&program);
    shaderProgramSetVsh(&program, &vshader_dvlb->DVLE[0]);
    C3D_BindProgram(&program);

    uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection");
    uLoc_modelView = shaderInstanceGetUniformLocation(program.vertexShader, "modelView");
    uLoc_lightVec = shaderInstanceGetUniformLocation(program.vertexShader, "lightVec");
    uLoc_lightHalfVec = shaderInstanceGetUniformLocation(program.vertexShader, "lightHalfVec");
    uLoc_lightClr = shaderInstanceGetUniformLocation(program.vertexShader, "lightClr");
    uLoc_material = shaderInstanceGetUniformLocation(program.vertexShader, "material");

    // Configure attributes for use with the vertex shader
    C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
    AttrInfo_Init(attrInfo);
    AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position
    AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=texcoord
    AttrInfo_AddLoader(attrInfo, 2, GPU_FLOAT, 3); // v2=normal

    // Compute the projection matrix
    Mtx_PerspTilt(&projection, C3D_AngleFromDegrees(80.0f), C3D_AspectRatioTop, 0.01f, 1000.0f, false);

    // Create the VBO (vertex buffer object)
    void* vbo_data = linearAlloc(sizeof(vertex_list));
    memcpy(vbo_data, vertex_list, sizeof(vertex_list));

    // Configure buffers
    C3D_BufInfo* bufInfo = C3D_GetBufInfo();
    BufInfo_Init(bufInfo);
    BufInfo_Add(bufInfo, vbo_data, sizeof(util::vertex), 3, 0x210);

    C3D_Tex png_texture;
    C3D_TexInit(&png_texture, w, h, GPU_TEXCOLOR::GPU_RGBA8);

    // Load the texture and bind it to the first texture unit
    GSPGPU_FlushDataCache(gpusrc, w*h * 4);
    C3D_SafeDisplayTransfer((u32*)gpusrc, GX_BUFFER_DIM(w, h), (u32*)img_fix, GX_BUFFER_DIM(w, h), TEXTURE_TRANSFER_FLAGS);
    gspWaitForPPF();

    
    C3D_TexUpload(&png_texture, &img_fix[0]);
    C3D_TexSetFilter(&png_texture, GPU_LINEAR, GPU_NEAREST);
    C3D_TexBind(0, &png_texture);

    // Configure the first fragment shading substage to blend the texture color with
    // the vertex color (calculated by the vertex shader using a lighting algorithm)
    // See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
    C3D_TexEnv* env = C3D_GetTexEnv(0);
    C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0);
    C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
    C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE);

    while (true) {

        C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
        C3D_FrameDrawOn(target);
        
        C3D_Mtx modelView;
        Mtx_Identity(&modelView);
        Mtx_Translate(&modelView, 0.0, 0.0, -2.0, true);

        // Update the uniforms
        C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection);
        C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView);
        C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_material, &material);
        C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightVec, 0.0f, 0.0f, -1.0f, 0.0f);
        C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightHalfVec, 0.0f, 0.0f, -1.0f, 0.0f);
        C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr, 1.0f, 1.0f, 1.0f, 1.0f);

        // Draw the VBO
        C3D_DrawArrays(GPU_TRIANGLES, 0, sizeof(vertex_list) / sizeof(util::vertex));

        C3D_FrameEnd(0);

    }
 
  • Like
Reactions: jockep and bee395

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
  • Veho @ Veho:
    The fuuuuu---
  • Veho @ Veho:
    I thought it was an actual xBox at that price.
  • Sicklyboy @ Sicklyboy:
    I wanna grab a 360 Slim and a 360 E one of these days. Missed the boat of getting them at their lowest though, once they were discontinued. Could've got them for cheap back when I was a broke 20 something working at Target, but then again, I was a broke 20 something working at Target
  • Veho @ Veho:
    Being broke is no fun.
  • K3Nv2 @ K3Nv2:
    @Sicklyboy, $150 isn't that bad for a jtag slim on ebay
  • Veho @ Veho:
    I only wish it was actually playable.
  • Veho @ Veho:
    There's a guy on the Tube of You that makes playable mechanical arcade games out of Lego. This could work on the same principle.
  • Veho @ Veho:
    Just a couple of guys taking their manatee out for some fresh air, why you have to molest them?
  • Veho @ Veho:
    Stupid Chinese shop switched their shipping company and this one is slooooooow.
  • LeoTCK @ LeoTCK:
    STOP BUYING CHINESE CRAP THEN
  • LeoTCK @ LeoTCK:
    SUPPORT LOCAL PRODUCTS, MAKE REVOLUTION
  • LeoTCK @ LeoTCK:
    THEY KEEP REMOVING LOCAL SHIt AND REPLACING WItH INFERIOR CHINESE CRAP
  • LeoTCK @ LeoTCK:
    THATS WHY MY PARTNER CANT GET A GOOTWEAR HIS SIZE ANYMORE
  • LeoTCK @ LeoTCK:
    HE HAS BIG FOOT AND BIG DUCK
  • LeoTCK @ LeoTCK:
    d*ck i mean*
  • LeoTCK @ LeoTCK:
    lol
  • Veho @ Veho:
    Mkay.
  • Veho @ Veho:
    I just ordered another package from China just to spite you.
  • SylverReZ @ SylverReZ:
    Communism lol
  • SylverReZ @ SylverReZ:
    OUR products
  • The Real Jdbye @ The Real Jdbye:
    @LeoTCK actually good quality products are dying out because they can't compete with dropshipped chinese crap
    +1
    The Real Jdbye @ The Real Jdbye: @LeoTCK actually good quality products are dying out because they can't compete with dropshipped... +1