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
54 memcpy(bufcur - 6, dummy, 6);
55
56 bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)
57
58 // write CRC32
59 *bufcur++ = objcrc & 0xff;
60 *bufcur++ = (objcrc >> 8) & 0xff;
61 *bufcur++ = (objcrc >> 16) & 0xff;
62 *bufcur++ = (objcrc >> 24) & 0xff;
63
64 // write original data length
65 *bufcur++ = objlen & 0xff;
66 *bufcur++ = (objlen >> 8) & 0xff;
67 *bufcur++ = (objlen >> 16) & 0xff;
68 *bufcur++ = (objlen >> 24) & 0xff;
69
70 result.resize(bufcur - result.data());
71 result.shrink_to_fit();
72}
73} // namespace
74
75// struct SdfCreator
76// {
77// ...
78// int max_tex_size = 4096;
79// int width = 1024; // atlas image width in pixels
80// int height = 0; // atlas image height in pixels (optional, automatic)
81// int row_height = 96; // row height in pixels (without SDF border)
82// int border_size = 16; // SDF distance in pixels, default 16
83// ...
84// void parse_unicode_ranges( const std::string &nword );
85// e.g.: 'start1:end1,start:end2,single_codepoint' without spaces!
86// default: '31:126,0xffff'
87// };
88
89////////////////////////////////////////////////////////////////////////////////
90/// Converts TTF font 'ttf_font' into a SDF font texture atlas (png format) and
91/// a compressed font metrics JSON file. Both files are put into the directory
92/// given by 'output_prefix'.
93
94int TGLSdfFontMaker::MakeFont(const char *ttf_font, const char *output_prefix, bool verbose)
95{
96 if (verbose)
97 printf("TGLSdfFontMaker::MakeFont entering.\n");
98
99 const std::string base = "31:126";
100 const std::string accented = ",0x00e0:0x00fc,0x010c:0x010d,0x0160:0x0161,0x017d:0x017e";
101 const std::string greek = ",0x0391:0x03a9,0x03b1:0x03c9";
102 const std::string range_end = ",0xffff";
103
104 root_sdf_fonts::SdfCreator sc;
105
106 // Minimal gl-widget / context.
107 std::unique_ptr<TGLWidget> glw(
108 TGLWidget::Create(TGLFormat(Rgl::kNone), gClient->GetDefaultRoot(), false, false, nullptr, 1, 1));
109 glw->MakeCurrent();
110
111 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &sc.max_tex_size);
112
113 std::string filename = ttf_font;
114 std::string res_filename = output_prefix;
115
116 if (filename.empty()) {
117 std::cerr << "Input file not specified" << std::endl;
118 return (1);
119 }
120
121 if (res_filename.empty()) {
122 size_t ext_dot = filename.find_last_of(".");
123 if (ext_dot == std::string::npos) {
124 res_filename = filename;
125 } else {
126 res_filename = filename.substr(0, ext_dot);
127 }
128 }
129
130 if (!sc.font.load_ttf_file(filename.c_str())) {
131 std::cerr << "Error reading TTF file '" << filename << "' " << std::endl;
132 return (1);
133 }
134
135 // Allocating glyph rects
136
137 sc.sdf_atlas.init(&sc.font, sc.width, sc.row_height, sc.border_size);
138
139 sc.parse_unicode_ranges(base + accented + greek + range_end);
140 sc.apply_unicode_ranges();
141
142 sc.sdf_atlas.draw_glyphs(sc.gp);
143
144 if (verbose) {
145 std::cout << "Allocated " << sc.sdf_atlas.glyph_count << " glyphs\n";
146 std::cout << "Atlas maximum height is " << sc.sdf_atlas.max_height << "\n";
147 }
148
149 if (sc.height == 0) {
150 sc.height = sc.sdf_atlas.max_height;
151 }
152
153 // GL initialization
154
155 sc.sdf_gl.init();
156
157 GLuint rbcolor;
158 glGenRenderbuffers(1, &rbcolor);
159 glBindRenderbuffer(GL_RENDERBUFFER, rbcolor);
160 glRenderbufferStorage(GL_RENDERBUFFER, GL_RED, sc.width, sc.height);
161 glBindRenderbuffer(GL_RENDERBUFFER, 0);
162
163 GLuint rbds;
164 glGenRenderbuffers(1, &rbds);
165 glBindRenderbuffer(GL_RENDERBUFFER, rbds);
166 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, sc.width, sc.height);
167 glBindRenderbuffer(GL_RENDERBUFFER, 0);
168
169 GLuint fbo;
170 glGenFramebuffers(1, &fbo);
171 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
172 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbcolor);
173 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbds);
174
175 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
176 std::cerr << "Error creating framebuffer!" << std::endl;
177 return (1);
178 }
179
180 // Rendering glyphs
181
182 uint8_t *picbuf = (uint8_t *)malloc(sc.width * sc.height);
183
184 glViewport(0, 0, sc.width, sc.height);
185 glClearColor(0.0, 0.0, 0.0, 0.0);
186 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
187
188 sc.sdf_gl.render_sdf({float(sc.width), float(sc.height)}, sc.gp.fp.vertices, sc.gp.lp.vertices);
189
190 glReadPixels(0, 0, sc.width, sc.height, GL_RED, GL_UNSIGNED_BYTE, picbuf);
191
192 glBindFramebuffer(GL_FRAMEBUFFER, 0);
193 glFinish();
194
195 if (verbose)
196 printf("Resulting GL buffer: w=%d, h=%d\n", sc.width, sc.height);
197
198 TASPngWriter pw(sc.width, sc.height, 0, 8);
199 pw.ref_row_pointers().resize(sc.height);
200 for (int iy = 0; iy < sc.height; ++iy) {
201 pw.ref_row_pointers()[sc.height - iy - 1] = picbuf + iy * sc.width;
202 }
203
204 pw.write_png_file(res_filename + ".png");
205
206 free(picbuf);
207
208 // Saving JSON
209
210 std::string json = sc.sdf_atlas.json(sc.height);
211 std::vector<char> json_gz;
212 gzip_compress_buffer(json.data(), json.size(), json_gz);
213
214 std::string json_filename = res_filename + ".js.gz";
215 FILE *json_file = fopen(json_filename.c_str(), "wb");
216 if (!json_file) {
217 perror("Error writing json file.");
218 return errno;
219 }
220 fwrite(json_gz.data(), json_gz.size(), 1, json_file);
221 fclose(json_file);
222
223 return 0;
224}
nlohmann::json json
#define gClient
Definition TGClient.h:156
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:1539
#define malloc
Definition civetweb.c:1536
C++ wrapper over simple writer of PNG files for standard GL memory formats: LUMINANCE,...
Definition TASPngWriter.h:7
std::vector< unsigned char * > & ref_row_pointers()
int write_png_file(std::string_view filename)
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:83
@ kNone
Definition TVirtualGL.h:128