]> Chaos Git - corbenik/ctrulib.git/commitdiff
Add shared system font parsing code.
authorfincs <fincs.alt1@gmail.com>
Tue, 19 Jan 2016 18:23:58 +0000 (19:23 +0100)
committerfincs <fincs.alt1@gmail.com>
Tue, 19 Jan 2016 18:23:58 +0000 (19:23 +0100)
libctru/include/3ds.h
libctru/include/3ds/font.h [new file with mode: 0644]
libctru/include/3ds/services/apt.h
libctru/source/font.c [new file with mode: 0644]
libctru/source/services/apt.c

index 48adc16f709b4a9f5446c9e1f07951e7b2339cfb..a8d3f6559de3fb68f3c425870fa6529b408d780d 100644 (file)
@@ -68,6 +68,7 @@ extern "C" {
 
 #include <3ds/sdmc.h>
 #include <3ds/romfs.h>
+#include <3ds/font.h>
 
 #ifdef __cplusplus
 }
diff --git a/libctru/include/3ds/font.h b/libctru/include/3ds/font.h
new file mode 100644 (file)
index 0000000..c747023
--- /dev/null
@@ -0,0 +1,205 @@
+/**
+ * @file font.h
+ * @brief Shared font support.
+ */
+#pragma once
+#include <3ds/types.h>
+
+///@name Data types
+///@{
+
+/// Character width information structure.
+typedef struct
+{
+       s8 left;       ///< Horizontal offset to draw the glyph with.
+       u8 glyphWidth; ///< Width of the glyph.
+       u8 charWidth;  ///< Width of the character, that is, horizontal distance to advance.
+} charWidthInfo_s;
+
+/// Font texture sheet information.
+typedef struct
+{
+       u8 cellWidth;    ///< Width of a glyph cell.
+       u8 cellHeight;   ///< Height of a glyph cell.
+       u8 baselinePos;  ///< Vertical position of the baseline.
+       u8 maxCharWidth; ///< Maximum character width.
+
+       u32 sheetSize; ///< Size in bytes of a texture sheet.
+       u16 nSheets;   ///< Number of texture sheets.
+       u16 sheetFmt;  ///< GPU texture format (GPU_TEXCOLOR).
+
+       u16 nRows;  ///< Number of glyphs per row per sheet.
+       u16 nLines; ///< Number of glyph rows per sheet.
+
+       u16 sheetWidth;  ///< Texture sheet width.
+       u16 sheetHeight; ///< Texture sheet height.
+       u8* sheetData;   ///< Pointer to texture sheet data.
+} TGLP_s;
+
+/// Font character width information block type.
+typedef struct tag_CWDH_s CWDH_s;
+
+/// Font character width information block structure.
+struct tag_CWDH_s
+{
+       u16 startIndex; ///< First Unicode codepoint the block applies to.
+       u16 endIndex;   ///< Last Unicode codepoint the block applies to.
+       CWDH_s* next;   ///< Pointer to the next block.
+
+       charWidthInfo_s widths[0]; ///< Table of character width information structures.
+};
+
+/// Font character map methods.
+enum
+{
+       CMAP_TYPE_DIRECT = 0, ///< Identity mapping.
+       CMAP_TYPE_TABLE = 1,  ///< Mapping using a table.
+       CMAP_TYPE_SCAN = 2,   ///< Mapping using a list of mapped characters.
+};
+
+/// Font character map type.
+typedef struct tag_CMAP_s CMAP_s;
+
+/// Font character map structure.
+struct tag_CMAP_s
+{
+       u16 codeBegin;     ///< First Unicode codepoint the block applies to.
+       u16 codeEnd;       ///< Last Unicode codepoint the block applies to.
+       u16 mappingMethod; ///< Mapping method.
+       u16 reserved;
+       CMAP_s* next;      ///< Pointer to the next map.
+
+       union
+       {
+               u16 indexOffset;   ///< For CMAP_TYPE_DIRECT: index of the first glyph.
+               u16 indexTable[0]; ///< For CMAP_TYPE_TABLE: table of glyph indices.
+               /// For CMAP_TYPE_SCAN: Mapping data.
+               struct
+               {
+                       u16 nScanEntries; ///< Number of pairs.
+                       /// Mapping pairs.
+                       struct
+                       {
+                               u16 code;       ///< Unicode codepoint.
+                               u16 glyphIndex; ///< Mapped glyph index.
+                       } scanEntries[0];
+               };
+       };
+};
+
+/// Font information structure.
+typedef struct
+{
+       u32 signature;   ///< Signature (FINF).
+       u32 sectionSize; ///< Section size.
+
+       u8 fontType;                  ///< Font type
+       u8 lineFeed;                  ///< Line feed vertical distance.
+       u16 alterCharIndex;           ///< Glyph index of the replacement character.
+       charWidthInfo_s defaultWidth; ///< Default character width information.
+       u8 encoding;                  ///< Font encoding (?)
+
+       TGLP_s* tglp; ///< Pointer to texture sheet information.
+       CWDH_s* cwdh; ///< Pointer to the first character width information block.
+       CMAP_s* cmap; ///< Pointer to the first character map.
+
+       u8 height;  ///< Font height.
+       u8 width;   ///< Font width.
+       u8 ascent;  ///< Font ascent.
+       u8 padding;
+} FINF_s;
+
+/// Font structure.
+typedef struct
+{
+       u32 signature;  ///< Signature (CFNU).
+       u16 endianness; ///< Endianness constant (0xFEFF).
+       u16 headerSize; ///< Header size.
+       u32 version;    ///< Format version.
+       u32 fileSize;   ///< File size.
+       u32 nBlocks;    ///< Number of blocks.
+
+       FINF_s finf; ///< Font information.
+} CFNT_s;
+
+/// Font glyph position structure.
+typedef struct
+{
+       int sheetIndex; ///< Texture sheet index to use to render the glyph.
+       float xOffset;  ///< Horizontal offset to draw the glyph width.
+       float xAdvance; ///< Horizontal distance to advance after drawing the glyph.
+       float width;    ///< Glyph width.
+       ///< Texture coordinates to use to render the glyph.
+       struct
+       {
+               float left, top, right, bottom;
+       } texcoord;
+       ///< Vertex coordinates to use to render the glyph.
+       struct
+       {
+               float left, top, right, bottom;
+       } vtxcoord;
+} fontGlyphPos_s;
+
+/// Flags for use with fontCalcGlyphPos.
+enum
+{
+       GLYPH_POS_CALC_VTXCOORD = BIT(0), ///< Calculates vertex coordinates in addition to texture coordinates.
+       GLYPH_POS_AT_BASELINE   = BIT(1), ///< Position the glyph at the baseline instead of at the top-left corner.
+       GLYPH_POS_Y_POINTS_UP   = BIT(2), ///< Indicates that the Y axis points up instead of down.
+};
+
+///@}
+
+///@name Initialization and basic operations
+///@{
+
+/// Ensures the shared system font is mapped.
+Result fontEnsureMapped(void);
+
+/// Retrieves the font information structure of the shared system font.
+static inline FINF_s* fontGetInfo(void)
+{
+       extern CFNT_s* g_sharedFont;
+       return &g_sharedFont->finf;
+}
+
+/// Retrieves the texture sheet information of the shared system font.
+static inline TGLP_s* fontGetGlyphInfo(void)
+{
+       return fontGetInfo()->tglp;
+}
+
+/**
+ * @brief Retrieves the pointer to texture data for the specified texture sheet.
+ * @param sheetIndex Index of the texture sheet.
+ */
+static inline void* fontGetGlyphSheetTex(int sheetIndex)
+{
+       TGLP_s* tglp = fontGetGlyphInfo();
+       return &tglp->sheetData[sheetIndex*tglp->sheetSize];
+}
+
+/**
+ * @brief Retrieves the glyph index of the specified Unicode codepoint.
+ * @param codePoint Unicode codepoint.
+ */
+int fontGlyphIndexFromCodePoint(u32 codePoint);
+
+/**
+ * @brief Retrieves character width information of the specified glyph.
+ * @param glyphIndex Index of the glyph.
+ */
+charWidthInfo_s* fontGetCharWidthInfo(int glyphIndex);
+
+/**
+ * @brief Calculates position information for the specified glyph.
+ * @param out Output structure in which to write the information.
+ * @param glyphIndex Index of the glyph.
+ * @param flags Calculation flags (see GLYPH_POS_* flags).
+ * @param scaleX Scale factor to apply horizontally.
+ * @param scaleY Scale factor to apply vertically.
+ */
+void fontCalcGlyphPos(fontGlyphPos_s* out, int glyphIndex, u32 flags, float scaleX, float scaleY);
+
+///@}
index 3b102bfd91083fd0fe6d05baef02ed52ba80ff4c..d73dd16ee21a27d9e9995b3a349df68300c01c09 100644 (file)
@@ -444,3 +444,9 @@ Result APT_PrepareToStartSystemApplet(NS_APPID appID);
  */
 Result APT_StartSystemApplet(NS_APPID appID, u32 bufSize, Handle applHandle, u8 *buf);
 
+/**
+ * @brief Retrieves the shared system font.
+ * @brief fontHandle Pointer to write the handle of the system font memory block to.
+ * @brief mapAddr Pointer to write the mapping address of the system font memory block to.
+ */
+Result APT_GetSharedFont(Handle* fontHandle, u32* mapAddr);
diff --git a/libctru/source/font.c b/libctru/source/font.c
new file mode 100644 (file)
index 0000000..8f3f675
--- /dev/null
@@ -0,0 +1,134 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <3ds/font.h>
+#include <3ds/svc.h>
+#include <3ds/synchronization.h>
+#include <3ds/result.h>
+#include <3ds/services/apt.h>
+
+CFNT_s* g_sharedFont;
+static u32 sharedFontAddr;
+static int charPerSheet;
+
+Result fontEnsureMapped(void)
+{
+       if (g_sharedFont) return 0;
+       Result res = 0;
+       Handle hSharedFont = 0;
+
+       aptOpenSession();
+       res = APT_GetSharedFont(&hSharedFont, &sharedFontAddr);
+       aptCloseSession();
+       if (R_FAILED(res)) return res;
+
+       // Map the shared font if it's not already mapped.
+       res = svcMapMemoryBlock(hSharedFont, 0, MEMPERM_READ, MEMPERM_DONTCARE);
+       svcCloseHandle(hSharedFont);
+       if (R_FAILED(res) && res != 0xE0A01BF5)
+               return res;
+
+       g_sharedFont = (CFNT_s*)(sharedFontAddr+0x80);
+       charPerSheet = g_sharedFont->finf.tglp->nRows * g_sharedFont->finf.tglp->nLines;
+       return 0;
+}
+
+int fontGlyphIndexFromCodePoint(u32 codePoint)
+{
+       int ret = g_sharedFont->finf.alterCharIndex;
+       if (codePoint < 0x10000)
+       {
+               CMAP_s* cmap;
+               for (cmap = g_sharedFont->finf.cmap; cmap; cmap = cmap->next)
+               {
+                       if (codePoint < cmap->codeBegin || codePoint > cmap->codeEnd)
+                               continue;
+
+                       if (cmap->mappingMethod == CMAP_TYPE_DIRECT)
+                       {
+                               ret = cmap->indexOffset + (codePoint - cmap->codeBegin);
+                               break;
+                       }
+
+                       if (cmap->mappingMethod == CMAP_TYPE_TABLE)
+                       {
+                               ret = cmap->indexTable[codePoint - cmap->codeBegin];
+                               break;
+                       }
+
+                       int j;
+                       for (j = 0; j < cmap->nScanEntries; j ++)
+                               if (cmap->scanEntries[j].code == codePoint)
+                                       break;
+                       if (j < cmap->nScanEntries)
+                       {
+                               ret = cmap->scanEntries[j].glyphIndex;
+                               break;
+                       }
+               }
+       }
+       return ret;
+}
+
+charWidthInfo_s* fontGetCharWidthInfo(int glyphIndex)
+{
+       charWidthInfo_s* info = NULL;
+       CWDH_s* cwdh;
+       for (cwdh = g_sharedFont->finf.cwdh; cwdh && !info; cwdh = cwdh->next)
+       {
+               if (glyphIndex < cwdh->startIndex || glyphIndex > cwdh->endIndex)
+                       continue;
+               info = &cwdh->widths[glyphIndex - cwdh->startIndex];
+       }
+       if (!info)
+               info = &g_sharedFont->finf.defaultWidth;
+       return info;
+}
+
+void fontCalcGlyphPos(fontGlyphPos_s* out, int glyphIndex, u32 flags, float scaleX, float scaleY)
+{
+       FINF_s* finf = &g_sharedFont->finf;
+       TGLP_s* tglp = finf->tglp;
+       charWidthInfo_s* cwi = fontGetCharWidthInfo(glyphIndex);
+
+       int sheetId = glyphIndex / charPerSheet;
+       int glInSheet = glyphIndex % charPerSheet;
+       out->sheetIndex = sheetId;
+       out->xOffset = scaleX*cwi->left;
+       out->xAdvance = scaleX*cwi->charWidth;
+       out->width = scaleX*cwi->glyphWidth;
+
+       int lineId = glInSheet / tglp->nRows;
+       int rowId = glInSheet % tglp->nRows;
+
+       float tx = (float)(rowId*(tglp->cellWidth+1)+1) / tglp->sheetWidth;
+       float ty = 1.0f - (float)((lineId+1)*(tglp->cellHeight+1)+1) / tglp->sheetHeight;
+       float tw = (float)cwi->glyphWidth / tglp->sheetWidth;
+       float th = (float)tglp->cellHeight / tglp->sheetHeight;
+       out->texcoord.left = tx;
+       out->texcoord.top = ty+th;
+       out->texcoord.right = tx+tw;
+       out->texcoord.bottom = ty;
+
+       if (flags & GLYPH_POS_CALC_VTXCOORD)
+       {
+               float vx = out->xOffset;
+               float vy = (flags & GLYPH_POS_AT_BASELINE) ? (scaleY*tglp->baselinePos) : 0;
+               float vw = out->width;
+               float vh = scaleY*tglp->cellHeight;
+               if (flags & GLYPH_POS_Y_POINTS_UP)
+               {
+                       vy = -(vh-vy);
+                       out->vtxcoord.left = vx;
+                       out->vtxcoord.top = vy+vh;
+                       out->vtxcoord.right = vx+vw;
+                       out->vtxcoord.bottom = vy;
+               } else
+               {
+                       vy = -vy;
+                       out->vtxcoord.left = vx;
+                       out->vtxcoord.top = vy;
+                       out->vtxcoord.right = vx+vw;
+                       out->vtxcoord.bottom = vy+vh;
+               }
+       }
+}
index 21ed31e051da0540730ce3306fb224900e15d0e1..d3554cef4af9d2ee55c161eaabcedd965e965f5b 100644 (file)
@@ -1342,3 +1342,16 @@ Result APT_StartSystemApplet(NS_APPID appID, u32 bufSize, Handle applHandle, u8
        return cmdbuf[1];
 }
 
+Result APT_GetSharedFont(Handle* fontHandle, u32* mapAddr)
+{
+       u32* cmdbuf=getThreadCommandBuffer();
+       cmdbuf[0] = IPC_MakeHeader(0x44,0,0); // 0x00440000
+
+       Result ret=0;
+       if(R_FAILED(ret=svcSendSyncRequest(aptuHandle)))return ret;
+
+       if(fontHandle) *fontHandle = cmdbuf[4];
+       if(mapAddr) *mapAddr = cmdbuf[2];
+
+       return cmdbuf[1];
+}