text.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #define MAX(a,b) ((a) > (b) ? a : b)
  5. #define MIN(a,b) ((a) < (b) ? a : b)
  6. #include <GL/glew.h>
  7. #include "../c3dlas/c3dlas.h"
  8. #include "text.h"
  9. #include "../EACSMB/src/utilities.h"
  10. FT_Library ftLib = NULL;
  11. static void makeVertices(TextRenderInfo* tri, unsigned int* colors);
  12. /*
  13. A Note About Charsets:
  14. All characters specified will be packed into a texture then shoved into video ram.
  15. There is a limit to the size of textures. A large font size and large character
  16. set may not fit in the largest texture available. Even if it does, precious vram
  17. is used for every character added. This is not the place to be a unicode twat;
  18. specify only the characters you will actually use. And for God's sake, don't try
  19. to render traditional Chinese at 64pt... you'd use 80+mb of ram.
  20. Also note the kerning information is n^2 in size with respect to strlen(charset).
  21. Currently this information is in system memory but eventually most operations
  22. will be moved to the gpu. Geometry shaders are amazing.
  23. */
  24. // all keys on a standard US keyboard.
  25. char* defaultCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 `~!@#$%^&*()_+|-=\\{}[]:;<>?,./'\"";
  26. // 16.16 fixed point to float conversion
  27. static float f2f(int i) {
  28. return (float)(i >> 6);
  29. }
  30. static void blit(
  31. int src_x, int src_y, int dst_x, int dst_y, int w, int h,
  32. int src_w, int dst_w, unsigned char* src, unsigned char* dst) {
  33. int y, x, s, d;
  34. // this may be upside down...
  35. for(y = 0; y < h; y++) {
  36. for(x = 0; x < w; x++) {
  37. s = ((y + src_y) * src_w) + src_x + x;
  38. d = ((y + dst_y) * dst_w) + dst_x + x;
  39. dst[d] = src[s];
  40. }
  41. }
  42. }
  43. TextRes* LoadFont(char* path, int size, char* chars) {
  44. FT_Error err;
  45. FT_GlyphSlot slot;
  46. TextRes* res;
  47. int i, j, charlen, width, h_above, h_below, height, padding, xoffset;
  48. padding = 2;
  49. if(!ftLib) {
  50. err = FT_Init_FreeType(&ftLib);
  51. if(err) {
  52. fprintf(stderr, "Could not initialize FreeType library.\n");
  53. return NULL;
  54. }
  55. }
  56. res = (TextRes*)malloc(sizeof(TextRes));
  57. // if you're out of memory you have bigger problems than error checking...
  58. err = FT_New_Face(ftLib, path, 0, &res->fontFace);
  59. if(err) {
  60. fprintf(stderr, "Could not load font file \"%s\".\n", path);
  61. free(res);
  62. return NULL;
  63. }
  64. err = FT_Set_Pixel_Sizes(res->fontFace, 0, size);
  65. if(err) {
  66. fprintf(stderr, "Could not set pixel size to %dpx.\n", size);
  67. free(res);
  68. return NULL;
  69. }
  70. // slot is a pointer
  71. slot = res->fontFace->glyph;
  72. if(!chars) chars = defaultCharset;
  73. res->charSet = strdup(chars);
  74. charlen = strlen(chars);
  75. res->charLen = charlen;
  76. h_above = 0;
  77. h_below = 0;
  78. width = 0;
  79. height = 0;
  80. // first find how wide of a texture we need
  81. for(i = 0; i < charlen; i++) {
  82. int ymin;
  83. err = FT_Load_Char(res->fontFace, chars[i], FT_LOAD_DEFAULT);
  84. ymin = slot->metrics.height >> 6;// - f2f(slot->metrics.horiBearingY);
  85. /*
  86. printf("%c-----\nymin: %d \n", chars[i], ymin);
  87. printf("bearingY: %d \n", slot->metrics.horiBearingY >> 6);
  88. printf("width: %d \n", slot->metrics.width >> 6);
  89. printf("height: %d \n\n", slot->metrics.height >> 6);
  90. */
  91. width += f2f(slot->metrics.width);
  92. h_above = MAX(h_above, slot->metrics.horiBearingY >> 6);
  93. h_below = MAX(h_below, ymin);
  94. }
  95. width += charlen * padding;
  96. height = h_below + padding + padding;
  97. res->maxHeight = height;
  98. res->padding = padding / 2;
  99. //TODO: clean up this messy function
  100. // printf("width: %d, height: %d \n", width, height);
  101. width = nextPOT(width);
  102. height = nextPOT(height);
  103. res->texWidth = width;
  104. res->texHeight = height; // may not always just be one row
  105. res->texture = (unsigned char*)calloc(width * height, 1);
  106. res->offsets = (unsigned short*)calloc(charlen * sizeof(unsigned short), 1);
  107. res->charWidths = (unsigned short*)calloc(charlen * sizeof(unsigned short), 1);
  108. res->valign = (unsigned char*)calloc(charlen * sizeof(unsigned char), 1);
  109. // construct code mapping
  110. // shitty method for now, improve later
  111. res->indexLen = 128; // 7 bits for now.
  112. res->codeIndex = (unsigned char*)calloc(res->indexLen, 1);
  113. // render the glyphs into the texture
  114. xoffset = 0;
  115. for(i = 0; i < charlen; i++) {
  116. int paddedw, charHeight, bearingY;
  117. err = FT_Load_Char(res->fontFace, chars[i], FT_LOAD_RENDER);
  118. paddedw = (slot->metrics.width >> 6) + padding;
  119. bearingY = slot->metrics.horiBearingY >> 6;
  120. charHeight = slot->metrics.height >> 6;
  121. res->charWidths[i] = paddedw + padding;
  122. /* printf("meh: %d\n", height - charHeight);
  123. printf("index: %d, char: %c, xoffset: %d, pitch: %d \n", i, chars[i], xoffset, slot->bitmap.pitch);
  124. printf("m.width: %d, m.height: %d, hbearing: %d, habove: %d \n\n", slot->metrics.width >> 6, slot->metrics.height >> 6, slot->metrics.horiBearingY >> 6, h_above);
  125. */ blit(
  126. 0, 0, // src x and y offset for the image
  127. xoffset + padding, padding + (h_above - bearingY), // dst offset
  128. slot->metrics.width >> 6, slot->metrics.height >> 6, // width and height BUG probably
  129. slot->bitmap.pitch, width, // src and dst row widths
  130. slot->bitmap.buffer, // source
  131. res->texture); // destination
  132. res->codeIndex[chars[i]] = i;
  133. res->offsets[i] = xoffset;
  134. res->valign[i] = (height - h_above + bearingY - padding);// + (slot->metrics.horiBearingY >> 6);
  135. xoffset += paddedw;
  136. }
  137. // kerning map
  138. res->kerning = (unsigned char*)malloc(charlen * charlen);
  139. for(i = 0; i < charlen; i++) {
  140. FT_UInt left, right;
  141. FT_Vector k;
  142. left = FT_Get_Char_Index(res->fontFace, chars[i]);
  143. for(j = 0; j < charlen; j++) {
  144. right = FT_Get_Char_Index(res->fontFace, chars[j]);
  145. FT_Get_Kerning(res->fontFace, left, right, FT_KERNING_DEFAULT, &k);
  146. // if(k.x != 0) printf("k: (%c%c) %d, %d\n", chars[i],chars[j], k.x, k.x >> 6);
  147. res->kerning[(i * charlen) + j] = k.x >> 6;
  148. }
  149. }
  150. //////////// opengl stuff ////////////
  151. // TODO: error checking
  152. glGenTextures(1, &res->textureID);
  153. glBindTexture(GL_TEXTURE_2D, res->textureID);
  154. glerr("bind font tex");
  155. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  156. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  157. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  158. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  159. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); // no mipmaps for this; it'll get fucked up
  160. glerr("param font tex");
  161. printf("width: %d, height: %d \n", width, height);
  162. glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, res->texture);
  163. glerr("load font tex");
  164. glBindTexture(GL_TEXTURE_2D, 0);
  165. return res;
  166. }
  167. TextRenderInfo* prepareText(TextRes* font, const char* str, int len, unsigned int* colors) {
  168. float offset;
  169. int v, i;
  170. TextRenderInfo* tri;
  171. float uscale, vscale, scale;
  172. unsigned int color;
  173. unsigned int defaultColor[] = {0xBADA55FF, INT_MAX}; // you have serious problems if the string is longer than INT_MAX
  174. if(!colors)
  175. colors = &defaultColor;
  176. //TODO:
  177. // normalize uv's
  178. // investigate and fix kerning, it seems off
  179. // move VAO to a better spot
  180. if(len == -1) len = strlen(str);
  181. // create vao/vbo
  182. tri = (TextRenderInfo*)malloc(sizeof(TextRenderInfo));
  183. tri->vertices = (TextVertex*)malloc(len * 2 * 3 * sizeof(TextVertex));
  184. tri->font = font;
  185. tri->text = strdup(str);
  186. tri->textLen = len;
  187. //move this to a global
  188. glGenVertexArrays(1, &tri->vao);
  189. glBindVertexArray(tri->vao);
  190. // have to create and bind the buffer before specifying its format
  191. glGenBuffers(1, &tri->vbo);
  192. glBindBuffer(GL_ARRAY_BUFFER, tri->vbo);
  193. // vertex
  194. glEnableVertexAttribArray(0);
  195. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(TextVertex), 0);
  196. glerr("pos attrib");
  197. // uvs
  198. glEnableVertexAttribArray(1);
  199. glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(TextVertex), 3*4);
  200. glerr("uv attrib");
  201. glEnableVertexAttribArray(2);
  202. glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(TextVertex), 5*4);
  203. glerr("color attrib");
  204. makeVertices(tri, colors);
  205. glBufferData(GL_ARRAY_BUFFER, tri->vertexCnt * sizeof(TextVertex), tri->vertices, GL_STATIC_DRAW);
  206. // glBufferData(GL_ARRAY_BUFFER, sizeof(testarr), testarr, GL_STATIC_DRAW);
  207. glerr("buffering text vertices");
  208. // init shaders elsewhere
  209. return tri;
  210. }
  211. // internal use.
  212. static void makeVertices(TextRenderInfo* tri, unsigned int* colors) {
  213. float offset, uscale, vscale, scale;
  214. int v, i;
  215. char* str;
  216. TextRes* font;
  217. unsigned int color;
  218. str = tri->text;
  219. font = tri->font;
  220. uscale = 1.0 / font->texWidth;
  221. vscale = 1.0 / font->texHeight;
  222. scale = 1.0 / font->maxHeight;
  223. offset = 0;
  224. v = 0;
  225. for(i = 0; i < tri->textLen; i++) {
  226. float width, valign, kerning;
  227. float tex_offset, to_next;
  228. int index, prev;
  229. //increment the colors pointer if we reach the next change point
  230. if(i == colors[1]) colors += 2;
  231. color = *colors;
  232. index = font->codeIndex[str[i]];
  233. prev = font->codeIndex[str[i-1]];
  234. // width = font->kerning[index];
  235. width = font->charWidths[index] * scale;
  236. tex_offset = (font->offsets[index] + font->padding) * uscale;
  237. to_next = (font->offsets[index + 1] + font->padding) * uscale; // bug at end of array
  238. kerning = 0;
  239. if(i > 0)
  240. kerning = (font->kerning[(index * font->charLen) + prev]) * uscale; // bug at end of array
  241. offset -= (font->padding * 2) * vscale;
  242. offset -= kerning;
  243. /*
  244. printf("kerning: %f\n", kerning);
  245. printf("index: %d, char: %c\n", index, str[i]);
  246. printf("offset %f\n", tex_offset);
  247. printf("next o %f\n", (float)to_next * uscale);
  248. printf("uscale %f\n", uscale);
  249. printf("valign %d\n", font->valign[index]);
  250. printf("width %f\n\n", width);
  251. */
  252. //tex_offset = 1;
  253. // add quad, set uv's
  254. // triangle 1
  255. tri->vertices[v].x = width + offset;
  256. tri->vertices[v].y = 1.0 + valign;
  257. tri->vertices[v].z = 0.0;
  258. tri->vertices[v].rgba = color;
  259. tri->vertices[v].u = to_next;
  260. tri->vertices[v++].v = 1.0;
  261. // top left
  262. tri->vertices[v].x = width + offset;
  263. tri->vertices[v].y = 0.0 + valign;
  264. tri->vertices[v].z = 0.0;
  265. tri->vertices[v].rgba = color;
  266. tri->vertices[v].u = to_next;
  267. tri->vertices[v++].v = 0.0;
  268. // top right
  269. tri->vertices[v].x = 0.0 + offset;
  270. tri->vertices[v].y = 1.0 + valign;
  271. tri->vertices[v].z = 0.0;
  272. tri->vertices[v].rgba = color;
  273. tri->vertices[v].u = tex_offset;
  274. tri->vertices[v++].v = 1.0;
  275. // triangle 2
  276. tri->vertices[v].x = 0.0 + offset;
  277. tri->vertices[v].y = 1.0 + valign;
  278. tri->vertices[v].z = 0.0;
  279. tri->vertices[v].rgba = color;
  280. tri->vertices[v].u = tex_offset;
  281. tri->vertices[v++].v = 1.0;
  282. // top right
  283. tri->vertices[v].x = width + offset;
  284. tri->vertices[v].y = 0.0 + valign;
  285. tri->vertices[v].z = 0.0;
  286. tri->vertices[v].rgba = color;
  287. tri->vertices[v].u = to_next;
  288. tri->vertices[v++].v = 0.0;
  289. // bottom right
  290. tri->vertices[v].x = 0.0 + offset;
  291. tri->vertices[v].y = 0.0 + valign;
  292. tri->vertices[v].z = 0.0;
  293. tri->vertices[v].rgba = color;
  294. tri->vertices[v].u = tex_offset;
  295. tri->vertices[v++].v = 0.0;
  296. // move right by kerning amount
  297. offset += width; //tex_offset;
  298. }
  299. tri->vertexCnt = v;
  300. }
  301. void FreeFont(TextRes* res) {
  302. free(res->texture);
  303. free(res->codeIndex);
  304. free(res->offsets);
  305. free(res->valign);
  306. free(res->kerning);
  307. free(res->charSet);
  308. free(res);
  309. };
  310. // super nifty site:
  311. // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
  312. int nextPOT(int in) {
  313. in--;
  314. in |= in >> 1;
  315. in |= in >> 2;
  316. in |= in >> 4;
  317. in |= in >> 8;
  318. in |= in >> 16;
  319. in++;
  320. return in;
  321. }
  322. void updateText(TextRenderInfo* tri, const char* str, int len, unsigned int* colors) {
  323. if(len <= 0) len = strlen(str);
  324. // text hasn't changed
  325. if(0 == strcmp(str, tri->text)) return;
  326. // need to check if colors changes too, but meh
  327. // reallocate the vertex data buffer if it's too small
  328. if(tri->vertices && len > tri->textLen) {
  329. free(tri->vertices);
  330. tri->vertices = (TextVertex*)malloc(len * 2 * 3 * sizeof(TextVertex));
  331. }
  332. if(tri->text) free(tri->text);
  333. tri->text = strdup(str);
  334. tri->textLen = len;
  335. // i've read that trying to update a vbo when opengl is rendering can force a
  336. // disasterous gpu<->cpu sync. here the old vbo is released (hopefully async)
  337. // and the next frame will get the new vbo (all hopefully async). this has not
  338. // been comparatively tested.
  339. glBindBuffer(GL_ARRAY_BUFFER, 0);
  340. GLuint oldvbo = tri->vbo;
  341. glBindVertexArray(tri->vao);
  342. glGenBuffers(1, &tri->vbo);
  343. glBindBuffer(GL_ARRAY_BUFFER, tri->vbo);
  344. glexit("update text buffer creation");
  345. glDeleteBuffers(1, &oldvbo);
  346. // vertex
  347. glEnableVertexAttribArray(0);
  348. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(TextVertex), 0);
  349. glerr("pos attrib");
  350. // uvs
  351. glEnableVertexAttribArray(1);
  352. glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(TextVertex), 3*4);
  353. glerr("uv attrib");
  354. glEnableVertexAttribArray(2);
  355. glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(TextVertex), 5*4);
  356. glerr("color attrib");
  357. makeVertices(tri, colors);
  358. glBufferData(GL_ARRAY_BUFFER, tri->vertexCnt * sizeof(TextVertex), tri->vertices, GL_STATIC_DRAW);
  359. // glBufferData(GL_ARRAY_BUFFER, sizeof(testarr), testarr, GL_STATIC_DRAW);
  360. glerr("buffering text vertices");
  361. }