File indexing completed on 2026-04-09 07:49:55
0001 #pragma once
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include <cstdio>
0017 #include <cstdlib>
0018 #ifdef OPTICKS_SYSRAP
0019 #include "sconfig.h"
0020 #endif
0021
0022 struct STTF
0023 {
0024 static constexpr const char* KEY = "OPTICKS_STTF_PATH" ;
0025
0026 static STTF* Create();
0027 static const char* GetFontPath();
0028 static unsigned char* Load(const char* path);
0029
0030 const char* fontPath ;
0031 unsigned char* fontBuffer ;
0032 void* font_ ;
0033 bool valid ;
0034
0035 STTF() ;
0036 virtual ~STTF();
0037
0038 void init();
0039 int render_background( unsigned char* bitmap, int channels, int width, int height, int* color );
0040 int render_text( unsigned char* bitmap, int channels, int width, int line_height, const char* text );
0041
0042 int annotate( unsigned char* bitmap, int channels, int width, int height, int line_height, const char* text, bool bottom );
0043
0044 };
0045
0046
0047
0048
0049 #ifdef __clang__
0050
0051
0052 #elif defined(__GNUC__) || defined(__GNUG__)
0053
0054 #pragma GCC diagnostic push
0055 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
0056 #pragma GCC diagnostic ignored "-Wsign-compare"
0057
0058 #elif defined(_MSC_VER)
0059
0060 #endif
0061
0062
0063 #ifdef STTF_IMPLEMENTATION
0064
0065 #define STB_TRUETYPE_IMPLEMENTATION
0066 #include "stb_truetype.h"
0067
0068 #endif
0069
0070 #ifdef __clang__
0071 #elif defined(__GNUC__) || defined(__GNUG__)
0072
0073 #pragma GCC diagnostic pop
0074
0075 #elif defined(_MSC_VER)
0076 #endif
0077
0078
0079
0080
0081 inline STTF* STTF::Create()
0082 {
0083 STTF* ttf = new STTF ;
0084 if(!ttf->valid)
0085 {
0086 printf("STTF::Create : failed to initialize font \n");
0087 return nullptr ;
0088 }
0089 return ttf ;
0090 }
0091
0092
0093
0094 inline const char* STTF::GetFontPath()
0095 {
0096 #ifdef OPTICKS_SYSRAP
0097 const char* dpath = sconfig::DefaultSTTFPath() ;
0098 #else
0099 const char* dpath = nullptr ;
0100 #endif
0101 const char* epath = getenv(KEY) ;
0102
0103 return epath ? epath : dpath ;
0104 }
0105
0106 inline unsigned char* STTF::Load(const char* path)
0107 {
0108 if(path == nullptr)
0109 {
0110 printf("STTF::Load : Envvar %s with path to ttf font file, eg Cousine-Regular.ttf, is required \n", KEY);
0111 return nullptr ;
0112 }
0113
0114 #ifdef DEBUG
0115 printf("STTF::Load font from %s\n", path );
0116 #endif
0117
0118 long size ;
0119 FILE* fontFile = fopen(path, "rb");
0120
0121 if( fontFile == nullptr )
0122 {
0123 printf("STTF::Load failed to open %s\n", path);
0124 return nullptr ;
0125 }
0126
0127 fseek(fontFile, 0, SEEK_END);
0128 size = ftell(fontFile);
0129 fseek(fontFile, 0, SEEK_SET);
0130
0131 unsigned char* buffer = (unsigned char*)malloc(size);
0132
0133 fread(buffer, size, 1, fontFile);
0134 fclose(fontFile);
0135
0136 return buffer ;
0137 }
0138
0139
0140
0141 inline STTF::STTF()
0142 :
0143 fontPath(GetFontPath()),
0144 fontBuffer(Load(fontPath)),
0145 font_(nullptr),
0146 valid(false)
0147 {
0148 init();
0149 }
0150
0151
0152
0153 inline void STTF::init()
0154 {
0155 if(fontBuffer == nullptr)
0156 {
0157 printf("STTF::init failed : no font file has been loaded \n");
0158 return ;
0159 }
0160
0161 stbtt_fontinfo* font = new stbtt_fontinfo ;
0162 if (!stbtt_InitFont(font, fontBuffer, 0))
0163 {
0164 printf("STTF::init failed : loaded font file is not a valid TTF font ? \n");
0165 return ;
0166 }
0167
0168 font_ = (void*)font ;
0169 valid = true ;
0170 }
0171
0172
0173 inline STTF::~STTF()
0174 {
0175 stbtt_fontinfo* font = (stbtt_fontinfo*)font_ ;
0176 delete font ;
0177 free(fontBuffer);
0178 }
0179
0180
0181 inline int STTF::render_background( unsigned char* bitmap, int channels, int width, int line_height, int* color )
0182 {
0183 for(int y=0 ; y < line_height ; y++ )
0184 {
0185 for(int x=0 ; x < width ; x++)
0186 {
0187 for(int c = 0 ; c < channels ; c++ )
0188 {
0189 bitmap[ (y*width + x)*channels + c] = color[c] ;
0190 }
0191 }
0192 }
0193 return 0 ;
0194 }
0195
0196 inline int STTF::render_text( unsigned char* bitmap, int channels, int width, int line_height, const char* text )
0197 {
0198 if(!valid) return 1 ;
0199 stbtt_fontinfo* font = (stbtt_fontinfo*)font_ ;
0200
0201 #ifdef DEBUG
0202 printf("STTF::render_text channels %d \n", channels );
0203 #endif
0204
0205 float pixels = float(line_height);
0206 float scale = stbtt_ScaleForPixelHeight(font, pixels);
0207
0208
0209
0210
0211
0212
0213
0214
0215 int ascent, descent, lineGap;
0216 stbtt_GetFontVMetrics(font, &ascent, &descent, &lineGap);
0217
0218
0219
0220
0221
0222
0223
0224 ascent = roundf(ascent * scale);
0225 descent = roundf(descent * scale);
0226
0227 int x = 0;
0228
0229
0230 while(*text && x + pixels < width)
0231 {
0232 int codepoint = *text ;
0233
0234 int ax;
0235 int lsb;
0236 stbtt_GetCodepointHMetrics(font, codepoint, &ax, &lsb);
0237 ax = roundf(ax*scale) ;
0238 lsb = roundf(lsb*scale) ;
0239
0240
0241 int ix0, iy0, ix1, iy1;
0242 stbtt_GetCodepointBitmapBox(font, codepoint, scale, scale, &ix0, &iy0, &ix1, &iy1);
0243
0244
0245
0246
0247
0248
0249 int y = ascent + iy0 ;
0250 int offset = x + lsb + (y * width);
0251
0252 unsigned char* output = bitmap + offset*channels ;
0253 int out_w = (ix1-ix0)*channels ;
0254 int out_h = (iy1-iy0) ;
0255 int out_stride = width*channels ;
0256
0257 float scale_x = scale*channels ;
0258 float scale_y = scale ;
0259
0260 stbtt_MakeCodepointBitmap(font, output, out_w, out_h, out_stride, scale_x, scale_y, codepoint );
0261
0262
0263
0264
0265
0266 int kern;
0267 kern = stbtt_GetCodepointKernAdvance(font, *text, *(text+1));
0268 kern = roundf(kern * scale) ;
0269
0270 x += ax + kern ;
0271
0272
0273 text++ ;
0274 }
0275 return 0 ;
0276 }
0277
0278
0279 inline int STTF::annotate( unsigned char* bitmap, int channels, int width, int height, int line_height, const char* text, bool bottom )
0280 {
0281 int rc = 1 ;
0282 if(!valid) return rc ;
0283
0284
0285
0286 int black[4] = {0,0,0,0} ;
0287
0288 int margin_bkg = 0 ;
0289 int margin_txt = 1 ;
0290
0291 int offset_bkg = bottom ? width*(height-line_height-margin_bkg)*channels : 0 ;
0292 int offset_txt = bottom ? width*(height-line_height-margin_txt)*channels : 0 ;
0293
0294 rc = render_background( bitmap+offset_bkg, channels, width, line_height, black ) ;
0295 rc = render_text( bitmap+offset_txt, channels, width, line_height, text ) ;
0296 return rc ;
0297 }
0298
0299
0300