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

xerpi

Well-Known Member
OP
Member
Joined
Dec 25, 2011
Messages
212
Trophies
0
Age
26
Location
Barcelona
XP
1,230
Country
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:
v93z1eU.png
 
Last edited by xerpi,

xerpi

Well-Known Member
OP
Member
Joined
Dec 25, 2011
Messages
212
Trophies
0
Age
26
Location
Barcelona
XP
1,230
Country
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

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!
 

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,161
Trophies
0
Age
27
Location
Bologna
Website
rinnegatamante.it
XP
4,677
Country
Italy
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!

luaGraphics module is only for 2D Graphics (probably for 3D i'll use another module name like lua3D).
 
  • Like
Reactions: Margen67

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,161
Trophies
0
Age
27
Location
Bologna
Website
rinnegatamante.it
XP
4,677
Country
Italy
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");
 

xerpi

Well-Known Member
OP
Member
Joined
Dec 25, 2011
Messages
212
Trophies
0
Age
26
Location
Barcelona
XP
1,230
Country
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");

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.
 

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,161
Trophies
0
Age
27
Location
Bologna
Website
rinnegatamante.it
XP
4,677
Country
Italy
  • Like
Reactions: xerpi

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,161
Trophies
0
Age
27
Location
Bologna
Website
rinnegatamante.it
XP
4,677
Country
Italy
Yes, this also happens with the ctrulib's GPU sample.
Are you using my sf2d sample?

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;
}
 

xerpi

Well-Known Member
OP
Member
Joined
Dec 25, 2011
Messages
212
Trophies
0
Age
26
Location
Barcelona
XP
1,230
Country
I just tried to blend two simple rectangles:


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();
 
General chit-chat
Help Users
    KenniesNewName @ KenniesNewName: O'Food Chung Jung One Fish Sausage Snack 75g (15g x 5) (Crab) https://a.co/d/9BX9YqM lol crab bong