xerpi / sftdlib

Simple and Fast Text Drawing library for the Nintendo 3DS
MIT License
30 stars 6 forks source link

What? Just What!? #23

Open Pecacheu opened 7 years ago

Pecacheu commented 7 years ago

This library is INSANELY UNSTABLE!

The sample works (often crashes or freezes though, especially after pressing HOME), but trying to do anything more than that causes all sorts of issues. The most common problem is the whole 3DS freezing.

I've done extensive testing with nearly every combination of different LIBCTRU modules and built-in C++ functions and headers to find out exactly which ones cause issues. The results are... almost everything does!

Basically anything regarding C++ strings or linearAlloc (or any kind of alloc, include C++ alloc) doesn't work. You'd think it's a memory problem, but new char[size] arrays of the same size work fine. Creating and printing an std::string works, but any string functions like .find or .substr instantly cause a crash. Making a bunch of strings also causes a crash. Even converting a string to a pointer and back can cause a crash. I've double and tipple checked that particular test to make sure that the pointer isn't NULL, and points to a valid string. I mean, how is that causing a crash!? Many LIBCTRU modules don't work. The apt module crashes or refuses to wake from sleep every once and a while. Network and audio modules are defiantly out. Instant crash there. The beloved console module doesn't work at all, so I had to re-write my error reporting code to use the very library that broke it, only to discover that it breaks more than just LIBCTRU modules. C++ templates and a lot of other C++11 or C++14 functionality causes a crash, somehow. Calling sf2d_start_frame twice in a row causes a crash. But wait... That's a problem with sf2d library, right? WRONG. Doesn't happen when this library isn't included/compiled. Most other external libraries cause a crash as well, particularly memory-intensive ones like audio/video libraries. (I tested with minimp3, libmad, ogg_vorbis, some H264 library, pnglib, my own compactbmp library, etc.) This probably stems from the fact that so much C++ functionality is broken, but the question is what could be causing that?

In addition to these tests, I tried them all over again, but with functions in different orders. For example, I ordered the init and exit functions for the LIBCTRU modules differently. This got the srv and os modules to work when they were init'ed in that order above sftdlib. But other than that, everything else is still broken. And pressing HOME then closing the screen causes the console to become unresponsive if you were calling aptRunLoop() in your main loop.

Need I remind you that ALL of these tests work flawlessly without this library. Well, not the camera module, but that never worked. And yes, I tried reinstalling DevKitARM. 3 times. And recompiled the latest LIBCTRU and Cirto3D from source, along with libsf2d and FreeType2 from portlibs, which took some effort to get working on Windows, but fortunately there's Cygwin.

Also, yes I'm using the library correctly. No compiler errors/warnings, no linking errors. Sample and SOME of my tests work fine for a while, then crash. So no, I can't be "using it wrong". It's just broken.

Tested on fully working (and mint-condition, if I do say so myself) O3DS 11.2.0-35U through SoundHax and MenuHax with latest Homebrew Launcher. I'll see I can pry my little brother's N3DS out of his hands so I can try that do, but I doubt it will help.

SonyUSA commented 7 years ago

This library hasn't been updated in yearrsss, it's not compatible with any current ASK. Stop using it :p

SonyUSA commented 7 years ago

Sorry, SDK. Dang auto correct.

xerpi commented 7 years ago

As @SonyUSA says, don't use this lib, use citro3d + your own Freetype wrapper using citro3d instead.

Pecacheu commented 7 years ago

Trying to make a new library based on this one's source and the FreeType documentation, but I don't really understand it... This is about as far as I've gotten. The character 'h' renders when I call the textDraw function, but it look corrupted and I don't know why.

#include "3dsfont.h"

#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
#include <cstring>

#define TEXTURE_SIZE 512

static FT_Library ftlib;

int fontInit() { return FT_Init_FreeType(&ftlib); }
void fontExit() { FT_Done_FreeType(ftlib); }

char *__cstr(string str) {
    char *cstr = new char[str.length()+1];
    strcpy(cstr, str.c_str()); return cstr;
}

static FT_Error face_req(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *face) {
    fontFace *font = (fontFace *)face_id;

    FT_Error err = FT_Err_Cannot_Open_Resource;

    if(font->file) err = FT_New_Face(library, __cstr(font->filename), 0, face);
    else err = FT_New_Memory_Face(library, (const FT_Byte *)font->font_buffer, font->buffer_size, 0, face);

    return err;
}

fontFace *fontLoadFile(string fname) {
    FT_Error err; fontFace *font = new fontFace;
    font->file = true; font->filename = fname;

    err = FTC_Manager_New(ftlib, 0, 0, 0, &face_req, NULL, &font->ftcmanager);
    if(err != FT_Err_Ok) return NULL;

    FTC_CMapCache_New(font->ftcmanager, &font->cmapcache);
    FTC_ImageCache_New(font->ftcmanager, &font->imagecache);

    //font->tex_atlas = atlas_create(ATLAS_DEFAULT_S, ATLAS_DEFAULT_S, TEXFMT_RGBA8, SF2D_PLACE_RAM);
    font->tex = sf2d_create_texture(TEXTURE_SIZE, TEXTURE_SIZE, TEXFMT_RGBA8, SF2D_PLACE_RAM);
    sf2d_texture_set_params(font->tex, GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR));
    sf2d_texture_tile32(font->tex);

    return font;
}

fontFace *fontLoad(const void *buffer, unsigned int size) {
    FT_Error err; fontFace *font = new fontFace;

    font->file = false;
    font->font_buffer = buffer;
    font->buffer_size = size;

    err = FTC_Manager_New(ftlib, 0, 0, 0, &face_req, NULL, &font->ftcmanager);
    if(err != FT_Err_Ok) return NULL;

    FTC_CMapCache_New(font->ftcmanager, &font->cmapcache);
    FTC_ImageCache_New(font->ftcmanager, &font->imagecache);

    //font->tex_atlas = atlas_create(ATLAS_DEFAULT_S, ATLAS_DEFAULT_S, TEXFMT_RGBA8, SF2D_PLACE_RAM);
    font->tex = sf2d_create_texture(TEXTURE_SIZE, TEXTURE_SIZE, TEXFMT_RGBA8, SF2D_PLACE_RAM);
    sf2d_texture_set_params(font->tex, GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR));
    sf2d_texture_tile32(font->tex);

    return font;
}

void fontFree(fontFace *font) {
    if(font) {
        FTC_FaceID face_id = (FTC_FaceID)font;
        FTC_Manager_RemoveFaceID(font->ftcmanager, face_id);
        FTC_Manager_Done(font->ftcmanager);
        //atlas_free(font->tex_atlas);
        free(font);
    }
}
void textDraw(fontFace *font, u16 x, u16 y, u32 color, u16 size, u16 lineWidth, string text) {
    FTC_FaceID face_id = (FTC_FaceID)font; FT_Face face;
    FTC_Manager_LookupFace(font->ftcmanager, face_id, &face);

    FT_Int charmap_index = FT_Get_Charmap_Index(face->charmap);

    FT_BitmapGlyph glyph;
    FT_Bool use_kerning = FT_HAS_KERNING(face);
    FT_UInt glyph_index;//, previous = 0;
    //int pen_x = x, pen_y = y + size;

    FTC_ScalerRec scaler;
    scaler.face_id = face_id;
    scaler.width = size;
    scaler.height = size;
    scaler.pixel = 1;

    glyph_index = FTC_CMapCache_Lookup(font->cmapcache, (FTC_FaceID)font, charmap_index, 'h');
    FTC_ImageCache_LookupScaler(font->imagecache, &scaler, (FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL), glyph_index, (FT_Glyph*)&glyph, NULL);

    FT_Bitmap *bitmap = &glyph->bitmap;
    u16 tW = bitmap->width, tH = bitmap->rows;
    //u16 *buffer = new u16[tW*tH*4];

    sf2d_texture *tex = sf2d_create_texture(tH, tW, TEXFMT_RGBA8, SF2D_PLACE_RAM);
    sf2d_texture_set_params(tex, GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR));
    sf2d_texture_tile32(tex);

    for(u16 j=0,k=0; j<tH; j++) {
        for(k=0; k<tW; k++) {
            if(bitmap->pixel_mode == FT_PIXEL_MODE_MONO) {
                sf2d_set_pixel(tex, k, j, __builtin_bswap32((u32)((bitmap->buffer[j*bitmap->pitch + k/8] & (1 << (7 - k%8))) ? 0xFF : 0)));
            } else {
                sf2d_set_pixel(tex, k, j, __builtin_bswap32((u32)(0x00FFFFFF | (bitmap->buffer[j*bitmap->pitch + k] << 24))));
            }
        }
    }

    sf2d_draw_texture_blend(tex, x, y, color);

    sf2d_free_texture(tex);

    //sf2d_draw_texture_part_scale_blend(font->tex_atlas->tex, pen_x + bitmap_left * scale,
    //pen_y - bitmap_top * scale, rect.x, rect.y, rect.w, rect.h, scale, scale, color);

    //if(!addGlyph(font->tex_atlas, glyph_index, (FT_BitmapGlyph)glyph, size)) continue;
}

The Header File:

#include <3ds.h>
#include <string>
#include "../libsf2d/sf2d.h"
#include <ft2build.h>
#include FT_CACHE_H
#include FT_FREETYPE_H

using namespace std;

#ifndef LIB_3DSFONT_H
#define LIB_3DSFONT_H

struct fontFace {
    bool file;
    string filename;
    const void *font_buffer;
    unsigned int buffer_size;
    FTC_Manager ftcmanager;
    FTC_CMapCache cmapcache;
    FTC_ImageCache imagecache;
    sf2d_texture *tex;
};

int fontInit();
void fontExit();

fontFace *fontLoadFile(string fname);
fontFace *fontLoad(const void *buffer, unsigned int size);
void fontFree(fontFace *font);

void textDraw(fontFace *font, u16 x, u16 y, u32 color, u16 size, u16 lineWidth, string text);
//u16 textGetWidth(fontFace *font, u16 size, string text);
//void textGetSize(u16 *width, u16 *height, fontFace *font, u16 size, u16 lineWidth, string text);

#endif

Output on a blue background: img_3729 The font I'm trying to use is Open Sans Light from Google Fonts, if that makes a difference.

SonyUSA commented 7 years ago

I put the solution to corrupted glyphs on github somewhere... basically you gotta render every character as your largest font for 1 frame because of a bug that will try to upscale, to ill effect, any glyph that had already been rendered at a smaller size.

Pecacheu commented 7 years ago

BTW I fixed my problem. It turns out I was just making my textures and buffers all the wrong size! The only other problem I had is that it doesn't render spaces. I solved that by just replacing them with 'i' characters (roughly the same width in most fonts) and not drawing them.

I'll post the new library to my GitHub shortly.