This commit is contained in:
zy 2024-12-29 19:19:38 +01:00
parent 714d9a8187
commit 5a116fa904
25 changed files with 3176 additions and 0 deletions

511
include/c2d/base.h Normal file
View file

@ -0,0 +1,511 @@
/**
* @file base.h
* @brief Basic citro2d initialization and drawing API
*/
#pragma once
#include <citro3d.h>
#include <tex3ds.h>
#define C2D_DEFAULT_MAX_OBJECTS 4096
#ifdef __cplusplus
#define C2D_CONSTEXPR constexpr
#define C2D_OPTIONAL(_x) =_x
#else
#define C2D_CONSTEXPR static inline
#define C2D_OPTIONAL(_x)
#endif
typedef struct
{
struct
{
float x, y, w, h;
} pos;
struct
{
float x, y;
} center;
float depth;
float angle;
} C2D_DrawParams;
typedef enum
{
C2D_TintSolid, ///< Plain solid tint color
C2D_TintMult, ///< Tint color multiplied by texture color
C2D_TintLuma, ///< Tint color multiplied by grayscale converted texture color
} C2D_TintMode;
typedef struct
{
u32 color; ///< RGB tint color and Alpha transparency
float blend; ///< Blending strength of the tint color (0.0~1.0)
} C2D_Tint;
typedef enum
{
C2D_TopLeft, ///< Top left corner
C2D_TopRight, ///< Top right corner
C2D_BotLeft, ///< Bottom left corner
C2D_BotRight, ///< Bottom right corner
} C2D_Corner;
typedef struct
{
C3D_Tex* tex;
const Tex3DS_SubTexture* subtex;
} C2D_Image;
typedef struct
{
C2D_Tint corners[4];
} C2D_ImageTint;
/** @defgroup Helper Helper functions
* @{
*/
/** @brief Clamps a value between bounds
* @param[in] x The value to clamp
* @param[in] min The lower bound
* @param[in] max The upper bound
* @returns The clamped value
*/
C2D_CONSTEXPR float C2D_Clamp(float x, float min, float max)
{
return x <= min ? min : x >= max ? max : x;
}
/** @brief Converts a float to u8
* @param[in] x Input value (0.0~1.0)
* @returns Output value (0~255)
*/
C2D_CONSTEXPR u8 C2D_FloatToU8(float x)
{
return (u8)(255.0f*C2D_Clamp(x, 0.0f, 1.0f)+0.5f);
}
/** @brief Builds a 32-bit RGBA color value
* @param[in] r Red component (0~255)
* @param[in] g Green component (0~255)
* @param[in] b Blue component (0~255)
* @param[in] a Alpha component (0~255)
* @returns The 32-bit RGBA color value
*/
C2D_CONSTEXPR u32 C2D_Color32(u8 r, u8 g, u8 b, u8 a)
{
return r | (g << (u32)8) | (b << (u32)16) | (a << (u32)24);
}
/** @brief Builds a 32-bit RGBA color value from float values
* @param[in] r Red component (0.0~1.0)
* @param[in] g Green component (0.0~1.0)
* @param[in] b Blue component (0.0~1.0)
* @param[in] a Alpha component (0.0~1.0)
* @returns The 32-bit RGBA color value
*/
C2D_CONSTEXPR u32 C2D_Color32f(float r, float g, float b, float a)
{
return C2D_Color32(C2D_FloatToU8(r),C2D_FloatToU8(g),C2D_FloatToU8(b),C2D_FloatToU8(a));
}
/** @brief Configures one corner of an image tint structure
* @param[in] tint Image tint structure
* @param[in] corner The corner of the image to tint
* @param[in] color RGB tint color and Alpha transparency
* @param[in] blend Blending strength of the tint color (0.0~1.0)
*/
static inline void C2D_SetImageTint(C2D_ImageTint* tint, C2D_Corner corner, u32 color, float blend)
{
tint->corners[corner].color = color;
tint->corners[corner].blend = blend;
}
/** @brief Configures an image tint structure with the specified tint parameters applied to all corners
* @param[in] tint Image tint structure
* @param[in] color RGB tint color and Alpha transparency
* @param[in] blend Blending strength of the tint color (0.0~1.0)
*/
static inline void C2D_PlainImageTint(C2D_ImageTint* tint, u32 color, float blend)
{
C2D_SetImageTint(tint, C2D_TopLeft, color, blend);
C2D_SetImageTint(tint, C2D_TopRight, color, blend);
C2D_SetImageTint(tint, C2D_BotLeft, color, blend);
C2D_SetImageTint(tint, C2D_BotRight, color, blend);
}
/** @brief Configures an image tint structure to just apply transparency to the image
* @param[in] tint Image tint structure
* @param[in] alpha Alpha transparency value to apply to the image
*/
static inline void C2D_AlphaImageTint(C2D_ImageTint* tint, float alpha)
{
C2D_PlainImageTint(tint, C2D_Color32f(0.0f, 0.0f, 0.0f, alpha), 0.0f);
}
/** @brief Configures an image tint structure with the specified tint parameters applied to the top side (e.g. for gradients)
* @param[in] tint Image tint structure
* @param[in] color RGB tint color and Alpha transparency
* @param[in] blend Blending strength of the tint color (0.0~1.0)
*/
static inline void C2D_TopImageTint(C2D_ImageTint* tint, u32 color, float blend)
{
C2D_SetImageTint(tint, C2D_TopLeft, color, blend);
C2D_SetImageTint(tint, C2D_TopRight, color, blend);
}
/** @brief Configures an image tint structure with the specified tint parameters applied to the bottom side (e.g. for gradients)
* @param[in] tint Image tint structure
* @param[in] color RGB tint color and Alpha transparency
* @param[in] blend Blending strength of the tint color (0.0~1.0)
*/
static inline void C2D_BottomImageTint(C2D_ImageTint* tint, u32 color, float blend)
{
C2D_SetImageTint(tint, C2D_BotLeft, color, blend);
C2D_SetImageTint(tint, C2D_BotRight, color, blend);
}
/** @brief Configures an image tint structure with the specified tint parameters applied to the left side (e.g. for gradients)
* @param[in] tint Image tint structure
* @param[in] color RGB tint color and Alpha transparency
* @param[in] blend Blending strength of the tint color (0.0~1.0)
*/
static inline void C2D_LeftImageTint(C2D_ImageTint* tint, u32 color, float blend)
{
C2D_SetImageTint(tint, C2D_TopLeft, color, blend);
C2D_SetImageTint(tint, C2D_BotLeft, color, blend);
}
/** @brief Configures an image tint structure with the specified tint parameters applied to the right side (e.g. for gradients)
* @param[in] tint Image tint structure
* @param[in] color RGB tint color and Alpha transparency
* @param[in] blend Blending strength of the tint color (0.0~1.0)
*/
static inline void C2D_RightImageTint(C2D_ImageTint* tint, u32 color, float blend)
{
C2D_SetImageTint(tint, C2D_TopRight, color, blend);
C2D_SetImageTint(tint, C2D_BotRight, color, blend);
}
/** @} */
/** @defgroup Base Basic functions
* @{
*/
/** @brief Initialize citro2d
* @param[in] maxObjects Maximum number of 2D objects that can be drawn per frame.
* @remarks Pass C2D_DEFAULT_MAX_OBJECTS as a starting point.
* @returns true on success, false on failure
*/
bool C2D_Init(size_t maxObjects);
/** @brief Deinitialize citro2d */
void C2D_Fini(void);
/** @brief Prepares the GPU for rendering 2D content
* @remarks This needs to be done only once in the program if citro2d is the sole user of the GPU.
*/
void C2D_Prepare(void);
/** @brief Ensures all 2D objects so far have been drawn */
void C2D_Flush(void);
/** @brief Configures the size of the 2D scene.
* @param[in] width The width of the scene, in pixels.
* @param[in] height The height of the scene, in pixels.
* @param[in] tilt Whether the scene is tilted like the 3DS's sideways screens.
*/
void C2D_SceneSize(u32 width, u32 height, bool tilt);
/** @brief Configures the size of the 2D scene to match that of the specified render target.
* @param[in] target Render target
*/
static inline void C2D_SceneTarget(C3D_RenderTarget* target)
{
C2D_SceneSize(target->frameBuf.width, target->frameBuf.height, target->linked);
}
/** @brief Resets the model transformation matrix. */
void C2D_ViewReset(void);
/** @brief Saves the current model transformation matrix.
* @param[out] matrix Pointer to save the current matrix to
*/
void C2D_ViewSave(C3D_Mtx* matrix);
/** @brief Restores a previously saved model transformation matrix.
* @param[in] matrix Pointer to matrix to restor
*/
void C2D_ViewRestore(const C3D_Mtx* matrix);
/** @brief Translates everything drawn via the model matrix.
* @param[in] x Translation in the x direction
* @param[in] y Translation in the y direction
*/
void C2D_ViewTranslate(float x, float y);
/** @brief Rotates everything drawn via the model matrix.
* @param[in] rotation Rotation in the counterclockwise direction in radians
*/
void C2D_ViewRotate(float rotation);
/** @brief Rotates everything drawn via the model matrix.
* @param[in] rotation Rotation in the counterclockwise direction in degrees
*/
static inline void C2D_ViewRotateDegrees(float rotation)
{
C2D_ViewRotate(C3D_AngleFromDegrees(rotation));
}
/** @brief Shears everything drawn via the model matrix.
* @param[in] x Shear factor in the x direction
* @param[in] y Shear factor in the y direction
*/
void C2D_ViewShear(float x, float y);
/** @brief Scales everything drawn via the model matrix.
* @param[in] x Scale factor in the x direction
* @param[in] y Scale factor in the y direction
*/
void C2D_ViewScale(float x, float y);
/** @brief Helper function to create a render target for a screen
* @param[in] screen Screen (GFX_TOP or GFX_BOTTOM)
* @param[in] side Side (GFX_LEFT or GFX_RIGHT)
* @returns citro3d render target object
*/
C3D_RenderTarget* C2D_CreateScreenTarget(gfxScreen_t screen, gfx3dSide_t side);
/** @brief Helper function to clear a rendertarget using the specified color
* @param[in] target Render target to clear
* @param[in] color 32-bit RGBA color value to fill the target with
*/
void C2D_TargetClear(C3D_RenderTarget* target, u32 color);
/** @brief Helper function to begin drawing a 2D scene on a render target
* @param[in] target Render target to draw the 2D scene to
*/
static inline void C2D_SceneBegin(C3D_RenderTarget* target)
{
C2D_Flush();
C3D_FrameDrawOn(target);
C2D_SceneTarget(target);
}
/** @} */
/** @defgroup Env Drawing environment functions
* @{
*/
/** @brief Configures the fading color
* @param[in] color 32-bit RGBA color value to be used as the fading color (0 by default)
* @remark The alpha component of the color is used as the strength of the fading color.
* If alpha is zero, the fading color has no effect. If it is the highest value,
* the rendered pixels will all have the fading color. Everything inbetween is
* rendered as a blend of the original pixel color and the fading color.
*/
bool C2D_Fade(u32 color);
/** @brief Configures the formula used to calculate the tinted texture color
* @param[in] mode Tinting mode
* @remark Texture tinting works by linearly interpolating between the regular texture color
* and the tinted texture color according to the blending strength parameter.
* This function can be used to change how the tinted texture color is precisely
* calculated, refer to \ref C2D_TintMode for a list of available tinting modes.
*/
bool C2D_SetTintMode(C2D_TintMode mode);
/** @} */
/** @defgroup Drawing Drawing functions
* @{
*/
/** @brief Draws an image using the GPU (variant accepting C2D_DrawParams)
* @param[in] img Handle of the image to draw
* @param[in] params Parameters with which to draw the image
* @param[in] tint Tint parameters to apply to the image (optional, can be null)
* @returns true on success, false on failure
*/
bool C2D_DrawImage(C2D_Image img, const C2D_DrawParams* params, const C2D_ImageTint* tint C2D_OPTIONAL(nullptr));
/** @brief Draws an image using the GPU (variant accepting position/scaling)
* @param[in] img Handle of the image to draw
* @param[in] x X coordinate at which to place the top left corner of the image
* @param[in] y Y coordinate at which to place the top left corner of the image
* @param[in] depth Depth value to draw the image with
* @param[in] tint Tint parameters to apply to the image (optional, can be null)
* @param[in] scaleX Horizontal scaling factor to apply to the image (optional, by default 1.0f); negative values apply a horizontal flip
* @param[in] scaleY Vertical scaling factor to apply to the image (optional, by default 1.0f); negative values apply a vertical flip
*/
static inline bool C2D_DrawImageAt(C2D_Image img, float x, float y, float depth,
const C2D_ImageTint* tint C2D_OPTIONAL(nullptr),
float scaleX C2D_OPTIONAL(1.0f), float scaleY C2D_OPTIONAL(1.0f))
{
C2D_DrawParams params =
{
{ x, y, scaleX*img.subtex->width, scaleY*img.subtex->height },
{ 0.0f, 0.0f },
depth, 0.0f
};
return C2D_DrawImage(img, &params, tint);
}
/** @brief Draws an image using the GPU (variant accepting position/scaling/rotation)
* @param[in] img Handle of the image to draw
* @param[in] x X coordinate at which to place the center of the image
* @param[in] y Y coordinate at which to place the center of the image
* @param[in] depth Depth value to draw the image with
* @param[in] angle Angle (in radians) to rotate the image by, counter-clockwise
* @param[in] tint Tint parameters to apply to the image (optional, can be null)
* @param[in] scaleX Horizontal scaling factor to apply to the image (optional, by default 1.0f); negative values apply a horizontal flip
* @param[in] scaleY Vertical scaling factor to apply to the image (optional, by default 1.0f); negative values apply a vertical flip
*/
static inline bool C2D_DrawImageAtRotated(C2D_Image img, float x, float y, float depth, float angle,
const C2D_ImageTint* tint C2D_OPTIONAL(nullptr),
float scaleX C2D_OPTIONAL(1.0f), float scaleY C2D_OPTIONAL(1.0f))
{
C2D_DrawParams params =
{
{ x, y, scaleX*img.subtex->width, scaleY*img.subtex->height },
{ (scaleX*img.subtex->width)/2.0f, (scaleY*img.subtex->height)/2.0f },
depth, angle
};
return C2D_DrawImage(img, &params, tint);
}
/** @brief Draws a plain triangle using the GPU
* @param[in] x0 X coordinate of the first vertex of the triangle
* @param[in] y0 Y coordinate of the first vertex of the triangle
* @param[in] clr0 32-bit RGBA color of the first vertex of the triangle
* @param[in] x1 X coordinate of the second vertex of the triangle
* @param[in] y1 Y coordinate of the second vertex of the triangle
* @param[in] clr1 32-bit RGBA color of the second vertex of the triangle
* @param[in] x2 X coordinate of the third vertex of the triangle
* @param[in] y2 Y coordinate of the third vertex of the triangle
* @param[in] clr2 32-bit RGBA color of the third vertex of the triangle
* @param[in] depth Depth value to draw the triangle with
*/
bool C2D_DrawTriangle(
float x0, float y0, u32 clr0,
float x1, float y1, u32 clr1,
float x2, float y2, u32 clr2,
float depth);
/** @brief Draws a plain line using the GPU
* @param[in] x0 X coordinate of the first vertex of the line
* @param[in] y0 Y coordinate of the first vertex of the line
* @param[in] clr0 32-bit RGBA color of the first vertex of the line
* @param[in] x1 X coordinate of the second vertex of the line
* @param[in] y1 Y coordinate of the second vertex of the line
* @param[in] clr1 32-bit RGBA color of the second vertex of the line
* @param[in] thickness Thickness, in pixels, of the line
* @param[in] depth Depth value to draw the line with
*/
bool C2D_DrawLine(
float x0, float y0, u32 clr0,
float x1, float y1, u32 clr1,
float thickness, float depth);
/** @brief Draws a plain rectangle using the GPU
* @param[in] x X coordinate of the top-left vertex of the rectangle
* @param[in] y Y coordinate of the top-left vertex of the rectangle
* @param[in] z Z coordinate (depth value) to draw the rectangle with
* @param[in] w Width of the rectangle
* @param[in] h Height of the rectangle
* @param[in] clr0 32-bit RGBA color of the top-left corner of the rectangle
* @param[in] clr1 32-bit RGBA color of the top-right corner of the rectangle
* @param[in] clr2 32-bit RGBA color of the bottom-left corner of the rectangle
* @param[in] clr3 32-bit RGBA color of the bottom-right corner of the rectangle
*/
bool C2D_DrawRectangle(
float x, float y, float z, float w, float h,
u32 clr0, u32 clr1, u32 clr2, u32 clr3);
/** @brief Draws a plain rectangle using the GPU (with a solid color)
* @param[in] x X coordinate of the top-left vertex of the rectangle
* @param[in] y Y coordinate of the top-left vertex of the rectangle
* @param[in] z Z coordinate (depth value) to draw the rectangle with
* @param[in] w Width of the rectangle
* @param[in] h Height of the rectangle
* @param[in] clr 32-bit RGBA color of the rectangle
*/
static inline bool C2D_DrawRectSolid(
float x, float y, float z, float w, float h,
u32 clr)
{
return C2D_DrawRectangle(x,y,z,w,h,clr,clr,clr,clr);
}
/** @brief Draws an ellipse using the GPU
* @param[in] x X coordinate of the top-left vertex of the ellipse
* @param[in] y Y coordinate of the top-left vertex of the ellipse
* @param[in] z Z coordinate (depth value) to draw the ellipse with
* @param[in] w Width of the ellipse
* @param[in] h Height of the ellipse
* @param[in] clr0 32-bit RGBA color of the top-left corner of the ellipse
* @param[in] clr1 32-bit RGBA color of the top-right corner of the ellipse
* @param[in] clr2 32-bit RGBA color of the bottom-left corner of the ellipse
* @param[in] clr3 32-bit RGBA color of the bottom-right corner of the ellipse
* @note Switching to and from "circle mode" internally requires an expensive state change. As such, the recommended usage of this feature is to draw all non-circular objects first, then draw all circular objects.
*/
bool C2D_DrawEllipse(
float x, float y, float z, float w, float h,
u32 clr0, u32 clr1, u32 clr2, u32 clr3);
/** @brief Draws a ellipse using the GPU (with a solid color)
* @param[in] x X coordinate of the top-left vertex of the ellipse
* @param[in] y Y coordinate of the top-left vertex of the ellipse
* @param[in] z Z coordinate (depth value) to draw the ellipse with
* @param[in] w Width of the ellipse
* @param[in] h Height of the ellipse
* @param[in] clr 32-bit RGBA color of the ellipse
* @note Switching to and from "circle mode" internally requires an expensive state change. As such, the recommended usage of this feature is to draw all non-circular objects first, then draw all circular objects.
*/
static inline bool C2D_DrawEllipseSolid(
float x, float y, float z, float w, float h,
u32 clr)
{
return C2D_DrawEllipse(x,y,z,w,h,clr,clr,clr,clr);
}
/** @brief Draws a circle (an ellipse with identical width and height) using the GPU
* @param[in] x X coordinate of the center of the circle
* @param[in] y Y coordinate of the center of the circle
* @param[in] z Z coordinate (depth value) to draw the ellipse with
* @param[in] radius Radius of the circle
* @param[in] clr0 32-bit RGBA color of the top-left corner of the ellipse
* @param[in] clr1 32-bit RGBA color of the top-right corner of the ellipse
* @param[in] clr2 32-bit RGBA color of the bottom-left corner of the ellipse
* @param[in] clr3 32-bit RGBA color of the bottom-right corner of the ellipse
* @note Switching to and from "circle mode" internally requires an expensive state change. As such, the recommended usage of this feature is to draw all non-circular objects first, then draw all circular objects.
*/
static inline bool C2D_DrawCircle(
float x, float y, float z, float radius,
u32 clr0, u32 clr1, u32 clr2, u32 clr3)
{
return C2D_DrawEllipse(
x - radius,y - radius,z,radius*2,radius*2,
clr0,clr1,clr2,clr3);
}
/** @brief Draws a circle (an ellipse with identical width and height) using the GPU (with a solid color)
* @param[in] x X coordinate of the center of the circle
* @param[in] y Y coordinate of the center of the circle
* @param[in] z Z coordinate (depth value) to draw the ellipse with
* @param[in] radius Radius of the circle
* @param[in] clr 32-bit RGBA color of the ellipse
* @note Switching to and from "circle mode" internally requires an expensive state change. As such, the recommended usage of this feature is to draw all non-circular objects first, then draw all circular objects.
*/
static inline bool C2D_DrawCircleSolid(
float x, float y, float z, float radius,
u32 clr)
{
return C2D_DrawCircle(x,y,z,radius,clr,clr,clr,clr);
}
/** @} */

95
include/c2d/font.h Normal file
View file

@ -0,0 +1,95 @@
/**
* @file font.h
* @brief Font loading and management
*/
#pragma once
#include "base.h"
struct C2D_Font_s;
typedef struct C2D_Font_s* C2D_Font;
/** @defgroup Font Font functions
* @{
*/
/** @brief Load a font from a file
* @param[in] filename Name of the font file (.bcfnt)
* @returns Font handle
* @retval NULL Error
*/
C2D_Font C2D_FontLoad(const char* filename);
/** @brief Load a font from memory
* @param[in] data Data to load
* @param[in] size Size of the data to load
* @returns Font handle
* @retval NULL Error
*/
C2D_Font C2D_FontLoadFromMem(const void* data, size_t size);
/** @brief Load a font from file descriptor
* @param[in] fd File descriptor used to load data
* @returns Font handle
* @retval NULL Error
*/
C2D_Font C2D_FontLoadFromFD(int fd);
/** @brief Load font from stdio file handle
* @param[in] f File handle used to load data
* @returns Font handle
* @retval NULL Error
*/
C2D_Font C2D_FontLoadFromHandle(FILE* f);
/** @brief Load corresponding font from system archive
* @param[in] region Region to get font from
* @returns Font handle
* @retval NULL Error
* @remark JPN, USA, EUR, and AUS all use the same font.
*/
C2D_Font C2D_FontLoadSystem(CFG_Region region);
/** @brief Free a font
* @param[in] font Font handle
*/
void C2D_FontFree(C2D_Font font);
/** @brief Set a font's texture filter
* @param[in] font Font handle
* @param[in] magFilter the magnification filter
* @param[in] minFilter the minification filter
*/
void C2D_FontSetFilter(C2D_Font font, GPU_TEXTURE_FILTER_PARAM magFilter, GPU_TEXTURE_FILTER_PARAM minFilter);
/** @brief Find the glyph index of a codepoint, or returns the default
* @param[in] font Font to search, or NULL for system font
* @param[in] codepoint Codepoint to search for
* @returns Glyph index
* @retval font->cfnt->finf.alterCharIndex The codepoint does not exist in the font
*/
int C2D_FontGlyphIndexFromCodePoint(C2D_Font font, u32 codepoint);
/** @brief Get character width info for a given index
* @param[in] font Font to read from, or NULL for system font
* @param[in] glyphIndex Index to get the width of
* @returns Width info for glyph
*/
charWidthInfo_s* C2D_FontGetCharWidthInfo(C2D_Font font, int glyphIndex);
/** @brief Calculate glyph position of given index
* @param[in] font Font to read from, or NULL for system font
* @param[out] out Glyph position
* @param[in] glyphIndex Index to get position of
* @param[in] flags Misc flags
* @param[in] scaleX Size to scale in X
* @param[in] scaleY Size to scale in Y
*/
void C2D_FontCalcGlyphPos(C2D_Font font, fontGlyphPos_s* out, int glyphIndex, u32 flags, float scaleX, float scaleY);
/** @brief Get the font info structure associated with the font
* @param[in] font Font to read from, or NULL for the system font
* @returns FINF associated with the font
*/
FINF_s* C2D_FontGetInfo(C2D_Font font);
/** @} */

179
include/c2d/sprite.h Normal file
View file

@ -0,0 +1,179 @@
/**
* @file sprite.h
* @brief Stateful sprite API
*/
#pragma once
#include "spritesheet.h"
typedef struct
{
C2D_Image image;
C2D_DrawParams params;
} C2D_Sprite;
/** @defgroup Sprite Sprite functions
* @{
*/
/** @brief Initializes a sprite from an image
* @param[in] Pointer to sprite
* @param[in] image Image to use
*/
static inline void C2D_SpriteFromImage(C2D_Sprite* sprite, C2D_Image image)
{
sprite->image = image;
sprite->params.pos.x = 0.0f;
sprite->params.pos.y = 0.0f;
sprite->params.pos.w = image.subtex->width;
sprite->params.pos.h = image.subtex->height;
sprite->params.center.x = 0.0f;
sprite->params.center.y = 0.0f;
sprite->params.angle = 0.0f;
sprite->params.depth = 0.0f;
}
/** @brief Initializes a sprite from an image stored in a sprite sheet
* @param[in] Pointer to sprite
* @param[in] sheet Sprite sheet handle
* @param[in] index Index of the image inside the sprite sheet
*/
static inline void C2D_SpriteFromSheet(C2D_Sprite* sprite, C2D_SpriteSheet sheet, size_t index)
{
C2D_SpriteFromImage(sprite, C2D_SpriteSheetGetImage(sheet, index));
}
/** @brief Scale sprite (relative)
* @param[in] sprite Pointer to sprite
* @param[in] x X scale (negative values flip the sprite horizontally)
* @param[in] y Y scale (negative values flip the sprite vertically)
*/
static inline void C2D_SpriteScale(C2D_Sprite* sprite, float x, float y)
{
sprite->params.pos.w *= x;
sprite->params.pos.h *= y;
sprite->params.center.x *= x;
sprite->params.center.y *= y;
}
/** @brief Rotate sprite (relative)
* @param[in] sprite Pointer to sprite
* @param[in] radians Amount to rotate in radians
*/
static inline void C2D_SpriteRotate(C2D_Sprite* sprite, float radians)
{
sprite->params.angle += radians;
}
/** @brief Rotate sprite (relative)
* @param[in] sprite Pointer to sprite
* @param[in] degrees Amount to rotate in degrees
*/
static inline void C2D_SpriteRotateDegrees(C2D_Sprite* sprite, float degrees)
{
C2D_SpriteRotate(sprite, C3D_AngleFromDegrees(degrees));
}
/** @brief Move sprite (relative)
* @param[in] sprite Pointer to sprite
* @param[in] x X translation
* @param[in] y Y translation
*/
static inline void C2D_SpriteMove(C2D_Sprite* sprite, float x, float y)
{
sprite->params.pos.x += x;
sprite->params.pos.y += y;
}
/** @brief Scale sprite (absolute)
* @param[in] sprite Pointer to sprite
* @param[in] x X scale (negative values flip the sprite horizontally)
* @param[in] y Y scale (negative values flip the sprite vertically)
*/
static inline void C2D_SpriteSetScale(C2D_Sprite* sprite, float x, float y)
{
float oldCenterX = sprite->params.center.x / sprite->params.pos.w;
float oldCenterY = sprite->params.center.y / sprite->params.pos.h;
sprite->params.pos.w = x*sprite->image.subtex->width;
sprite->params.pos.h = y*sprite->image.subtex->height;
sprite->params.center.x = fabsf(oldCenterX*sprite->params.pos.w);
sprite->params.center.y = fabsf(oldCenterY*sprite->params.pos.h);
}
/** @brief Rotate sprite (absolute)
* @param[in] sprite Pointer to sprite
* @param[in] radians Amount to rotate in radians
*/
static inline void C2D_SpriteSetRotation(C2D_Sprite* sprite, float radians)
{
sprite->params.angle = radians;
}
/** @brief Rotate sprite (absolute)
* @param[in] sprite Pointer to sprite
* @param[in] degrees Amount to rotate in degrees
*/
static inline void C2D_SpriteSetRotationDegrees(C2D_Sprite* sprite, float degrees)
{
C2D_SpriteSetRotation(sprite, C3D_AngleFromDegrees(degrees));
}
/** @brief Set the center of a sprite in values independent of the sprite size (absolute)
* @param[in] sprite Pointer to sprite
* @param[in] x X position of the center (0.0 through 1.0)
* @param[in] y Y position of the center (0.0 through 1.0)
*/
static inline void C2D_SpriteSetCenter(C2D_Sprite* sprite, float x, float y)
{
sprite->params.center.x = x*sprite->params.pos.w;
sprite->params.center.y = y*sprite->params.pos.h;
}
/** @brief Set the center of a sprite in terms of pixels (absolute)
* @param[in] sprite Pointer to sprite
* @param[in] x X position of the center (in pixels)
* @param[in] y Y position of the center (in pixels)
*/
static inline void C2D_SpriteSetCenterRaw(C2D_Sprite* sprite, float x, float y)
{
sprite->params.center.x = x;
sprite->params.center.y = y;
}
/** @brief Move sprite (absolute)
* @param[in] sprite Pointer to sprite
* @param[in] x X position
* @param[in] y Y position
*/
static inline void C2D_SpriteSetPos(C2D_Sprite* sprite, float x, float y)
{
sprite->params.pos.x = x;
sprite->params.pos.y = y;
}
/** @brief Sets the depth level of a sprite (absolute)
* @param[in] sprite Pointer to sprite
* @param[in] depth Depth value
*/
static inline void C2D_SpriteSetDepth(C2D_Sprite* sprite, float depth)
{
sprite->params.depth = depth;
}
/** @brief Draw sprite
* @param[in] sprite Sprite to draw
*/
static inline bool C2D_DrawSprite(const C2D_Sprite* sprite)
{
return C2D_DrawImage(sprite->image, &sprite->params, NULL);
}
/** @brief Draw sprite with color tinting
* @param[in] sprite Sprite to draw
* @param[in] tint Color tinting parameters to apply to the sprite
*/
static inline bool C2D_DrawSpriteTinted(const C2D_Sprite* sprite, const C2D_ImageTint* tint)
{
return C2D_DrawImage(sprite->image, &sprite->params, tint);
}
/** @} */

62
include/c2d/spritesheet.h Normal file
View file

@ -0,0 +1,62 @@
/**
* @file spritesheet.h
* @brief Spritesheet (texture atlas) loading and management
*/
#pragma once
#include "base.h"
struct C2D_SpriteSheet_s;
typedef struct C2D_SpriteSheet_s* C2D_SpriteSheet;
/** @defgroup SpriteSheet Sprite sheet functions
* @{
*/
/** @brief Load a sprite sheet from file
* @param[in] filename Name of the sprite sheet file (.t3x)
* @returns Sprite sheet handle
* @retval NULL Error
*/
C2D_SpriteSheet C2D_SpriteSheetLoad(const char* filename);
/** @brief Load a sprite sheet from memory
* @param[in] data Data to load
* @param[in] size Size of the data to load
* @returns Sprite sheet handle
* @retval NULL Error
*/
C2D_SpriteSheet C2D_SpriteSheetLoadFromMem(const void* data, size_t size);
/** @brief Load sprite sheet from file descriptor
* @param[in] fd File descriptor used to load data
* @returns Sprite sheet handle
* @retval NULL Error
*/
C2D_SpriteSheet C2D_SpriteSheetFromFD(int fd);
/** @brief Load sprite sheet from stdio file handle
* @param[in] f File handle used to load data
* @returns Sprite sheet handle
* @retval NULL Error
*/
C2D_SpriteSheet C2D_SpriteSheetLoadFromHandle(FILE* f);
/** @brief Free a sprite sheet
* @param[in] sheet Sprite sheet handle
*/
void C2D_SpriteSheetFree(C2D_SpriteSheet sheet);
/** @brief Retrieves the number of sprites in the specified sprite sheet
* @param[in] sheet Sprite sheet handle
* @returns Number of sprites
*/
size_t C2D_SpriteSheetCount(C2D_SpriteSheet sheet);
/** @brief Retrieves the specified image from the specified sprite sheet
* @param[in] sheet Sprite sheet handle
* @param[in] index Index of the image to retrieve
* @returns Image object
*/
C2D_Image C2D_SpriteSheetGetImage(C2D_SpriteSheet sheet, size_t index);
/** @} */

154
include/c2d/text.h Executable file
View file

@ -0,0 +1,154 @@
/**
* @file text.h
* @brief Text rendering API
*/
#pragma once
#include "base.h"
#include "font.h"
struct C2D_TextBuf_s;
typedef struct C2D_TextBuf_s* C2D_TextBuf;
/** @defgroup Text Text drawing functions
* @{
*/
/// Text object.
typedef struct
{
C2D_TextBuf buf; ///< Buffer associated with the text.
size_t begin; ///< Reserved for internal use.
size_t end; ///< Reserved for internal use.
float width; ///< Width of the text in pixels, according to 1x scale metrics.
u32 lines; ///< Number of lines in the text.
u32 words; ///< Number of words in the text.
C2D_Font font; ///< Font used to draw the text, or NULL for system font
} C2D_Text;
enum
{
C2D_AtBaseline = BIT(0), ///< Matches the Y coordinate with the baseline of the font.
C2D_WithColor = BIT(1), ///< Draws text with color. Requires a u32 color value.
C2D_AlignLeft = 0 << 2, ///< Draws text aligned to the left. This is the default.
C2D_AlignRight = 1 << 2, ///< Draws text aligned to the right.
C2D_AlignCenter = 2 << 2, ///< Draws text centered.
C2D_AlignJustified = 3 << 2, ///< Draws text justified. When C2D_WordWrap is not specified, right edge is x + scaleX*text->width. Otherwise, right edge is x + the width specified for those values.
C2D_AlignMask = 3 << 2, ///< Bitmask for alignment values.
C2D_WordWrap = BIT(4), ///< Draws text with wrapping of full words before specified width. Requires a float value, passed after color if C2D_WithColor is specified.
};
/** @brief Creates a new text buffer.
* @param[in] maxGlyphs Maximum number of glyphs that can be stored in the buffer.
* @returns Text buffer handle (or NULL on failure).
*/
C2D_TextBuf C2D_TextBufNew(size_t maxGlyphs);
/** @brief Resizes a text buffer.
* @param[in] buf Text buffer to resize.
* @param[in] maxGlyphs Maximum number of glyphs that can be stored in the buffer.
* @returns New text buffer handle (or NULL on failure).
* @remarks If successful, old text buffer handle becomes invalid.
*/
C2D_TextBuf C2D_TextBufResize(C2D_TextBuf buf, size_t maxGlyphs);
/** @brief Deletes a text buffer.
* @param[in] buf Text buffer handle.
* @remarks This also invalidates all text objects previously created with this buffer.
*/
void C2D_TextBufDelete(C2D_TextBuf buf);
/** @brief Clears all stored text in a buffer.
* @param[in] buf Text buffer handle.
*/
void C2D_TextBufClear(C2D_TextBuf buf);
/** @brief Retrieves the number of glyphs stored in a text buffer.
* @param[in] buf Text buffer handle.
* @returns The number of glyphs.
*/
size_t C2D_TextBufGetNumGlyphs(C2D_TextBuf buf);
/** @brief Parses and adds a single line of text to a text buffer.
* @param[out] text Pointer to text object to store information in.
* @param[in] buf Text buffer handle.
* @param[in] str String to parse.
* @param[in] lineNo Line number assigned to the text (used to calculate vertical position).
* @remarks Whitespace doesn't add any glyphs to the text buffer and is thus "free".
* @returns On success, a pointer to the character on which string processing stopped, which
* can be a newline ('\n'; indicating that's where the line ended), the null character
* ('\0'; indicating the end of the string was reached), or any other character
* (indicating the text buffer is full and no more glyphs can be added).
* On failure, NULL.
*/
const char* C2D_TextParseLine(C2D_Text* text, C2D_TextBuf buf, const char* str, u32 lineNo);
/** @brief Parses and adds a single line of text to a text buffer.
* @param[out] text Pointer to text object to store information in.
* @param[in] font Font to get glyphs from, or null for system font
* @param[in] buf Text buffer handle.
* @param[in] str String to parse.
* @param[in] lineNo Line number assigned to the text (used to calculate vertical position).
* @remarks Whitespace doesn't add any glyphs to the text buffer and is thus "free".
* @returns On success, a pointer to the character on which string processing stopped, which
* can be a newline ('\n'; indicating that's where the line ended), the null character
* ('\0'; indicating the end of the string was reached), or any other character
* (indicating the text buffer is full and no more glyphs can be added).
* On failure, NULL.
*/
const char* C2D_TextFontParseLine(C2D_Text* text, C2D_Font font, C2D_TextBuf buf, const char* str, u32 lineNo);
/** @brief Parses and adds arbitrary text (including newlines) to a text buffer.
* @param[out] text Pointer to text object to store information in.
* @param[in] buf Text buffer handle.
* @param[in] str String to parse.
* @remarks Whitespace doesn't add any glyphs to the text buffer and is thus "free".
* @returns On success, a pointer to the character on which string processing stopped, which
* can be the null character ('\0'; indicating the end of the string was reached),
* or any other character (indicating the text buffer is full and no more glyphs can be added).
* On failure, NULL.
*/
const char* C2D_TextParse(C2D_Text* text, C2D_TextBuf buf, const char* str);
/** @brief Parses and adds arbitrary text (including newlines) to a text buffer.
* @param[out] text Pointer to text object to store information in.
* @param[in] font Font to get glyphs from, or null for system font
* @param[in] buf Text buffer handle.
* @param[in] str String to parse.
* @remarks Whitespace doesn't add any glyphs to the text buffer and is thus "free".
* @returns On success, a pointer to the character on which string processing stopped, which
* can be the null character ('\0'; indicating the end of the string was reached),
* or any other character (indicating the text buffer is full and no more glyphs can be added).
* On failure, NULL.
*/
const char* C2D_TextFontParse(C2D_Text* text, C2D_Font font, C2D_TextBuf buf, const char* str);
/** @brief Optimizes a text object in order to be drawn more efficiently.
* @param[in] text Pointer to text object.
*/
void C2D_TextOptimize(const C2D_Text* text);
/** @brief Retrieves the total dimensions of a text object.
* @param[in] text Pointer to text object.
* @param[in] scaleX Horizontal size of the font. 1.0f corresponds to the native size of the font.
* @param[in] scaleY Vertical size of the font. 1.0f corresponds to the native size of the font.
* @param[out] outWidth (optional) Variable in which to store the width of the text.
* @param[out] outHeight (optional) Variable in which to store the height of the text.
*/
void C2D_TextGetDimensions(const C2D_Text* text, float scaleX, float scaleY, float* outWidth, float* outHeight);
/** @brief Draws text using the GPU.
* @param[in] text Pointer to text object.
* @param[in] flags Text drawing flags.
* @param[in] x Horizontal position to draw the text on.
* @param[in] y Vertical position to draw the text on. If C2D_AtBaseline is not specified (default), this
* is the top left corner of the block of text; otherwise this is the position of the baseline
* of the first line of text.
* @param[in] z Depth value of the text. If unsure, pass 0.0f.
* @param[in] scaleX Horizontal size of the font. 1.0f corresponds to the native size of the font.
* @param[in] scaleY Vertical size of the font. 1.0f corresponds to the native size of the font.
* @remarks The default 3DS system font has a glyph height of 30px, and the baseline is at 25px.
*/
void C2D_DrawText(const C2D_Text* text, u32 flags, float x, float y, float z, float scaleX, float scaleY, ...);
/** @} */