Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TGLSdfFontMaker.cxx
Go to the documentation of this file.
1#include "TGLSdfFontMaker.h"
2#include "TGLWidget.h"
3#include "TGClient.h"
4#include "TGLIncludes.h"
5#include "TASPngWriter.h"
6#include "RZip.h"
7
8#include <cstdio>
9
10#include "TGLSdfFontMakerLowLevel.icxx"
11
12/** \class TGLSdfFontMaker
13\ingroup opengl
14
15Helper class for generation of Signed Distance Field (SDF) fonts for REve.
16
17*/
18
19namespace {
20
21// cloned from THttpCallArg::CompressWithGzip()
22
23void gzip_compress_buffer(const char *objbuf, const size_t objlen, std::vector<char> &result)
24{
25 unsigned long objcrc = R__crc32(0, NULL, 0);
26 objcrc = R__crc32(objcrc, (const unsigned char *)objbuf, objlen);
27
28 // 10 bytes (ZIP header), compressed data, 8 bytes (CRC and original length)
29 int buflen = 10 + objlen + 8;
30 if (buflen < 512)
31 buflen = 512;
32
33 result.resize(buflen);
34
35 char *bufcur = result.data();
36
37 *bufcur++ = 0x1f; // first byte of ZIP identifier
38 *bufcur++ = 0x8b; // second byte of ZIP identifier
39 *bufcur++ = 0x08; // compression method
40 *bufcur++ = 0x00; // FLAG - empty, no any file names
41 *bufcur++ = 0; // empty timestamp
42 *bufcur++ = 0; //
43 *bufcur++ = 0; //
44 *bufcur++ = 0; //
45 *bufcur++ = 0; // XFL (eXtra FLags)
46 *bufcur++ = 3; // OS 3 means Unix
47
48 char dummy[8];
49 memcpy(dummy, bufcur - 6, 6);
50
51 // R__memcompress fills first 6 bytes with own header, therefore just overwrite them
52 unsigned long ziplen = R__memcompress(bufcur - 6, objlen + 6, (char *)objbuf, objlen);
53 if (!ziplen) {
54 // failure - return empty result
55 result.clear();
56 return;
57 }
58
59 memcpy(bufcur - 6, dummy, 6);
60
61 bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)
62
63 // write CRC32
64 *bufcur++ = objcrc & 0xff;
65 *bufcur++ = (objcrc >> 8) & 0xff;
66 *bufcur++ = (objcrc >> 16) & 0xff;
67 *bufcur++ = (objcrc >> 24) & 0xff;
68
69 // write original data length
70 *bufcur++ = objlen & 0xff;
71 *bufcur++ = (objlen >> 8) & 0xff;
72 *bufcur++ = (objlen >> 16) & 0xff;
73 *bufcur++ = (objlen >> 24) & 0xff;
74
75 result.resize(bufcur - result.data());
76 result.shrink_to_fit();
77}
78} // namespace
79
80// struct SdfCreator
81// {
82// ...
83// int max_tex_size = 4096;
84// int width = 1024; // atlas image width in pixels
85// int height = 0; // atlas image height in pixels (optional, automatic)
86// int row_height = 96; // row height in pixels (without SDF border)
87// int border_size = 16; // SDF distance in pixels, default 16
88// ...
89// void parse_unicode_ranges( const std::string &nword );
90// e.g.: 'start1:end1,start:end2,single_codepoint' without spaces!
91// default: '31:126,0xffff'
92// };
93
94////////////////////////////////////////////////////////////////////////////////
95/// Converts TTF font 'ttf_font' into a SDF font texture atlas (png format) and
96/// a compressed font metrics JSON file. Both files are put into the directory
97/// given by 'output_prefix'.
98
99int TGLSdfFontMaker::MakeFont(const char *ttf_font, const char *output_prefix, bool verbose)
100{
101 if (verbose)
102 printf("TGLSdfFontMaker::MakeFont entering.\n");
103
104 const std::string base = "31:126";
105 const std::string accented = ",0x00e0:0x00fc,0x010c:0x010d,0x0160:0x0161,0x017d:0x017e";
106 const std::string greek = ",0x0391:0x03a9,0x03b1:0x03c9";
107 const std::string range_end = ",0xffff";
108
109 root_sdf_fonts::SdfCreator sc;
110
111 // Minimal gl-widget / context.
112 std::unique_ptr<TGLWidget> glw(
113 TGLWidget::Create(TGLFormat(Rgl::kNone), gClient->GetDefaultRoot(), false, false, nullptr, 1, 1));
114 glw->MakeCurrent();
115
117
118 std::string filename = ttf_font;
119 std::string res_filename = output_prefix;
120
121 if (filename.empty()) {
122 std::cerr << "Input file not specified" << std::endl;
123 return (1);
124 }
125
126 if (res_filename.empty()) {
127 size_t ext_dot = filename.find_last_of(".");
128 if (ext_dot == std::string::npos) {
130 } else {
131 res_filename = filename.substr(0, ext_dot);
132 }
133 }
134
135 if (!sc.font.load_ttf_file(filename.c_str())) {
136 std::cerr << "Error reading TTF file '" << filename << "' " << std::endl;
137 return (1);
138 }
139
140 // Allocating glyph rects
141
142 sc.sdf_atlas.init(&sc.font, sc.width, sc.row_height, sc.border_size);
143
144 sc.parse_unicode_ranges(base + accented + greek + range_end);
145 sc.apply_unicode_ranges();
146
147 sc.sdf_atlas.draw_glyphs(sc.gp);
148
149 if (verbose) {
150 std::cout << "Allocated " << sc.sdf_atlas.glyph_count << " glyphs\n";
151 std::cout << "Atlas maximum height is " << sc.sdf_atlas.max_height << "\n";
152 }
153
154 if (sc.height == 0) {
155 sc.height = sc.sdf_atlas.max_height;
156 }
157
158 // GL initialization
159
160 sc.sdf_gl.init();
161
167
168 GLuint rbds;
173
174 GLuint fbo;
179
181 std::cerr << "Error creating framebuffer!" << std::endl;
182 return (1);
183 }
184
185 // Rendering glyphs
186
187 uint8_t *picbuf = (uint8_t *)malloc(sc.width * sc.height);
188
189 glViewport(0, 0, sc.width, sc.height);
190 glClearColor(0.0, 0.0, 0.0, 0.0);
192
193 sc.sdf_gl.render_sdf({float(sc.width), float(sc.height)}, sc.gp.fp.vertices, sc.gp.lp.vertices);
194
195 glReadPixels(0, 0, sc.width, sc.height, GL_RED, GL_UNSIGNED_BYTE, picbuf);
196
198 glFinish();
199
200 if (verbose)
201 printf("Resulting GL buffer: w=%d, h=%d\n", sc.width, sc.height);
202
203 TASPngWriter pw(sc.width, sc.height, 0, 8);
204 pw.ref_row_pointers().resize(sc.height);
205 for (int iy = 0; iy < sc.height; ++iy) {
206 pw.ref_row_pointers()[sc.height - iy - 1] = picbuf + iy * sc.width;
207 }
208
209 pw.write_png_file(res_filename + ".png");
210
211 free(picbuf);
212
213 // Saving JSON
214
215 std::string json = sc.sdf_atlas.json(sc.height);
216 std::vector<char> json_gz;
217 gzip_compress_buffer(json.data(), json.size(), json_gz);
218
219 std::string json_filename = res_filename + ".js.gz";
220 FILE *json_file = fopen(json_filename.c_str(), "wb");
221 if (!json_file) {
222 perror("Error writing json file.");
223 return errno;
224 }
225 fwrite(json_gz.data(), json_gz.size(), 1, json_file);
227
228 return 0;
229}
nlohmann::json json
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gClient
Definition TGClient.h:157
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
#define free
Definition civetweb.c:1578
#define malloc
Definition civetweb.c:1575
C++ wrapper over simple writer of PNG files for standard GL memory formats: LUMINANCE,...
Definition TASPngWriter.h:7
Encapsulation of format / contents of an OpenGL buffer.
Definition TGLFormat.h:36
static int MakeFont(const char *ttf_font, const char *output_prefix, bool verbose=false)
Converts TTF font 'ttf_font' into a SDF font texture atlas (png format) and a compressed font metrics...
static TGLWidget * Create(const TGWindow *parent, Bool_t selectInput, Bool_t shareDefault, const TGLPaintDevice *shareDevice, UInt_t width, UInt_t height)
Static constructor for creating widget with default pixel format.
Definition TGLWidget.cxx:82
@ kNone
Definition TVirtualGL.h:128