+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
+
+#include <unistd.h>
+#include <freetype/freetype.h>
+
+/* NOTE: _user_info is defined in crt0.c. It points to a 4096 byte
+ block of memory that contains 1024 32-bit values that can be set
+ with the setUserInfo() method of MIPSEmu.
+
+ The VM will pause after initialization. When unpaused, it expects
+ that:
+
+ user_info[0] = ptr to font byte stream in memory
+ user_info[1] = length of font stream
+ user_info[2] = unicode index of first glyph to render
+ user_info[3] = unicode index of last glyph to render
+ user_info[4] = point size to render in
+
+ The VM will then iterate over the requested glyphs, performing the
+ following actions for each glyph:
+
+ - render the glyph
+ - store the address of the glyph bitmap in user_info[5]
+ - store the width of the glyph bitmap in user_info[6]
+ - store the height of the glyph bitmap in user_info[7]
+ - store the font's ascender into user_info[8]
+ - store the font's height into user_info[9]
+ - store the glyph's ascender into user_info[10]
+ - store the glyph's advance into user_info[11]
+
+ The VM will then pause after each glyph. The VM should not be
+ unpaused after the last glyph until the next glyph set has been
+ configured in user_info (ie it does not pause twice).
+
+*/
+
+extern char *user_info[1024];
+
+#define FT_Check(expr) do { \
+ if((expr) != 0) { \
+ errprint(#expr " failed\n"); \
+ exit(EXIT_FAILURE); \
+ } \
+} while(0)
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static int errprint(const char *s) {
+ int l = strlen(s);
+ int n;
+ while(l) {
+ n = write(STDERR_FILENO,s,l);
+ if(n < 0) return n;
+ l -= n;
+ s += n;
+ }
+ return 0;
+}
+
+extern void _pause();
+
+int freetype_main() {
+ char *fontdata;
+ int glyph_index;
+ short charcode;
+ FT_Library library; /* handle to library */
+ FT_Face face; /* handle to face object */
+
+ FT_Check(FT_Init_FreeType(&library));
+ FT_Check(FT_New_Memory_Face(library, user_info[0], (int)user_info[1], 0, &face));
+
+ for(;;) {
+
+ _pause();
+ FT_Check(FT_Set_Char_Size(face, 0, ((int)user_info[4]) * 64, 72, 72));
+ for(charcode = (int)user_info[2]; charcode <= (int)user_info[3]; charcode++) {
+
+ glyph_index = FT_Get_Char_Index(face, charcode);
+ FT_Check(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT | FT_LOAD_FORCE_AUTOHINT));
+ FT_Check(FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL));
+
+ user_info[5] = (char*)face->glyph->bitmap.buffer;
+ user_info[6] = (char*)face->glyph->bitmap.width;
+ user_info[7] = (char*)face->glyph->bitmap.rows;
+ user_info[8] = (char*)(face->size->metrics.ascender >> 6);
+ user_info[9] = (char*)((-1 * face->size->metrics.descender) >> 6);
+ user_info[10] = (char*)(face->glyph->metrics.horiBearingY >> 6);
+ user_info[11] = (char*)(face->glyph->advance.x >> 6);
+
+ }
+ }
+}
+
+
+// Kerning code; add back in later
+/*
+if (old_glyph_index != -1) {
+ if (FT_HAS_KERNING(face)) {
+ FT_Check(FT_Get_Kerning(face, old_glyph_index, glyph_index, 0, &kerning));
+ x += kerning.x >> 6;
+ } else {
+ x += face->glyph->advance.x >> 6;
+ }
+}
+old_glyph_index = glyph_index;
+*/