Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
4.5 KiB

  1. #define STB_DEFINE
  2. #include "stb.h"
  3. #define STB_TRUETYPE_IMPLEMENTATION
  4. #include "stb_truetype.h"
  5. #define STB_IMAGE_WRITE_IMPLEMENTATION
  6. #include "stb_image_write.h"
  7. // used both to compute SDF and in 'shader'
  8. float sdf_size = 32.0; // the larger this is, the better large font sizes look
  9. float pixel_dist_scale = 64.0; // trades off precision w/ ability to handle *smaller* sizes
  10. int onedge_value = 128;
  11. int padding = 3; // not used in shader
  12. typedef struct
  13. {
  14. float advance;
  15. signed char xoff;
  16. signed char yoff;
  17. unsigned char w,h;
  18. unsigned char *data;
  19. } fontchar;
  20. fontchar fdata[128];
  21. #define BITMAP_W 1200
  22. #define BITMAP_H 800
  23. unsigned char bitmap[BITMAP_H][BITMAP_W][3];
  24. char *sample = "This is goofy text, size %d!";
  25. char *small_sample = "This is goofy text, size %d! Really needs in-shader supersampling to look good.";
  26. void blend_pixel(int x, int y, int color, float alpha)
  27. {
  28. int i;
  29. for (i=0; i < 3; ++i)
  30. bitmap[y][x][i] = (unsigned char) (stb_lerp(alpha, bitmap[y][x][i], color)+0.5); // round
  31. }
  32. void draw_char(float px, float py, char c, float relative_scale)
  33. {
  34. int x,y;
  35. fontchar *fc = &fdata[c];
  36. float fx0 = px + fc->xoff*relative_scale;
  37. float fy0 = py + fc->yoff*relative_scale;
  38. float fx1 = fx0 + fc->w*relative_scale;
  39. float fy1 = fy0 + fc->h*relative_scale;
  40. int ix0 = (int) floor(fx0);
  41. int iy0 = (int) floor(fy0);
  42. int ix1 = (int) ceil(fx1);
  43. int iy1 = (int) ceil(fy1);
  44. // clamp to viewport
  45. if (ix0 < 0) ix0 = 0;
  46. if (iy0 < 0) iy0 = 0;
  47. if (ix1 > BITMAP_W) ix1 = BITMAP_W;
  48. if (iy1 > BITMAP_H) iy1 = BITMAP_H;
  49. for (y=iy0; y < iy1; ++y) {
  50. for (x=ix0; x < ix1; ++x) {
  51. float sdf_dist, pix_dist;
  52. float bmx = stb_linear_remap(x, fx0, fx1, 0, fc->w);
  53. float bmy = stb_linear_remap(y, fy0, fy1, 0, fc->h);
  54. int v00,v01,v10,v11;
  55. float v0,v1,v;
  56. int sx0 = (int) bmx;
  57. int sx1 = sx0+1;
  58. int sy0 = (int) bmy;
  59. int sy1 = sy0+1;
  60. // compute lerp weights
  61. bmx = bmx - sx0;
  62. bmy = bmy - sy0;
  63. // clamp to edge
  64. sx0 = stb_clamp(sx0, 0, fc->w-1);
  65. sx1 = stb_clamp(sx1, 0, fc->w-1);
  66. sy0 = stb_clamp(sy0, 0, fc->h-1);
  67. sy1 = stb_clamp(sy1, 0, fc->h-1);
  68. // bilinear texture sample
  69. v00 = fc->data[sy0*fc->w+sx0];
  70. v01 = fc->data[sy0*fc->w+sx1];
  71. v10 = fc->data[sy1*fc->w+sx0];
  72. v11 = fc->data[sy1*fc->w+sx1];
  73. v0 = stb_lerp(bmx,v00,v01);
  74. v1 = stb_lerp(bmx,v10,v11);
  75. v = stb_lerp(bmy,v0 ,v1 );
  76. #if 0
  77. // non-anti-aliased
  78. if (v > onedge_value)
  79. blend_pixel(x,y,0,1.0);
  80. #else
  81. // Following math can be greatly simplified
  82. // convert distance in SDF value to distance in SDF bitmap
  83. sdf_dist = stb_linear_remap(v, onedge_value, onedge_value+pixel_dist_scale, 0, 1);
  84. // convert distance in SDF bitmap to distance in output bitmap
  85. pix_dist = sdf_dist * relative_scale;
  86. // anti-alias by mapping 1/2 pixel around contour from 0..1 alpha
  87. v = stb_linear_remap(pix_dist, -0.5f, 0.5f, 0, 1);
  88. if (v > 1) v = 1;
  89. if (v > 0)
  90. blend_pixel(x,y,0,v);
  91. #endif
  92. }
  93. }
  94. }
  95. void print_text(float x, float y, char *text, float scale)
  96. {
  97. int i;
  98. for (i=0; text[i]; ++i) {
  99. if (fdata[text[i]].data)
  100. draw_char(x,y,text[i],scale);
  101. x += fdata[text[i]].advance * scale;
  102. }
  103. }
  104. int main(int argc, char **argv)
  105. {
  106. int ch;
  107. float scale, ypos;
  108. stbtt_fontinfo font;
  109. void *data = stb_file("c:/windows/fonts/times.ttf", NULL);
  110. stbtt_InitFont(&font, data, 0);
  111. scale = stbtt_ScaleForPixelHeight(&font, sdf_size);
  112. for (ch=32; ch < 127; ++ch) {
  113. fontchar fc;
  114. int xoff,yoff,w,h, advance;
  115. fc.data = stbtt_GetCodepointSDF(&font, scale, ch, padding, onedge_value, pixel_dist_scale, &w, &h, &xoff, &yoff);
  116. fc.xoff = xoff;
  117. fc.yoff = yoff;
  118. fc.w = w;
  119. fc.h = h;
  120. stbtt_GetCodepointHMetrics(&font, ch, &advance, NULL);
  121. fc.advance = advance * scale;
  122. fdata[ch] = fc;
  123. }
  124. ypos = 60;
  125. memset(bitmap, 255, sizeof(bitmap));
  126. print_text(400, ypos+30, stb_sprintf("sdf bitmap height %d", (int) sdf_size), 30/sdf_size);
  127. ypos += 80;
  128. for (scale = 8.0; scale < 120.0; scale *= 1.33f) {
  129. print_text(80, ypos+scale, stb_sprintf(scale == 8.0 ? small_sample : sample, (int) scale), scale / sdf_size);
  130. ypos += scale*1.05f + 20;
  131. }
  132. stbi_write_png("sdf_test.png", BITMAP_W, BITMAP_H, 3, bitmap, 0);
  133. return 0;
  134. }