Last active
May 20, 2025 18:30
-
-
Save NAEL2XD/be1593607fe8de6f59d7e9a138aedaac to your computer and use it in GitHub Desktop.
3DS: Cool Utils!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <3ds.h> | |
| #include <citro2d.h> | |
| // Prework those things. | |
| // Text Functions | |
| C2D_Text renderText; | |
| C2D_Font defaultFont; | |
| C2D_TextBuf g_staticBuf; | |
| u32 borderColor; | |
| u32 textColor; | |
| C3D_RenderTarget* pos[2]; | |
| // Custom Vars | |
| u64 oldTime = 0; | |
| touchPosition touch; | |
| bool initialized = false; | |
| // If the x variable is -1, then it will be set to middle. | |
| float centerX(float xCheck, C2D_Text text, float size) { | |
| return (int)xCheck == -1 ? (-(text.width * size) / 2) + 200 : xCheck; | |
| } | |
| void UTILS_Init() { | |
| if (initialized) return; | |
| // Initializes Citro2D | |
| C2D_Init(C2D_DEFAULT_MAX_OBJECTS); | |
| C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); | |
| C2D_Prepare(); | |
| pos[0] = C2D_CreateScreenTarget(GFX_TOP, GFX_LEFT); | |
| pos[1] = C2D_CreateScreenTarget(GFX_BOTTOM, GFX_LEFT); | |
| // TEXT | |
| defaultFont = C2D_FontLoadSystem(CFG_REGION_USA); | |
| g_staticBuf = C2D_TextBufNew(4096); | |
| borderColor = C2D_Color32(0, 0, 0, 170); | |
| textColor = C2D_Color32(255, 255, 255, 255); | |
| // Initializes stuff | |
| gfxInitDefault(); | |
| romfsInit(); | |
| cfguInit(); | |
| newsInit(); | |
| // TIME | |
| oldTime = osGetTime(); | |
| initialized = true; | |
| } | |
| void UTILS_Exit() { | |
| if (!initialized) return; | |
| C2D_Fini(); | |
| C3D_Fini(); | |
| newsExit(); | |
| cfguExit(); | |
| romfsExit(); | |
| initialized = false; | |
| } | |
| bool UTILS_SCREEN_renderBothScreenUsingFuncs(bool (*func1)(), bool (*func2)()) { | |
| bool exit; | |
| C3D_FrameBegin(C3D_FRAME_SYNCDRAW); | |
| for (int i = 0; i < 2; i++) { | |
| C2D_TargetClear(pos[i], C2D_Color32(60, 60, 60, 0xFF)); | |
| C2D_SceneBegin(pos[i]); | |
| exit = i == 0 ? func1() : func2(); | |
| if (exit) break; | |
| } | |
| C3D_FrameEnd(0); | |
| return exit; | |
| } | |
| void UTILS_TEXT_renderBorderText(const char *text, float x, float y, float borderSize, float size, C2D_Font font) { | |
| // Clear and Parse to make text work. | |
| C2D_TextBufClear(g_staticBuf); | |
| C2D_TextFontParse(&renderText, font ? font : defaultFont, g_staticBuf, text); | |
| C2D_TextOptimize(&renderText); | |
| // Center X | |
| x = centerX(x, renderText, size); | |
| // Do the trick. | |
| int pos[8][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}, {1, 0}, {-1, 0}, {0, 1}, {0, -1}}; | |
| for (int i = 0; i < 8; i++) { | |
| float finalMult = borderSize * size; | |
| C2D_DrawText(&renderText, C2D_WithColor, x + (pos[i][0] * finalMult), y + (pos[i][1] * finalMult), 0.5f, size, size, borderColor); | |
| } | |
| C2D_DrawText(&renderText, C2D_WithColor, x, y, 0.5f, size, size, textColor); | |
| } | |
| void UTILS_TEXT_quickRenderText(const char *text, float x, float y, u32 col, float size, C2D_Font font) { | |
| // Clear and Parse to make text work. | |
| C2D_TextBufClear(g_staticBuf); | |
| C2D_TextFontParse(&renderText, font ? font : defaultFont, g_staticBuf, text); | |
| C2D_TextOptimize(&renderText); | |
| // Center X | |
| x = centerX(x, renderText, size); | |
| // Check col | |
| if (col == 0) col = C2D_Color32(255, 255, 255, 255); | |
| // Draw! | |
| C2D_DrawText(&renderText, C2D_WithColor, x, y, 0.5f, size, size, col); | |
| } | |
| u64 UTILS_OS_getRunningTime() { | |
| return osGetTime() - oldTime; | |
| } | |
| C2D_Image UTILS_IMAGE_loadImage(char *file) { | |
| C2D_SpriteSheet spriteSheet = C2D_SpriteSheetLoad(file); | |
| if (!spriteSheet) { | |
| printf("Failed to load sprite sheet: %s\n", file); | |
| return (C2D_Image){0}; // Return an empty image on failure | |
| } | |
| return C2D_SpriteSheetGetImage(spriteSheet, 0); | |
| } | |
| double UTILS_MATH_angleToRadians(double angle) { | |
| return angle * (M_PI / 180.0); | |
| } | |
| bool UTILS_BOOL_isTouchingImage(C2D_Image img, float x, float y, float size) { | |
| hidTouchRead(&touch); | |
| return (x < touch.px && x + img.tex->width > touch.px && y < touch.py && y + img.tex->height > touch.py); | |
| } | |
| bool UTILS_BOOL_isTouchingHitbox(float x, float y, float width, float height) { | |
| hidTouchRead(&touch); | |
| return (x < touch.px && x + width > touch.px && y < touch.py && y + height > touch.py); | |
| } | |
| char* UTILS_STRING_swkbdGetInputText() { // Return char pointer | |
| static char text[512]; | |
| SwkbdState swkbd; | |
| swkbdInit(&swkbd, SWKBD_TYPE_NORMAL, 1, -1); | |
| swkbdSetFeatures(&swkbd, SWKBD_MULTILINE | SWKBD_DARKEN_TOP_SCREEN | SWKBD_FIXED_WIDTH); | |
| swkbdSetHintText(&swkbd, "Enter Text Here."); | |
| swkbdSetInitialText(&swkbd, text); | |
| swkbdInputText(&swkbd, text, sizeof(text)); | |
| return text; | |
| } | |
| void UTILS_OS_popupError(const char* text) { | |
| errorConf errorCtx; | |
| errorInit(&errorCtx, ERROR_TEXT, CFG_LANGUAGE_EN); | |
| errorText(&errorCtx, text); | |
| errorCtx.homeButton = false; | |
| errorDisp(&errorCtx); | |
| } | |
| void UTILS_OS_sendNotification(const char* titleText, const char* descText) { | |
| // Convert strings to UTF-16 | |
| u16 title[128] = {0}; | |
| u16 message[1024] = {0}; | |
| // Convert ASCII to UTF-16 | |
| for (size_t i = 0; i < strlen(titleText); i++) title[i] = titleText[i]; | |
| for (size_t i = 0; i < strlen(descText); i++) message[i] = descText[i]; | |
| // Create notification | |
| NEWS_AddNotification(title, strlen(titleText) + 2, message, strlen(descText) + 2, NULL, 0, false); | |
| } | |
| const char* UTILS_IO_getContentFromFile(const char* filePath) { | |
| static char content[8192] = {0}; // Static buffer persists after return | |
| FILE* f = fopen(filePath, "r"); | |
| if (!f) { | |
| printf("File read failed: %s\n", filePath); | |
| content[0] = '\0'; // Ensure empty string | |
| return content; | |
| } | |
| size_t bytes_read = fread(content, 1, sizeof(content)-1, f); | |
| content[bytes_read] = '\0'; // Null-terminate | |
| fclose(f); | |
| return content; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef _utils_h_ | |
| #define _utils_h_ | |
| #include <3ds.h> | |
| #include <citro2d.h> | |
| /** | |
| Initializes `UTILS`, giving you useful functions. | |
| **/ | |
| void UTILS_Init(); | |
| /** | |
| Exits services being `Citro2D`, `Citro3D`, `news`, `cfgu` and `romfs`. | |
| */ | |
| void UTILS_Exit(); | |
| /** | |
| @brief Render both screens with both function. | |
| @param func1 1st function to render top screen. | |
| @param func2 2nd function to render bottom screen. | |
| @return A boolean variable that would be true if you want to exit or false to keep continuing. | |
| */ | |
| bool UTILS_SCREEN_renderBothScreenUsingFuncs(bool (*func1)(), bool (*func2)()); | |
| /** | |
| Renders a bordered text quickly, no `C2D_Text` required | |
| @param text String text to write as. | |
| @param x The x position to draw in. If `x` is set to `-1` then it will make the text go in middle. | |
| @param y The y position to draw in. | |
| @param borderSize Size for the border in pixels to draw. | |
| @param size Size for the text to draw. | |
| `NOTE` that `borderSize` will be multiplied by `size`! | |
| @param font *(Optional)* Font to use, can be NULL for default nintendo font. | |
| **/ | |
| void UTILS_TEXT_renderBorderText(const char *text, float x, float y, float borderSize, float size, C2D_Font font); | |
| /** | |
| Quickly renders a bordered text without having to use any special variables. | |
| @param text String text to write as. | |
| @param x The x position to draw in. If `x` is set to `-1` then it will make the text go in middle. | |
| @param y The y position to draw in. | |
| @param col u32 color to set as. Optional, can be `NULL` (will be white). | |
| @param size Size for the text to draw. NOTE that `borderSize` will be multiplied by `size`! | |
| @param font *(Optional)* Font to use, can be NULL for default nintendo font. | |
| **/ | |
| void UTILS_TEXT_quickRenderText(const char *text, float x, float y, u32 col, float size, C2D_Font font); | |
| /** | |
| @brief Gets the current time the application has ran. | |
| @return A u64 (float) variable by how many milliseconds it has been ran. | |
| **/ | |
| u64 UTILS_OS_getRunningTime(); | |
| /** | |
| Loads an image without having to use special properties (like `C2D_SpriteSheet`) | |
| ### ~~You will need to initialize ROMFS using `romfsInit()` next to `gfxInitDefault()`!!~~ | |
| Edit (20/25/2025): You don't need this anymore because the UTILS does it for you. | |
| @param file The file name to load in romfs, make sure the image is a .t3x! Example: `romfs:/image.t3x` | |
| @return The image variable stored in there. | |
| **/ | |
| C2D_Image UTILS_IMAGE_loadImage(char *file); | |
| /** | |
| @brief Returns converted angle to radians. Also the same as [this](https://www.rapidtables.com/convert/number/degrees-to-radians.html). | |
| @param angle The angle to convert to radians. | |
| @return The converted radian. | |
| **/ | |
| double UTILS_MATH_angleToRadians(double angle); | |
| /** | |
| @brief Returns whatever if it's touching the image or not in the bottom screen. | |
| @param img The image to use and check if it's touching. | |
| @param x The X Position of the image. | |
| @param y The Y Position of the image. | |
| @param size The Size of the image. | |
| @return `true` if it collides and is touching the image, `false` otherwise. | |
| **/ | |
| bool UTILS_BOOL_isTouchingImage(C2D_Image img, float x, float y, float size); | |
| /** | |
| @brief Same as `UTILS_BOOL_isTouchingImage` but it's a hitbox instead. | |
| Returns whatever if it's touching the hitbox or not in the bottom screen. | |
| @param x The X Position of the hitbox. | |
| @param y The Y Position of the hitbox. | |
| @param width The Width of the hitbox. | |
| @param height The Height of the hitbox. | |
| @return `true` if it collides and is touching the hitbox, `false` otherwise. | |
| **/ | |
| bool UTILS_BOOL_isTouchingHitbox(float x, float y, float width, float height); | |
| /** | |
| @brief Reads the input text from user and returns the char result. | |
| @return Char String with text inputted to user. | |
| **/ | |
| char* UTILS_STRING_swkbdGetInputText(); | |
| /** | |
| @brief Displays a blocking error popup with custom text | |
| #### Features: | |
| - Disables home button while active | |
| - Uses system error dialog style | |
| - Blocks execution until dismissed | |
| - Auto-wraps long text | |
| @param text Error message to display (ASCII). Supports newlines with '\n'. | |
| Max ~2000 chars (libctru limit). UTF-8 not supported. | |
| @note Requires error service (automatically initialized) | |
| @warning Avoid special characters - use basic ASCII only | |
| */ | |
| void UTILS_OS_popupError(const char* text); | |
| /** | |
| @brief Sends a notification to HOME Menu | |
| #### Features: | |
| - Shows in Notifications (blue LED blinks) | |
| - Appears under "Nintendo 3DS" sender | |
| - No icon/image attached | |
| - Automatically encodes to UTF-16 | |
| @param titleText Notification title (ASCII, max 128 chars) | |
| @param descText Notification body (ASCII, max 1024 chars) | |
| @note Requires news service (auto-init/shutdown) | |
| @warning Title truncates at 128 chars, description at 1024 | |
| */ | |
| void UTILS_OS_sendNotification(const char* titleText, const char* descText); | |
| /** | |
| @brief Reads file contents into a static buffer | |
| @param filePath Path to file (e.g. "romfs:/text.txt") | |
| @return const char* - Pointer to null-terminated file contents. | |
| WARNING: Buffer is reused between calls! Copy immediately. | |
| Returns empty string "" on failure. | |
| @note Security Considerations: | |
| - Buffer size fixed at 8191 bytes + null terminator | |
| - Subsequent calls overwrite previous content | |
| - Not thread-safe | |
| - Limited to ASCII/text files | |
| @warning MAX FILE SIZE: 8191 bytes. Larger files will be truncated. | |
| Returned pointer becomes invalid on next function call! | |
| */ | |
| const char* UTILS_IO_getContentFromFile(const char* filePath); | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment