[Release] {beta} sf2dlib - Simple and Fast 2D library (using the GPU)

Discussion in '3DS - Homebrew Development and Emulators' started by xerpi, Mar 22, 2015.

  1. xerpi
    OP

    xerpi GBAtemp Regular

    Member
    167
    448
    Dec 25, 2011
    Barcelona
    Hi there, lately I've been coding a GPU accelerated 2D library for the Nintendo 3DS, on top of ctrulib. I've got to the point where it starts to be usable, so I think it's time to release it.
    This will benefit you if you want to code a 2D game/app/emulator, as you obviously will need to draw textures/images. Maybe software rendering is enough, but if you have a GPU out there, why don't you use it ? ;)

    DOCUMENTATION: http://xerpi.github.io/sf2dlib/html/sf2d_8h.html#func-members

    DOWNLOAD: https://github.com/xerpi/sf2dlib

    Precompiled portlibs: https://github.com/xerpi/3ds_portlibs/releases/tag/1

    If you need to load images, take a look at this lib: https://github.com/xerpi/sfillib

    Here there are the functions SF2D provides:
    Code:
    
    int sf2d_init();
    int sf2d_init_advanced(int gpucmd_size, int temppool_size);
    int sf2d_fini();
    
    void sf2d_set_3D(int enable);
    
    void sf2d_start_frame(gfxScreen_t screen, gfx3dSide_t side);
    void sf2d_end_frame();
    
    void sf2d_swapbuffers();
    void sf2d_set_vblank_wait(int enable);
    
    float sf2d_get_fps();
    
    void *sf2d_pool_malloc(u32 size);
    void *sf2d_pool_memalign(u32 size, u32 alignment);
    unsigned int sf2d_pool_space_free();
    void sf2d_pool_reset();
    
    void sf2d_set_clear_color(u32 color);
    
    void sf2d_draw_line(int x0, int y0, int x1, int y1, u32 color);
    void sf2d_draw_rectangle(int x, int y, int w, int h, u32 color);
    void sf2d_draw_rectangle_rotate(int x, int y, int w, int h, u32 color, float rad);
    
    sf2d_texture *sf2d_create_texture(int width, int height, GPU_TEXCOLOR pixel_format, sf2d_place place);
    void sf2d_free_texture(sf2d_texture *texture);
    
    void sf2d_fill_texture_from_RGBA8(sf2d_texture *dst, const void *rgba8, int source_w, int source_h);
    sf2d_texture *sf2d_create_texture_mem_RGBA8(const void *src_buffer, int src_w, int src_h, GPU_TEXCOLOR pixel_format, sf2d_place place);
    
    void sf2d_bind_texture(const sf2d_texture *texture, GPU_TEXUNIT unit);
    void sf2d_bind_texture_color(const sf2d_texture *texture, GPU_TEXUNIT unit, u32 color);
    
    void sf2d_draw_texture(const sf2d_texture *texture, int x, int y);
    void sf2d_draw_texture_rotate(const sf2d_texture *texture, int x, int y, float rad);
    void sf2d_draw_texture_part(const sf2d_texture *texture, int x, int y, int tex_x, int tex_y, int tex_w, int tex_h);
    void sf2d_draw_texture_scale(const sf2d_texture *texture, int x, int y, float x_scale, float y_scale);
    void sf2d_draw_texture_rotate_cut_scale(const sf2d_texture *texture, int x, int y, float rad, int tex_x, int tex_y, int tex_w, int tex_h, float x_scale, float y_scale);
    void sf2d_draw_texture_blend(const sf2d_texture *texture, int x, int y, u32 color);
    void sf2d_draw_texture_part_blend(const sf2d_texture *texture, int x, int y, int tex_x, int tex_y, int tex_w, int tex_h, u32 color);
    void sf2d_draw_texture_depth(const sf2d_texture *texture, int x, int y, signed short z);
    void sf2d_texture_tile32(sf2d_texture *texture);
    
    void sf2d_set_scissor_test(GPU_SCISSORMODE mode, u32 x, u32 y, u32 w, u32 h);
    
    gfxScreen_t sf2d_get_current_screen();
    gfx3dSide_t sf2d_get_current_side();
    
    The 2D coordinate system goes like this:
    Code:
    Top screen:
          X
      ---------->
      | (0,0)
      |  ______________________
    Y | |                      |
      | |                      |
      v |                      |
        |                      |
        |                      |
        |______________________|
                          (400, 240)
    Bottom screen:
            X
        ---------->
        | (0,0)
        |  ________________
      Y | |                |
        | |                |
        v |                |
          |                |
          |                |
          |________________|
                      (320, 240)
    
    And the skeleton of a program using this lib:
    Code:
    int main()
    {
        sf2d_init();
        sf2d_set_clear_color(RGBA8(0x00, 0x00, 0x00, 0x00));
    
        while (aptMainLoop()) {
    
            hidScanInput();
            if (hidKeysDown() & KEY_START) break;
    
            sf2d_start_frame(GFX_TOP, GFX_LEFT);
                //Draws a 100x100 yellow rectangle (255, 255, 00, 255) at (150, 70)
                sf2d_draw_rectangle(150, 70, 100, 100, RGBA8(0xFF, 0xFF, 0x00, 0xFF));
            sf2d_end_frame();
    
            sf2d_start_frame(GFX_BOTTOM, GFX_LEFT);
                //Draws a 70x100 blue rectangle (0, 0, 00, 255) at (120, 30)
                sf2d_draw_rectangle(120, 30, 70, 100, RGBA8(0x00, 0x00, 0xFF, 0xFF));
            sf2d_end_frame();
    
            sf2d_swapbuffers();
        }
    
        sf2d_fini();
        return 0;
    }
    A more complex sample: https://github.com/xerpi/sf2dlib/blob/master/sample/source/main.c

    Screenshot of Citra emulator running a sample using my lib:
    [​IMG]
     
    Last edited by xerpi, Nov 22, 2015


  2. Rinnegatamante

    Rinnegatamante GBAtemp Psycho!

    Member
    3,127
    3,270
    Nov 24, 2014
    Italy
    Bologna
    I was just starting converting lpp-3ds luaGraphics to ctrGL for GPU usage but this sounds much more better, very thanks for sharing this :D
     
    Margen67 and xerpi like this.
  3. xerpi
    OP

    xerpi GBAtemp Regular

    Member
    167
    448
    Dec 25, 2011
    Barcelona
    No problem :D Btw this will be a 2D-only lib, so if you want to do some 3D on lpp-3ds maybe it's not the best option.
    I'll add texture rotation/zoom support very soon!
     
  4. Rinnegatamante

    Rinnegatamante GBAtemp Psycho!

    Member
    3,127
    3,270
    Nov 24, 2014
    Italy
    Bologna
    luaGraphics module is only for 2D Graphics (probably for 3D i'll use another module name like lua3D).
     
    Margen67 likes this.
  5. xerpi
    OP

    xerpi GBAtemp Regular

    Member
    167
    448
    Dec 25, 2011
    Barcelona
    Cool! Btw switching from 2D to 3DS isn't hard, you mainly have to change the projection matrix (an uniform passed to the GPU) and maybe the shader.
     
  6. Rinnegatamante

    Rinnegatamante GBAtemp Psycho!

    Member
    3,127
    3,270
    Nov 24, 2014
    Italy
    Bologna
    Got an error during compilation, i'm using GPU folder from latest libctru revision:
    Code:
    c:/Users/Alessio/Desktop/lpp-3ds/source/include/sf2d/sf2d.c:48:58: error: request for member 'vertexShader' in something not a structure or union
      modelview_desc = shaderInstanceGetUniformLocation(shader.vertexShader, "modelview");
     
  7. filfat

    filfat Musician, Developer & Entrepreneur

    Member
    1,229
    858
    Nov 24, 2012
    This looks great, will use it to the simple UI lib im working on :D
     
    Margen67 likes this.
  8. xerpi
    OP

    xerpi GBAtemp Regular

    Member
    167
    448
    Dec 25, 2011
    Barcelona
    Weird, are you sure you are using the latest ctrulib version?
    I've shader defined as:
    Code:
    static shaderProgram_s shader;
    And if you look at the source of ctrulib: https://github.com/smealum/ctrulib/blob/master/libctru/include/3ds/gpu/shaderProgram.h#L28
    It has the vertexShader member.
     
  9. xerpi
    OP

    xerpi GBAtemp Regular

    Member
    167
    448
    Dec 25, 2011
    Barcelona
    Awesome! , hope it works well, and report any bugs :D
     
    Margen67 and filfat like this.
  10. filfat

    filfat Musician, Developer & Entrepreneur

    Member
    1,229
    858
    Nov 24, 2012
    Quick question, is 0,0 top left or bottom left?
     
  11. Rinnegatamante

    Rinnegatamante GBAtemp Psycho!

    Member
    3,127
    3,270
    Nov 24, 2014
    Italy
    Bologna
    xerpi likes this.
  12. xerpi
    OP

    xerpi GBAtemp Regular

    Member
    167
    448
    Dec 25, 2011
    Barcelona
    Ah yeah, forgot to say this, (0, 0) is top left.
    2D coordinates go like this:
    Code:
           X
     ---------->
     | (0,0)
     |   ______________________
    Y|  |                      |
     |  |                      |
     v  |                      |
        |                      |
        |                      |
        |______________________|
                           (400, 240)
    
     
    Margen67, Cid2mizard and filfat like this.
  13. filfat

    filfat Musician, Developer & Entrepreneur

    Member
    1,229
    858
    Nov 24, 2012
    Perfect, i will not have to change the cord system i currently use :)
     
  14. Rinnegatamante

    Rinnegatamante GBAtemp Psycho!

    Member
    3,127
    3,270
    Nov 24, 2014
    Italy
    Bologna
    What about right framebuffer support?
     
    Margen67 and filfat like this.
  15. xerpi
    OP

    xerpi GBAtemp Regular

    Member
    167
    448
    Dec 25, 2011
    Barcelona
    I'll work on it now :D
    And also bottom screen support.

    Btw I've just added CPU texture rotation support, check github.
     
    Margen67 and filfat like this.
  16. Rinnegatamante

    Rinnegatamante GBAtemp Psycho!

    Member
    3,127
    3,270
    Nov 24, 2014
    Italy
    Bologna
    Don't know why but now i get several errors in Citra and nothing blended on screens.
    [​IMG]
     
    filfat likes this.
  17. filfat

    filfat Musician, Developer & Entrepreneur

    Member
    1,229
    858
    Nov 24, 2012
    He's aware of the issue, we're currently talking on #3dsdev.
    :)
     
    Margen67 likes this.
  18. xerpi
    OP

    xerpi GBAtemp Regular

    Member
    167
    448
    Dec 25, 2011
    Barcelona
    Yes, this also happens with the ctrulib's GPU sample.
    Are you using my sf2d sample?
     
  19. Rinnegatamante

    Rinnegatamante GBAtemp Psycho!

    Member
    3,127
    3,270
    Nov 24, 2014
    Italy
    Bologna
    I just tried to blend two simple rectangles:

    Code:
    Graphics.init()
    while true do
        Graphics.initBlend(TOP_SCREEN)
        Graphics.fillRect(50,100,50,100,Color.new(255,255,0,255))
        Graphics.termBlend()
        Graphics.initBlend(BOTTOM_SCREEN)
        Graphics.fillRect(70,120,100,120,Color.new(255,255,0,255))
        Graphics.termBlend()
    end
    where:
    Code:
    static int lua_init(lua_State *L) {
        int argc = lua_gettop(L);
        if (argc != 0) return luaL_error(L, "wrong number of arguments"); 
        sf2d_init();
        sf2d_set_clear_color(RGBA8(0x00, 0x00, 0x00, 0xFF));
        return 0;
    }
     
    static int lua_initblend(lua_State *L) {
        int argc = lua_gettop(L);
        if ((argc != 1) && (argc != 2))  return luaL_error(L, "wrong number of arguments");
        int screen = luaL_checkinteger(L,1);
        int side=0;
        if (argc == 2) side = luaL_checkinteger(L,2);
        gfxScreen_t my_screen;
        gfx3dSide_t eye;
        if (screen == 0) my_screen = GFX_TOP;
        else my_screen = GFX_BOTTOM;
        if (side == 0) eye = GFX_LEFT;
        else eye = GFX_RIGHT;
        sf2d_start_frame(my_screen,eye);
        return 0;
    }
     
    static int lua_rect(lua_State *L) {
        int argc = lua_gettop(L);
        if (argc != 5) return luaL_error(L, "wrong number of arguments");
        int x1 = luaL_checkinteger(L,1);
        int x2 = luaL_checkinteger(L,2);
        int y1 = luaL_checkinteger(L,3);
        int y2 = luaL_checkinteger(L,4);
        if (x2 < x1){
            int tmp = x2;
            x2 = x1;
            x1 = tmp;
        }
        if (y2 < y1){
            int tmp = y2;
            y2 = y1;
            y1 = tmp;
        }
        u32 color = luaL_checkinteger(L,5);
        sf2d_draw_rectangle(x1, y1, x2-x1, y2-y1, RGBA8((color >> 16) & 0xFF, (color >> 8) & 0xFF, (color) & 0xFF, (color >> 24) & 0xFF));
        return 0;
    }
     
    static int lua_termblend(lua_State *L) {
        int argc = lua_gettop(L);
        if (argc != 0) return luaL_error(L, "wrong number of arguments");
        sf2d_end_frame();
        return 0;
    }
     
  20. xerpi
    OP

    xerpi GBAtemp Regular

    Member
    167
    448
    Dec 25, 2011
    Barcelona

    I see what's wrong, you have to call sf2d_swapbuffers(); once after rendering, something like this:
    Code:
    sf2d_start_frame(GFX_TOP, GFX_LEFT);
        //Draw top
    sf2d_end_frame();
    sf2d_start_frame(GFX_BOTTOM, GFX_LEFT);
        //Draw bottom
    sf2d_end_frame();
    sf2d_swapbuffers();
     
    Margen67, Rinnegatamante and filfat like this.