Question SDL2 Switch Development Woes

Discussion in 'Switch - Hacking & Homebrew' started by delete12345, Apr 17, 2018.

  1. delete12345
    OP

    delete12345 GBAtemp Advanced Fan

    Member
    566
    261
    Feb 27, 2010
    United States
    Taipei, Taiwan
    This thread will document the many challenges and difficulties in developing homebrew for the Nintendo Switch, using SDL2 library. Below is the table of contents of breakthroughs, small and large, that will redirect you to the relevant posts in this thread:

    Table of Contents:

    More posts will be added to the table of contents along the way when new findings in regards to making better SDL2 codes are posted.

    Please feel free to submit your own SDL2 breakthroughs to this thread, so everyone else can learn and share.
     
    Last edited by delete12345, Apr 22, 2018 at 9:39 PM
  2. delete12345
    OP

    delete12345 GBAtemp Advanced Fan

    Member
    566
    261
    Feb 27, 2010
    United States
    Taipei, Taiwan
    Original Post:

    Currently trying to figure out how to work with SDL2 at the moment. The SDL2 I'm using is from devkitpro, with the SDL2 fork for the Switch.

    Right now, the code will cause the program to crash on the Switch. And I'm trying to troubleshoot this.

    Code:
    #include <switch.h>
    
    #include <SDL.h>
    #include <SDL_ttf.h>
    
    int main(int argc, char* argv[]) {
        SDL_Init(SDL_INIT_EVERYTHING);
    
        /*gfxInitDefault();
        consoleInit(nullptr);*/
       
        //Switch screen size: 720p. Must set to full screen.
        SDL_Window* window = SDL_CreateWindow(nullptr, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_FULLSCREEN);
        if (!window)
            SDL_Quit();
        SDL_Renderer* renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_SOFTWARE);
        if (!renderer)
            SDL_Quit();
        SDL_Surface* windowSurface = SDL_GetWindowSurface(window);
    
        while (appletMainLoop()) {
            hidScanInput();
    
            u32 keyDown = hidKeysDown(CONTROLLER_P1_AUTO);
            if (keyDown & KEY_PLUS)
                break;
    
            SDL_RenderClear(renderer);
    
            /*gfxFlushBuffers();
            gfxSwapBuffers();
            gfxWaitForVsync();*/
    
            SDL_Delay(1);
        }
    
        SDL_FreeSurface(windowSurface);
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
    
        SDL_Quit();
    
        //gfxExit();
        return 0;
    }
    The commented code may be up for debate, because who knows at this point if the buffer swapping is done automatically by SDL2, or that I need to uncomment them. The crash is caused when it's attempting to initialize a surface, and then attempting to quit out of the application. But somehow, it's stuck. I don't know the cause, because from a glance, this code is just merely refreshing the screen to black, and polls whether the Plus button on the right Joycon is pressed or not. It shouldn't be getting stuck.

    If anyone knows how to troubleshoot this, I'll appreciate your help.


    Second Post:


    At least I can now see some output log messages. But I don't understand why it's not picking up Joycon buttons at the moment.

    The output message says:

    Hello world
    SDL EVENT: SDL_AUDIODEVICEADDED

    And then, no more SDL_Event for inputs from the Joycons.

    Does anyone know how to obtain the inputs from the Joycons using SDL2?

    Code:
    #include <switch.h>
    #include <stdio.h>
    
    #include <SDL2/SDL.h>
    #include <SDL2/SDL_events.h>
    #include <SDL2/SDL_ttf.h>
    
    //Copied / pasted from the SDL source.
    
    static void SDL_DebugPrintEvent(const SDL_Event *event)
    {
        printf("SDL EVENT: ");
    
        if ((event->type >= SDL_USEREVENT) && (event->type <= SDL_LASTEVENT)) {
            printf("SDL_USEREVENT");
            if (event->type > SDL_USEREVENT) {
                printf("+%u", ((uint) event->type) - SDL_USEREVENT);
            }
            printf(" (timestamp=%u windowid=%u code=%d data1=%p data2=%p)",
                (uint) event->user.timestamp, (uint) event->user.windowID,
                (int) event->user.code, event->user.data1, event->user.data2);
            return;
        }
    
        switch (event->type) {
    #define SDL_EVENT_CASE(x) case x: printf("%s", #x);
            SDL_EVENT_CASE(SDL_FIRSTEVENT) printf("(THIS IS PROBABLY A BUG!)"); break;
            SDL_EVENT_CASE(SDL_QUIT) printf("(timestamp=%u)", (uint) event->quit.timestamp); break;
            SDL_EVENT_CASE(SDL_APP_TERMINATING) break;
            SDL_EVENT_CASE(SDL_APP_LOWMEMORY) break;
            SDL_EVENT_CASE(SDL_APP_WILLENTERBACKGROUND) break;
            SDL_EVENT_CASE(SDL_APP_DIDENTERBACKGROUND) break;
            SDL_EVENT_CASE(SDL_APP_WILLENTERFOREGROUND) break;
            SDL_EVENT_CASE(SDL_APP_DIDENTERFOREGROUND) break;
            SDL_EVENT_CASE(SDL_KEYMAPCHANGED) break;
            SDL_EVENT_CASE(SDL_CLIPBOARDUPDATE) break;
            SDL_EVENT_CASE(SDL_RENDER_TARGETS_RESET) break;
            SDL_EVENT_CASE(SDL_RENDER_DEVICE_RESET) break;
    #undef SDL_EVENT_CASE
    
    #define SDL_EVENT_CASE(x) case x: printf("%s ", #x);
    
            SDL_EVENT_CASE(SDL_WINDOWEVENT)
                printf("(timestamp=%u windowid=%u event=", (uint) event->window.timestamp, (uint) event->window.windowID);
            switch (event->window.event) {
                case SDL_WINDOWEVENT_NONE: printf("none(THIS IS PROBABLY A BUG!)"); break;
    #define SDL_WINDOWEVENT_CASE(x) case x: printf("%s", #x); break
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_SHOWN);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_HIDDEN);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_EXPOSED);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MOVED);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_RESIZED);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_SIZE_CHANGED);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MINIMIZED);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MAXIMIZED);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_RESTORED);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_ENTER);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_LEAVE);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_FOCUS_GAINED);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_FOCUS_LOST);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_CLOSE);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_TAKE_FOCUS);
                    SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_HIT_TEST);
    #undef SDL_WINDOWEVENT_CASE
                default: printf("UNKNOWN(bug? fixme?)"); break;
            }
            printf(" data1=%d data2=%d)", (int) event->window.data1, (int) event->window.data2);
            break;
    
            SDL_EVENT_CASE(SDL_SYSWMEVENT)
                printf("(timestamp=%u)", (uint) event->syswm.timestamp);
            /* !!! FIXME: we don't delve further at the moment. */
            break;
    
    #define PRINT_KEY_EVENT(event) \
                printf("(timestamp=%u windowid=%u state=%s repeat=%s scancode=%u keycode=%u mod=%u)", \
                    (uint) event->key.timestamp, (uint) event->key.windowID, \
                    event->key.state == SDL_PRESSED ? "pressed" : "released", \
                    event->key.repeat ? "true" : "false", \
                    (uint) event->key.keysym.scancode, \
                    (uint) event->key.keysym.sym, \
                    (uint) event->key.keysym.mod)
            SDL_EVENT_CASE(SDL_KEYDOWN) PRINT_KEY_EVENT(event); break;
            SDL_EVENT_CASE(SDL_KEYUP) PRINT_KEY_EVENT(event); break;
    #undef PRINT_KEY_EVENT
    
            SDL_EVENT_CASE(SDL_TEXTEDITING)
                printf("(timestamp=%u windowid=%u text='%s' start=%d length=%d)",
                (uint) event->edit.timestamp, (uint) event->edit.windowID,
                    event->edit.text, (int) event->edit.start, (int) event->edit.length);
            break;
    
            SDL_EVENT_CASE(SDL_TEXTINPUT)
                printf("(timestamp=%u windowid=%u text='%s')", (uint) event->text.timestamp, (uint) event->text.windowID, event->text.text);
            break;
    
    
            SDL_EVENT_CASE(SDL_MOUSEMOTION)
                printf("(timestamp=%u windowid=%u which=%u state=%u x=%d y=%d xrel=%d yrel=%d)",
                (uint) event->motion.timestamp, (uint) event->motion.windowID,
                    (uint) event->motion.which, (uint) event->motion.state,
                    (int) event->motion.x, (int) event->motion.y,
                    (int) event->motion.xrel, (int) event->motion.yrel);
            break;
    
    #define PRINT_MBUTTON_EVENT(event) \
                printf("(timestamp=%u windowid=%u which=%u button=%u state=%s clicks=%u x=%d y=%d)", \
                        (uint) event->button.timestamp, (uint) event->button.windowID, \
                        (uint) event->button.which, (uint) event->button.button, \
                        event->button.state == SDL_PRESSED ? "pressed" : "released", \
                        (uint) event->button.clicks, (int) event->button.x, (int) event->button.y)
            SDL_EVENT_CASE(SDL_MOUSEBUTTONDOWN) PRINT_MBUTTON_EVENT(event); break;
            SDL_EVENT_CASE(SDL_MOUSEBUTTONUP) PRINT_MBUTTON_EVENT(event); break;
    #undef PRINT_MBUTTON_EVENT
    
    
            SDL_EVENT_CASE(SDL_MOUSEWHEEL)
                printf("(timestamp=%u windowid=%u which=%u x=%d y=%d direction=%s)",
                (uint) event->wheel.timestamp, (uint) event->wheel.windowID,
                    (uint) event->wheel.which, (int) event->wheel.x, (int) event->wheel.y,
                    event->wheel.direction == SDL_MOUSEWHEEL_NORMAL ? "normal" : "flipped");
            break;
    
            SDL_EVENT_CASE(SDL_JOYAXISMOTION)
                printf("(timestamp=%u which=%d axis=%u value=%d)",
                (uint) event->jaxis.timestamp, (int) event->jaxis.which,
                    (uint) event->jaxis.axis, (int) event->jaxis.value);
            break;
    
            SDL_EVENT_CASE(SDL_JOYBALLMOTION)
                printf("(timestamp=%u which=%d ball=%u xrel=%d yrel=%d)",
                (uint) event->jball.timestamp, (int) event->jball.which,
                    (uint) event->jball.ball, (int) event->jball.xrel, (int) event->jball.yrel);
            break;
    
            SDL_EVENT_CASE(SDL_JOYHATMOTION)
                printf("(timestamp=%u which=%d hat=%u value=%u)",
                (uint) event->jhat.timestamp, (int) event->jhat.which,
                    (uint) event->jhat.hat, (uint) event->jhat.value);
            break;
    
    #define PRINT_JBUTTON_EVENT(event) \
                printf("(timestamp=%u which=%d button=%u state=%s)", \
                    (uint) event->jbutton.timestamp, (int) event->jbutton.which, \
                    (uint) event->jbutton.button, event->jbutton.state == SDL_PRESSED ? "pressed" : "released")
            SDL_EVENT_CASE(SDL_JOYBUTTONDOWN) PRINT_JBUTTON_EVENT(event); break;
            SDL_EVENT_CASE(SDL_JOYBUTTONUP) PRINT_JBUTTON_EVENT(event); break;
    #undef PRINT_JBUTTON_EVENT
    
    #define PRINT_JOYDEV_EVENT(event) printf("(timestamp=%u which=%d)", (uint) event->jdevice.timestamp, (int) event->jdevice.which)
            SDL_EVENT_CASE(SDL_JOYDEVICEADDED) PRINT_JOYDEV_EVENT(event); break;
            SDL_EVENT_CASE(SDL_JOYDEVICEREMOVED) PRINT_JOYDEV_EVENT(event); break;
    #undef PRINT_JOYDEV_EVENT
    
            SDL_EVENT_CASE(SDL_CONTROLLERAXISMOTION)
                printf("(timestamp=%u which=%d axis=%u value=%d)",
                (uint) event->caxis.timestamp, (int) event->caxis.which,
                    (uint) event->caxis.axis, (int) event->caxis.value);
            break;
    
    #define PRINT_CBUTTON_EVENT(event) \
                printf("(timestamp=%u which=%d button=%u state=%s)", \
                    (uint) event->cbutton.timestamp, (int) event->cbutton.which, \
                    (uint) event->cbutton.button, event->cbutton.state == SDL_PRESSED ? "pressed" : "released")
            SDL_EVENT_CASE(SDL_CONTROLLERBUTTONDOWN) PRINT_CBUTTON_EVENT(event); break;
            SDL_EVENT_CASE(SDL_CONTROLLERBUTTONUP) PRINT_CBUTTON_EVENT(event); break;
    #undef PRINT_CBUTTON_EVENT
    
    #define PRINT_CONTROLLERDEV_EVENT(event) printf("(timestamp=%u which=%d)", (uint) event->cdevice.timestamp, (int) event->cdevice.which)
            SDL_EVENT_CASE(SDL_CONTROLLERDEVICEADDED) PRINT_CONTROLLERDEV_EVENT(event); break;
            SDL_EVENT_CASE(SDL_CONTROLLERDEVICEREMOVED) PRINT_CONTROLLERDEV_EVENT(event); break;
            SDL_EVENT_CASE(SDL_CONTROLLERDEVICEREMAPPED) PRINT_CONTROLLERDEV_EVENT(event); break;
    #undef PRINT_CONTROLLERDEV_EVENT
    
    #define PRINT_FINGER_EVENT(event) \
                printf("(timestamp=%u touchid=%lld fingerid=%lld x=%f y=%f dx=%f dy=%f pressure=%f)", \
                    (uint) event->tfinger.timestamp, (long long) event->tfinger.touchId, \
                    (long long) event->tfinger.fingerId, event->tfinger.x, event->tfinger.y, \
                    event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure)
            SDL_EVENT_CASE(SDL_FINGERDOWN) PRINT_FINGER_EVENT(event); break;
            SDL_EVENT_CASE(SDL_FINGERUP) PRINT_FINGER_EVENT(event); break;
            SDL_EVENT_CASE(SDL_FINGERMOTION) PRINT_FINGER_EVENT(event); break;
    #undef PRINT_FINGER_EVENT
    
    #define PRINT_DOLLAR_EVENT(event) \
                printf("(timestamp=%u touchid=%lld gestureid=%lld numfingers=%u error=%f x=%f y=%f)", \
                    (uint) event->dgesture.timestamp, (long long) event->dgesture.touchId, \
                    (long long) event->dgesture.gestureId, (uint) event->dgesture.numFingers, \
                    event->dgesture.error, event->dgesture.x, event->dgesture.y);
            SDL_EVENT_CASE(SDL_DOLLARGESTURE) PRINT_DOLLAR_EVENT(event); break;
            SDL_EVENT_CASE(SDL_DOLLARRECORD) PRINT_DOLLAR_EVENT(event); break;
    #undef PRINT_DOLLAR_EVENT
    
            SDL_EVENT_CASE(SDL_MULTIGESTURE)
                printf("(timestamp=%u touchid=%lld dtheta=%f ddist=%f x=%f y=%f numfingers=%u)",
                (uint) event->mgesture.timestamp, (long long) event->mgesture.touchId,
                    event->mgesture.dTheta, event->mgesture.dDist,
                    event->mgesture.x, event->mgesture.y, (uint) event->mgesture.numFingers);
            break;
    
    #define PRINT_DROP_EVENT(event) printf("(file='%s' timestamp=%u windowid=%u)", event->drop.file, (uint) event->drop.timestamp, (uint) event->drop.windowID)
            SDL_EVENT_CASE(SDL_DROPFILE) PRINT_DROP_EVENT(event); break;
            SDL_EVENT_CASE(SDL_DROPTEXT) PRINT_DROP_EVENT(event); break;
            SDL_EVENT_CASE(SDL_DROPBEGIN) PRINT_DROP_EVENT(event); break;
            SDL_EVENT_CASE(SDL_DROPCOMPLETE) PRINT_DROP_EVENT(event); break;
    #undef PRINT_DROP_EVENT
    
    #define PRINT_AUDIODEV_EVENT(event) printf("(timestamp=%u which=%u iscapture=%s)", (uint) event->adevice.timestamp, (uint) event->adevice.which, event->adevice.iscapture ? "true" : "false");
            SDL_EVENT_CASE(SDL_AUDIODEVICEADDED) PRINT_AUDIODEV_EVENT(event); break;
            SDL_EVENT_CASE(SDL_AUDIODEVICEREMOVED) PRINT_AUDIODEV_EVENT(event); break;
    #undef PRINT_AUDIODEV_EVENT
    
    #undef SDL_EVENT_CASE
    
            default:
                printf("UNKNOWN SDL EVENT #%u! (Bug? FIXME?)", (uint) event->type);
                break;
        }
    
        printf("\n");
    }
    
    
    //Actual code
    
    int main(int argc, char* argv[]) {
        gfxInitDefault();
        consoleInit(nullptr);
    
        SDL_Init(SDL_INIT_EVERYTHING);
    
        printf("Hello world");
    
        while (appletMainLoop()) {
            SDL_Event event;
            while (SDL_PollEvent(&event)) {
                SDL_DebugPrintEvent(&event);
            }
        }
    
        SDL_Quit();
    
        gfxExit();
        return 0;
    }
     
    Last edited by delete12345, Apr 22, 2018 at 4:35 AM
  3. laramie

    laramie GBAtemp Advanced Fan

    Member
    506
    163
    Dec 15, 2014
    United States
    I think you should double check you code, that if statement mainly...
     
    Ronhero likes this.
  4. delete12345
    OP

    delete12345 GBAtemp Advanced Fan

    Member
    566
    261
    Feb 27, 2010
    United States
    Taipei, Taiwan
    No worries, since that long if statement is copied directly from the SDL codebase.

    I figured out why the Switch keeps crashing.

    I should not be mixing <switch.h> related API functions and SDL2 functions together. Particularly, when initializing and setting up the video memory.

    gfxInitDefault() and consoleInit(NULL) both initializes the video memory, which SDL_InitSubSystem(SDL_INIT_VIDEO) would also overwrite the initializations, so these 2 things (switch.h and SDL2) conflict with each other.

    With that in mind, after commenting out gfxExit(), program now works.

    So, the main points to drive home is: Always use SDL2 only if you use at least 1 SDL2 API function. Always use <switch.h> only if you use at least 1 of the libnx functions.

    Working code. Now I need to figure out the inputs and joycon buttons.

    Code:
    #include <switch.h>
    #include <iostream>
    
    #include <SDL2/SDL.h>
    #include <SDL2/SDL_events.h>
    #include <SDL2/SDL_ttf.h>
    
    int main(int argc, char* argv[]) {
        //Do not use anything from <switch.h>
        //gfxInitDefault();
        //consoleInit(nullptr);
    
        SDL_Init(SDL_INIT_EVERYTHING);
       
        //Switch screen size: 720p. Must set to full screen.
        SDL_Window* window = SDL_CreateWindow(nullptr, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP);
        if (!window)
            SDL_Quit();
        SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
        if (!renderer)
            SDL_Quit();
        SDL_Surface* screen = SDL_GetWindowSurface(window);
        SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, screen);
    
        uint32_t* pixels = (uint32_t*) screen->pixels;
    
        SDL_SetRenderDrawColor(renderer, 33, 33, 128, 255);
        SDL_RenderClear(renderer);
        SDL_RenderPresent(renderer);
    
        while (appletMainLoop()) {
            bool flag = false;
            SDL_Event event;
            while (SDL_PollEvent(&event)) {
                switch (event.type) {
                    case SDL_KEYDOWN:
                        u32 key = event.key.keysym.sym;
                        u32 mod = event.key.keysym.mod;
                        std::cout << "Input: " << key << " " << mod << std::endl;
                        flag = true;
                        break;
                }
            }
            if (flag)
                break;
    
            pixels[23 * screen->pitch + 40] = 0x12345678;
    
            SDL_UpdateTexture(texture, nullptr, screen->pixels, screen->pitch);
    
            SDL_RenderClear(renderer);
            SDL_RenderCopy(renderer, texture, nullptr, nullptr);
            SDL_RenderPresent(renderer);
        }
    
        SDL_DestroyTexture(texture);
        SDL_FreeSurface(screen);
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
    
        //No libnx function calls.
        //gfxExit();
    
        SDL_Quit();
        return 0;
    }
    
     
    Last edited by delete12345, Apr 18, 2018 at 4:21 AM
  5. cpasjuste

    cpasjuste GBAtemp Fan

    Member
    488
    837
    Aug 27, 2015
    France
    Hi, you can deduct buttons from here : https://github.com/devkitPro/SDL/blob/switch-sdl2/src/joystick/switch/SDL_sysjoystick.c#L52 :
    - A = SDL button 0, B = 1, X = 2 .... You need to look for SDL joystick event too, not key (keyboard) events. You can find a sample here : https://github.com/devkitPro/SDL/blob/switch-sdl2/test/testswitch.c

    Also, you can/may use "switch.h", just don't use any (switch) gfx code.
     
    Last edited by cpasjuste, Apr 18, 2018 at 7:43 AM
  6. delete12345
    OP

    delete12345 GBAtemp Advanced Fan

    Member
    566
    261
    Feb 27, 2010
    United States
    Taipei, Taiwan
    Thank you. I was looking around the devkitpro SDL repository, and I was not able to find information in regards to inputs, video memory management, and how to port an SDL2 build to the Switch.

    Hopefully, there are more test codes coming.
     
  7. cpasjuste

    cpasjuste GBAtemp Fan

    Member
    488
    837
    Aug 27, 2015
    France
    There's no more test code to come, you can follow any SDL2 tutorial :P
     
  8. Ronhero

    Ronhero Too Weird to Live, Too Rare to Die

    Member
    3,209
    1,162
    Jun 28, 2014
    United States
    Arizona Bay
    Good to see you old friend :-D
     
    laramie likes this.
  9. delete12345
    OP

    delete12345 GBAtemp Advanced Fan

    Member
    566
    261
    Feb 27, 2010
    United States
    Taipei, Taiwan
    When using SDL2, what's the best method to print a "Hello world" sentence?

    Since, you can't use consoleInit() and gfxInitDefault() to set up the font rendering and the console output, I'm stuck wondering about this, and how to go about it.


    UPDATE:

    Found it! Somehow, the debugDevice_SVC is important.

    consoleDebugInit(debugDevice_SVC);

    And then I can choose whether to do this or not:

    stdout = stderr;

    It's optional.
     
    Last edited by delete12345, Apr 19, 2018 at 4:56 AM
  10. laramie

    laramie GBAtemp Advanced Fan

    Member
    506
    163
    Dec 15, 2014
    United States

    Yeah I figured, well good luck with whateverr it is you are doing, cheers!
     
  11. delete12345
    OP

    delete12345 GBAtemp Advanced Fan

    Member
    566
    261
    Feb 27, 2010
    United States
    Taipei, Taiwan
    So this is a milestone for me using SDL2.

    One of the hard parts in SDL2 development for the Switch, is how to load fonts.

    After scouring tons of Github source codes, I've finally figured out how to do this. Steps for you to follow:

    1. In your Makefile, at the very bottom, add the following:

      Code:
      # Add this if your font file type is a TrueType Collection
      %.ttc.o :    %.ttc
          @echo $(notdir $<)
          @$(bin2o)
      
      # Add this if your font file type is a TrueType Font
      %.ttf.o :    %.ttf
          @echo $(notdir $<)
          @$(bin2o)
      Essentially, the Makefile would compile all binary data types (those that are not in text format) into the NRO build.

    2. In your topmost header file (.h), add the following in the format given:

      Code:
      #include <[name of font file][replace periods and whitespaces with underscores][file format].h>
      If you want to use Times New Roman, and it's a TTC file, aptly named "times NeW RoNaN.ttc" on Windows, you will add:

      Code:
      #include <times_NeW_RoNaN_ttc.h>
      This includes case-sensitivity, typos, whitespaces and periods.

    3. In your CPP file, to use SDL2's SDL_ttf function call to load fonts, you do this:

      Code:
      TTF_Font* myFont = TTF_OpenFontRW(SDL_RWFromMem((void *) times_NeW_RoNaN_ttc, times_NeW_RoNaN_ttc_size), 1, 36);
      Note there are 2 variables, times_NeW_RoNaN_ttc and times_NeW_RoNaN_ttc_size. [font name]_size is a variable included when generating the [font name] header files.

    And there I go, I can now load fonts!

    I know there is another way to do this, and that is to load fonts by passing in a file path to said font file.

    I don't know how to make that work though, and I was fussing over this for 2 days, until I resorted to use the method given above.


    -----------


    The next step for me is to learn how to load a text file using the Makefile build method for the Switch.
     
    Last edited by delete12345, Apr 20, 2018 at 4:23 AM
  12. delete12345
    OP

    delete12345 GBAtemp Advanced Fan

    Member
    566
    261
    Feb 27, 2010
    United States
    Taipei, Taiwan
    I'm currently using Visual Studio 2017 to write code for an SDL2 app for Nintendo Switch, and I'm a heavily invested user who loves IntelliSense. Can't live without it. Some people expressed dissatisfaction and annoyance that I'm using Visual Studio on Windows to write Linux code, and I can sort of understand where they are coming from. But this is a need, not a want.

    There are times when I wanted to use IntelliSense to find POSIX standard functions. But because I'm on Windows 10, POSIX header files are not compatible with Windows, because Microsoft made a firm decision saying IntelliSense is not supposed to know anything about POSIX standard header files due to incompatibility with Windows. But also, it won't be until when the time comes where IntelliSense integrates with WSL moreso. Here, Microsoft did mention they haven't yet synchronized the include files from the WSL Linux system to Visual Studio 2017, so it may happen in the future. For now, it will be like this.

    The best way for me to get IntelliSense to show POSIX standard C headers and functions, is to run WSL, and do this inside WSL Bash:

    Code:
    cp -r /usr/include/ /mnt/c/posix/include
    This will copy the entire POSIX C header files to Windows 10. It's a whopping 25MB, so it will take a while to recursively copy all the files and folders.

    Then in my Visual Studio 2017 Project, I added C:\posix\include to the VC++ Directories > Includes Path in my project's Project Properties. IntelliSense will then be able to find the right function for use with the Nintendo Switch, and I won't have to be annoyed at Google searching the various POSIX C functions. I am, of course, not familiar with all POSIX-exclusive C functions, so having to look them up then writing it out is comparably more tedious than letting IntelliSense look it up for me and using TAB key to enter in the needed functions quickly.

    ----------------------

    Also important:

    Because when building SDL2 apps for Switch on Windows, due to an issue with libnx installed from the devkitpro-installer, version 2.2.1, it's not able to fetch the latest libnx at this point in time.

    So, in all SDL2 Makefiles on Windows, use the following LIBS flags and add/overwrite it in that Makefile:

    LIBS := -lSDL2_ttf `sdl2-config --libs` -L/mnt/c/devkitPro/portlibs/switch/lib -L/mnt/c/devkitPro/libnx/lib -L/mnt/c/devkitPro/portlibs/switch/lib -lfreetype -lbz2 -lpng16 -lz -lm -lnx -lz
     
    Last edited by delete12345, Apr 23, 2018 at 2:39 AM
  13. delete12345
    OP

    delete12345 GBAtemp Advanced Fan

    Member
    566
    261
    Feb 27, 2010
    United States
    Taipei, Taiwan
    Thanks to WinterMute, I now know how to actually use romfs in SDL2 build.
    1. The first thing I need is to install a pacman package called switch-tools. This is essentially a collection of tools and packages. One of the tools needed is the romfs packing tool, that packages whatever files you need to be added to the "romfs" as read-only files into your NRO builds. Without out, romfs would not work. It's on pacman right now.
    2. With that out of the way, I then follow the instructions with the provided switch examples when you install devkitPro libnx toolchains. The examples show how to use romfs.
    3. When building the NRO build, I need to make sure that in the build output logs, it says something like: 1>Writing C:/Users/delete12345/SDL2/romfs/myTextFile.txt to RomFS image...
    4. And then I should be able to use romfs as I wanted to.
    Since I'm now using romfs, all current Switch emulators will not work at this point in time.

    Still many challenges ahead...
     
    Last edited by delete12345, Apr 22, 2018 at 9:40 PM
Loading...