uiglyph.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /*
  2. * sfnedit/uiglyph.c
  3. *
  4. * Copyright (C) 2020 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief Glyph renderer for the editor window
  27. *
  28. */
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include "libsfn.h"
  32. #include "ui.h"
  33. #include "lang.h"
  34. /**
  35. * Render a glyph's layer or all layers
  36. */
  37. void ui_glyph(ui_win_t *win, int x, int y, int size, uint32_t unicode, int layer, int wa)
  38. {
  39. uint8_t cs;
  40. int j, k, m, n, w, h;
  41. uint32_t P, O, *Op, *Ol;
  42. unsigned long int sR, sG, sB, sA;
  43. int ox, oy, y0, y1, Y0, Y1, x0, x1, X0, X1, X2, xs, ys, yp, pc, af, fB, fG, fR, fA, bB, bG, bR;
  44. sfngc_t g;
  45. g.p = g.h = 0;
  46. if(!sfn_glyph(size, unicode, layer, 1, &g)) {
  47. if(g.p * g.h >= (260 + 260 / SSFN_ITALIC_DIV) << 8)
  48. fprintf(stderr, "sfnedit: %s U+%06X: p %d h %d size %d\n",lang[ERR_SIZE],unicode,g.p,g.h,size);
  49. return;
  50. }
  51. ssfn_dst.ptr = (uint8_t*)win->data;
  52. ssfn_dst.p = win->p*4;
  53. ssfn_dst.x = x + (wa ? size / 2 + 1 : 0);
  54. ssfn_dst.y = y;
  55. h = size;
  56. w = g.p * h / g.h;
  57. if(w > size - 4) { h = h * (size - 4) / w; w = size - 4; if(wa) ssfn_dst.y += (size - h) / 2; }
  58. n = size > 16 ? 2 : 1;
  59. if(w < n) w = n;
  60. if(ssfn_dst.ptr) {
  61. ox = oy = 0;
  62. if(wa) {
  63. ox = w / 2;
  64. if(ox > size / 2) ox = size / 2;
  65. }
  66. j = ssfn_dst.w < 0 ? -ssfn_dst.w : ssfn_dst.w;
  67. cs = ssfn_dst.w < 0 ? 16 : 0;
  68. #if 0
  69. printf("Scaling to w %d h %d (glyph %d %d, cache %d %d, font %d)\n",
  70. w,h,ctx.glyphs[unicode].width,ctx.glyphs[unicode].width,g.p,g.h,ctx.height);
  71. #endif
  72. fR = (ssfn_dst.fg >> 16) & 0xFF; fG = (ssfn_dst.fg >> 8) & 0xFF; fB = (ssfn_dst.fg >> 0) & 0xFF;
  73. fA = (ssfn_dst.fg >> 24) & 0xFF;
  74. Op = (uint32_t*)(ssfn_dst.ptr + ssfn_dst.p * (ssfn_dst.y - oy) + ((ssfn_dst.x - ox) << 2));
  75. for (y = 0; y < h && ssfn_dst.y + y - oy < ssfn_dst.h; y++, Op += ssfn_dst.p >> 2) {
  76. if(ssfn_dst.y + y - oy < 0) continue;
  77. y0 = (y << 8) * g.h / h; Y0 = y0 >> 8; y1 = ((y + 1) << 8) * g.h / h; Y1 = y1 >> 8; Ol = Op;
  78. for (x = 0; x < w && ssfn_dst.x + x - ox < j; x++, Ol++) {
  79. if(ssfn_dst.x + x - ox < 0) continue;
  80. m = 0; sR = sG = sB = sA = 0;
  81. /* real linear frame buffers should be accessed only as uint32_t on 32 bit boundary */
  82. O = *Ol;
  83. bR = (O >> (16 - cs)) & 0xFF;
  84. bG = (O >> 8) & 0xFF;
  85. bB = (O >> cs) & 0xFF;
  86. x0 = (x << 8) * g.p / w; X0 = x0 >> 8; x1 = ((x + 1) << 8) * g.p / w; X1 = x1 >> 8;
  87. for(ys = y0; ys < y1; ys += 256) {
  88. if(ys >> 8 == Y0) { yp = 256 - (ys & 0xFF); ys &= ~0xFF; if(yp > y1 - y0) yp = y1 - y0; }
  89. else if(ys >> 8 == Y1) yp = y1 & 0xFF;
  90. else yp = 256;
  91. X2 = (ys >> 8) * g.p;
  92. for(xs = x0; xs < x1; xs += 256) {
  93. if (xs >> 8 == X0) {
  94. k = 256 - (xs & 0xFF); xs &= ~0xFF; if(k > x1 - x0) k = x1 - x0;
  95. pc = k == 256 ? yp : (k * yp) >> 8;
  96. } else
  97. if (xs >> 8 == X1) { k = x1 & 0xFF; pc = k == 256 ? yp : (k * yp) >> 8; }
  98. else pc = yp;
  99. m += pc;
  100. k = g.data[X2 + (xs >> 8)];
  101. P = *((uint32_t*)(ctx.cpal + (k << 2)));
  102. if(k == 0xFF) {
  103. sB += bB * pc; sG += bG * pc; sR += bR * pc;
  104. } else
  105. if(k == 0xFE || !P) {
  106. af = (256 - fA) * pc;
  107. sB += fB * af; sG += fG * af; sR += fR * af; sA += fA * pc;
  108. } else {
  109. af = (256 - (P >> 24)) * pc;
  110. sR += (((P >> 16) & 0xFF) * af);
  111. sG += (((P >> 8) & 0xFF) * af);
  112. sB += (((P >> 0) & 0xFF) * af);
  113. sA += (((P >> 24) & 0xFF) * pc);
  114. }
  115. }
  116. }
  117. if(m) { sR /= m; sG /= m; sB /= m; sA /= m; }
  118. else { sR >>= 8; sG >>= 8; sB >>= 8; sA >>= 8; }
  119. if(sA > 15) {
  120. *Ol = ((sA > 255 ? 255 : sA) << 24) | ((sR > 255 ? 255 : sR) << (16 - cs)) |
  121. ((sG > 255 ? 255 : sG) << 8) | ((sB > 255 ? 255 : sB) << cs);
  122. }
  123. }
  124. }
  125. }
  126. return;
  127. }
  128. /**
  129. * Get the next UNICODE from string
  130. */
  131. uint32_t ui_c(char **str)
  132. {
  133. uint32_t unicode = 0, i, l;
  134. if(!*str || !**str) return 0;
  135. for(i = 0; i <= SSFN_LIG_LAST-SSFN_LIG_FIRST; i++)
  136. if(ctx.ligatures[i]) {
  137. l = strlen(ctx.ligatures[i]);
  138. if(!memcmp(str, ctx.ligatures[i], l)) {
  139. unicode = SSFN_LIG_FIRST + i;
  140. (*str) += l;
  141. break;
  142. }
  143. }
  144. if(!unicode) unicode = ssfn_utf8(str);
  145. return unicode;
  146. }
  147. /**
  148. * Render glyph from string
  149. */
  150. int ui_render(ui_win_t *win, int *x, int *y, int size, char *str)
  151. {
  152. sfnglyph_t *g;
  153. char *orig = str;
  154. uint32_t unicode, next;
  155. int ret = 0, w, n;
  156. if(!win || !x || !y || !str) return 0;
  157. if(!*str) return 0;
  158. if(!ctx.height) ctx.height = 1;
  159. if(!ctx.baseline) ctx.baseline = ctx.height;
  160. unicode = ui_c(&str);
  161. if((unicode >> 16) > 0x10) return 0;
  162. g = &ctx.glyphs[unicode];
  163. ret = (uintptr_t)str - (uintptr_t)orig;
  164. ui_glyph(win, *x, *y, size, unicode, -1, 0);
  165. /* FIXME: advances are not okay for vector fonts */
  166. w = ((g->adv_x - g->ovl_x) * size + ctx.height - 1) / ctx.height;
  167. n = size > 16 ? 2 : 1;
  168. if(w < n) w = n;
  169. (*x) += w;
  170. (*y) += (g->adv_y * size + ctx.height - 1) / ctx.height;
  171. if(g->kern && g->numkern && (next = ui_c(&str)) > 32)
  172. for(n = 0; n < g->numkern; n++)
  173. if(g->kern[n].n == (int)next) {
  174. (*x) += (int)g->kern[n].x * size / ctx.height;
  175. (*y) += (int)g->kern[n].y * size / ctx.height;
  176. break;
  177. }
  178. return ret;
  179. }
  180. /**
  181. * Draw a dot or X
  182. */
  183. void ui_dot(ui_win_t *win, int x, int y, int t)
  184. {
  185. uint32_t c = theme[t ? THEME_CPOINT : THEME_POINT];
  186. int i, j, n, z = win->zoom & ~1;
  187. x >>= 8; y >>= 8;
  188. if(z < 3) z = 3;
  189. y -= z/2; x -= z/2;
  190. for(i = 0, n = y * win->p + x; i <= z; i++, n += win->p) {
  191. if(y + i >= 36 && y + i < ssfn_dst.h) {
  192. if(!t) {
  193. for(j = 0; j < z; j++)
  194. if(x + j >= 20 && x + j < ssfn_dst.w) win->data[n + j] = c;
  195. } else {
  196. if(x + i >= 20 && x + i < ssfn_dst.w) win->data[n + i] = c;
  197. if(x + z - i >= 20 && x + z - i < ssfn_dst.w) win->data[n + z - i] = c;
  198. }
  199. }
  200. }
  201. }
  202. /**
  203. * Draw line
  204. */
  205. void ui_line(ui_win_t *win, int x0, int y0, int x1, int y1, int dot, uint32_t c)
  206. {
  207. int sx, sy, dx, dy, x, y, m;
  208. x0 >>= 8; y0 >>= 8; x1 >>= 8; y1 >>= 8;
  209. if((x0 < 20 && x1 < 20) || (x0 >= ssfn_dst.w && x1 >= ssfn_dst.w) ||
  210. (y0 < 36 && y1 < 36) || (y0 >= ssfn_dst.h && y1 >= ssfn_dst.h) || (x0 == x1 && y0 == y1)) return;
  211. sx = x1 >= x0? 1 : -1; sy = y1 >= y0? 1 : -1; dx = x1 - x0; dy = y1 - y0;
  212. if(sx * dx >= sy * dy && dx) {
  213. for(x = x0, m = sx * dx; m > 0; m -= dot, x += sx*dot) {
  214. y = y0 + ((x - x0) * dy / dx);
  215. if(y >= 36 && y < ssfn_dst.h && x >= 20 && x < ssfn_dst.w) win->data[y * win->p + x] = c;
  216. }
  217. } else {
  218. for(y = y0, m = sy * dy; m > 0; m -= dot, y += sy*dot) {
  219. x = x0 + ((y - y0) * dx / dy);
  220. if(x >= 20 && x < ssfn_dst.w && y >= 36 && y < ssfn_dst.h) win->data[y * win->p + x] = c;
  221. }
  222. }
  223. }
  224. /**
  225. * Draw Bezier curve
  226. */
  227. void ui_bezier(ui_win_t *win, int x0,int y0, int x1,int y1, int x2,int y2, int x3,int y3, uint32_t c, int l)
  228. {
  229. int m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y,m5x, m5y;
  230. if(l<8 && (x0!=x3 || y0!=y3)) {
  231. m0x = ((x1-x0)/2) + x0; m0y = ((y1-y0)/2) + y0;
  232. m1x = ((x2-x1)/2) + x1; m1y = ((y2-y1)/2) + y1;
  233. m2x = ((x3-x2)/2) + x2; m2y = ((y3-y2)/2) + y2;
  234. m3x = ((m1x-m0x)/2) + m0x; m3y = ((m1y-m0y)/2) + m0y;
  235. m4x = ((m2x-m1x)/2) + m1x; m4y = ((m2y-m1y)/2) + m1y;
  236. m5x = ((m4x-m3x)/2) + m3x; m5y = ((m4y-m3y)/2) + m3y;
  237. ui_bezier(win, x0,y0, m0x,m0y, m3x,m3y, m5x,m5y, c, l+1);
  238. ui_bezier(win, m5x,m5y, m4x,m4y, m2x,m2y, x3,y3, c, l+1);
  239. } else
  240. if(l) ui_line(win, x0,y0, x3,y3, 1, c);
  241. }
  242. /**
  243. * Render one layer
  244. */
  245. void ui_layer(ui_win_t *win, int x, int y, uint32_t unicode, int layer, int hl)
  246. {
  247. int i, j, k, l, m, n, p, lx, ly, mx, my, ox, oy, sx, sy, w = ctx.glyphs[unicode].width, h = ctx.glyphs[unicode].height;
  248. int a,b,A,B,C,D;
  249. uint32_t c = 0, f, f0, *uc = (uint32_t*)&ctx.cpal;
  250. uint8_t *bc = (uint8_t*)&f, *bc0 = (uint8_t*)&f0;
  251. sfnlayer_t *lyr = &ctx.glyphs[unicode].layers[layer];
  252. sfncont_t *cont;
  253. if(layer < 0 || layer >= ctx.glyphs[unicode].numlayer) return;
  254. cont = (sfncont_t*)ctx.glyphs[unicode].layers[layer].data;
  255. if(lyr->color >= 0xFE) f = theme[THEME_FG];
  256. else f = uc[lyr->color];
  257. if(!hl) f = (f & 0xFF000000) | ((f >> 1) & 0x7F7F7F);
  258. switch(lyr->type) {
  259. case SSFN_FRAG_CONTOUR:
  260. mx = my = lx = ly = -1; f0 = f;
  261. for(j = 0; j < lyr->len; j++, cont++) {
  262. if(hl == 2) { a = ((j+1) * 64 / lyr->len) - 64; bc[0] = bc0[0] + a; bc[1] = bc0[1] + a; bc[2] = bc0[2] + a; }
  263. a = (x + cont->px * win->zoom) << 8; b = (y + cont->py * win->zoom) << 8;
  264. switch(cont->type) {
  265. case SSFN_CONTOUR_MOVE: mx = a; my = b; break;
  266. case SSFN_CONTOUR_LINE: ui_line(win, lx, ly, a, b, 1, f); break;
  267. case SSFN_CONTOUR_QUAD:
  268. A = (x + cont->c1x * win->zoom) << 8; B = (y + cont->c1y * win->zoom) << 8;
  269. if(hl == 2) {
  270. ui_line(win, lx, ly, A, B, 5, theme[THEME_CURVE]);
  271. ui_line(win, A, B, a, b, 5, theme[THEME_CURVE]);
  272. }
  273. ui_bezier(win, lx, ly, (A - lx)/2+lx, (B - ly)/2+ly, (a - A)/2 + A, (b - B)/2 + B, a, b, f, 0);
  274. break;
  275. case SSFN_CONTOUR_CUBIC:
  276. A = (x + cont->c1x * win->zoom) << 8; B = (y + cont->c1y * win->zoom) << 8;
  277. C = (x + cont->c2x * win->zoom) << 8; D = (y + cont->c2y * win->zoom) << 8;
  278. if(hl == 2) {
  279. ui_line(win, lx, ly, A, B, 5, theme[THEME_CURVE]);
  280. ui_line(win, A, B, C, D, 5, theme[THEME_CURVE]);
  281. ui_line(win, C, D, a, b, 5, theme[THEME_CURVE]);
  282. }
  283. ui_bezier(win, lx, ly, A, B, C, D, a, b, f, 0);
  284. break;
  285. }
  286. lx = a; ly = b;
  287. }
  288. if(hl != 2 && ((lx > 0 && mx > 0 && lx != mx) || (ly > 0 && mx > 0 && ly != my)))
  289. ui_line(win, lx, ly, mx, my, 1, f);
  290. if(hl == 2) {
  291. cont = (sfncont_t*)ctx.glyphs[unicode].layers[layer].data;
  292. for(j = 0; j < lyr->len; j++, cont++) {
  293. a = (x + cont->px * win->zoom) << 8; b = (y + cont->py * win->zoom) << 8;
  294. switch(cont->type) {
  295. case SSFN_CONTOUR_MOVE: mx = a; my = b; break;
  296. case SSFN_CONTOUR_QUAD:
  297. A = (x + cont->c1x * win->zoom) << 8; B = (y + cont->c1y * win->zoom) << 8;
  298. ui_dot(win, A,B, 1);
  299. break;
  300. case SSFN_CONTOUR_CUBIC:
  301. A = (x + cont->c1x * win->zoom) << 8; B = (y + cont->c1y * win->zoom) << 8;
  302. C = (x + cont->c2x * win->zoom) << 8; D = (y + cont->c2y * win->zoom) << 8;
  303. ui_dot(win, A,B, 1);
  304. ui_dot(win, C,D, 1);
  305. break;
  306. }
  307. ui_dot(win, a, b, 0);
  308. lx = a; ly = b;
  309. }
  310. }
  311. break;
  312. case SSFN_FRAG_BITMAP:
  313. case SSFN_FRAG_PIXMAP:
  314. for(j = 0; j < h && y < ssfn_dst.h; j++, y += win->zoom) {
  315. if(y + win->zoom >= 36) {
  316. if(y < 36) { oy = 36-y; sy = y + win->zoom - 36; } else { oy = 0; sy = win->zoom; }
  317. for(i = 0, k = x; i < w && k < ssfn_dst.w; i++, k += win->zoom)
  318. if(k + win->zoom >= 20) {
  319. if(k < 20) { ox = 20-k; sx = k + win->zoom - 20; } else { ox = 0; sx = win->zoom; }
  320. l = lyr->data[j * w + i];
  321. if(l < 0xFF) {
  322. if(l == 0xFE) c = f;
  323. else {
  324. c = uc[l];
  325. if(!hl) c = (c & 0xFF000000) | ((c >> 1) & 0x7F7F7F);
  326. }
  327. p = (y + oy) * win->p + (k + ox);
  328. for(m=0; m < sy && y + oy + m < ssfn_dst.h; m++, p += win->p)
  329. for(n=0; n < sx && k + ox + n < ssfn_dst.w; n++)
  330. win->data[p + n] = c;
  331. }
  332. }
  333. }
  334. }
  335. break;
  336. }
  337. }
  338. /**
  339. * This is a special renderer that must not use anti-aliasing
  340. * and uses crop to render the glyph just partially
  341. */
  342. void ui_edit(ui_win_t *win, int x, int y, uint32_t unicode, int layer)
  343. {
  344. int i;
  345. if(unicode > 0x10FFFF) return;
  346. for(i = 0; i < ctx.glyphs[unicode].numlayer; i++)
  347. if(i != layer)
  348. ui_layer(win, x, y, unicode, i, layer == -1 ? 1 : 0);
  349. if(layer != -1 && layer < ctx.glyphs[unicode].numlayer)
  350. ui_layer(win, x, y, unicode, layer, 2);
  351. }