123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- #define STB_DEFINE
- #include "stb.h"
- #define STB_TRUETYPE_IMPLEMENTATION
- #include "stb_truetype.h"
- #define STB_IMAGE_WRITE_IMPLEMENTATION
- #include "stb_image_write.h"
- // used both to compute SDF and in 'shader'
- float sdf_size = 32.0; // the larger this is, the better large font sizes look
- float pixel_dist_scale = 64.0; // trades off precision w/ ability to handle *smaller* sizes
- int onedge_value = 128;
- int padding = 3; // not used in shader
- typedef struct
- {
- float advance;
- signed char xoff;
- signed char yoff;
- unsigned char w,h;
- unsigned char *data;
- } fontchar;
- fontchar fdata[128];
- #define BITMAP_W 1200
- #define BITMAP_H 800
- unsigned char bitmap[BITMAP_H][BITMAP_W][3];
- char *sample = "This is goofy text, size %d!";
- char *small_sample = "This is goofy text, size %d! Really needs in-shader supersampling to look good.";
- void blend_pixel(int x, int y, int color, float alpha)
- {
- int i;
- for (i=0; i < 3; ++i)
- bitmap[y][x][i] = (unsigned char) (stb_lerp(alpha, bitmap[y][x][i], color)+0.5); // round
- }
- void draw_char(float px, float py, char c, float relative_scale)
- {
- int x,y;
- fontchar *fc = &fdata[c];
- float fx0 = px + fc->xoff*relative_scale;
- float fy0 = py + fc->yoff*relative_scale;
- float fx1 = fx0 + fc->w*relative_scale;
- float fy1 = fy0 + fc->h*relative_scale;
- int ix0 = (int) floor(fx0);
- int iy0 = (int) floor(fy0);
- int ix1 = (int) ceil(fx1);
- int iy1 = (int) ceil(fy1);
- // clamp to viewport
- if (ix0 < 0) ix0 = 0;
- if (iy0 < 0) iy0 = 0;
- if (ix1 > BITMAP_W) ix1 = BITMAP_W;
- if (iy1 > BITMAP_H) iy1 = BITMAP_H;
- for (y=iy0; y < iy1; ++y) {
- for (x=ix0; x < ix1; ++x) {
- float sdf_dist, pix_dist;
- float bmx = stb_linear_remap(x, fx0, fx1, 0, fc->w);
- float bmy = stb_linear_remap(y, fy0, fy1, 0, fc->h);
- int v00,v01,v10,v11;
- float v0,v1,v;
- int sx0 = (int) bmx;
- int sx1 = sx0+1;
- int sy0 = (int) bmy;
- int sy1 = sy0+1;
- // compute lerp weights
- bmx = bmx - sx0;
- bmy = bmy - sy0;
- // clamp to edge
- sx0 = stb_clamp(sx0, 0, fc->w-1);
- sx1 = stb_clamp(sx1, 0, fc->w-1);
- sy0 = stb_clamp(sy0, 0, fc->h-1);
- sy1 = stb_clamp(sy1, 0, fc->h-1);
- // bilinear texture sample
- v00 = fc->data[sy0*fc->w+sx0];
- v01 = fc->data[sy0*fc->w+sx1];
- v10 = fc->data[sy1*fc->w+sx0];
- v11 = fc->data[sy1*fc->w+sx1];
- v0 = stb_lerp(bmx,v00,v01);
- v1 = stb_lerp(bmx,v10,v11);
- v = stb_lerp(bmy,v0 ,v1 );
- #if 0
- // non-anti-aliased
- if (v > onedge_value)
- blend_pixel(x,y,0,1.0);
- #else
- // Following math can be greatly simplified
- // convert distance in SDF value to distance in SDF bitmap
- sdf_dist = stb_linear_remap(v, onedge_value, onedge_value+pixel_dist_scale, 0, 1);
- // convert distance in SDF bitmap to distance in output bitmap
- pix_dist = sdf_dist * relative_scale;
- // anti-alias by mapping 1/2 pixel around contour from 0..1 alpha
- v = stb_linear_remap(pix_dist, -0.5f, 0.5f, 0, 1);
- if (v > 1) v = 1;
- if (v > 0)
- blend_pixel(x,y,0,v);
- #endif
- }
- }
- }
- void print_text(float x, float y, char *text, float scale)
- {
- int i;
- for (i=0; text[i]; ++i) {
- if (fdata[text[i]].data)
- draw_char(x,y,text[i],scale);
- x += fdata[text[i]].advance * scale;
- }
- }
- int main(int argc, char **argv)
- {
- int ch;
- float scale, ypos;
- stbtt_fontinfo font;
- void *data = stb_file("c:/windows/fonts/times.ttf", NULL);
- stbtt_InitFont(&font, data, 0);
- scale = stbtt_ScaleForPixelHeight(&font, sdf_size);
- for (ch=32; ch < 127; ++ch) {
- fontchar fc;
- int xoff,yoff,w,h, advance;
- fc.data = stbtt_GetCodepointSDF(&font, scale, ch, padding, onedge_value, pixel_dist_scale, &w, &h, &xoff, &yoff);
- fc.xoff = xoff;
- fc.yoff = yoff;
- fc.w = w;
- fc.h = h;
- stbtt_GetCodepointHMetrics(&font, ch, &advance, NULL);
- fc.advance = advance * scale;
- fdata[ch] = fc;
- }
- ypos = 60;
- memset(bitmap, 255, sizeof(bitmap));
- print_text(400, ypos+30, stb_sprintf("sdf bitmap height %d", (int) sdf_size), 30/sdf_size);
- ypos += 80;
- for (scale = 8.0; scale < 120.0; scale *= 1.33f) {
- print_text(80, ypos+scale, stb_sprintf(scale == 8.0 ? small_sample : sample, (int) scale), scale / sdf_size);
- ypos += scale*1.05f + 20;
- }
- stbi_write_png("sdf_test.png", BITMAP_W, BITMAP_H, 3, bitmap, 0);
- return 0;
- }
|