1 /*
2  * Copyright 2013 Jeremie Roy. All rights reserved.
3  * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
4  */
5 
6 #include "common.h"
7 #include "bgfx_utils.h"
8 
9 #include <bx/timer.h>
10 #include <bx/string.h>
11 #include <bx/math.h>
12 
13 #include "font/font_manager.h"
14 #include "font/text_buffer_manager.h"
15 #include "entry/input.h"
16 
17 #include <iconfontheaders/icons_font_awesome.h>
18 #include <iconfontheaders/icons_kenney.h>
19 
20 #include <wchar.h>
21 
22 #include "imgui/imgui.h"
23 
24 namespace
25 {
26 
loadTtf(FontManager * _fm,const char * _filePath)27 TrueTypeHandle loadTtf(FontManager* _fm, const char* _filePath)
28 {
29 	uint32_t size;
30 	void* data = load(_filePath, &size);
31 
32 	if (NULL != data)
33 	{
34 		TrueTypeHandle handle = _fm->createTtf( (uint8_t*)data, size);
35 		BX_FREE(entry::getAllocator(), data);
36 		return handle;
37 	}
38 
39 	TrueTypeHandle invalid = BGFX_INVALID_HANDLE;
40 	return invalid;
41 }
42 
43 static const char* s_fontFilePath[] =
44 {
45 	"font/droidsans.ttf",
46 	"font/chp-fire.ttf",
47 	"font/bleeding_cowboys.ttf",
48 	"font/mias_scribblings.ttf",
49 	"font/ruritania.ttf",
50 	"font/signika-regular.ttf",
51 	"font/five_minutes.otf",
52 };
53 
54 class ExampleFont : public entry::AppI
55 {
56 public:
ExampleFont(const char * _name,const char * _description,const char * _url)57 	ExampleFont(const char* _name, const char* _description, const char* _url)
58 		: entry::AppI(_name, _description, _url)
59 	{
60 	}
61 
init(int32_t _argc,const char * const * _argv,uint32_t _width,uint32_t _height)62 	void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
63 	{
64 		Args args(_argc, _argv);
65 
66 		m_width  = _width;
67 		m_height = _height;
68 		m_debug  = BGFX_DEBUG_NONE;
69 		m_reset  = BGFX_RESET_VSYNC;
70 
71 		bgfx::Init init;
72 		init.type     = args.m_type;
73 		init.vendorId = args.m_pciId;
74 		init.resolution.width  = m_width;
75 		init.resolution.height = m_height;
76 		init.resolution.reset  = m_reset;
77 		bgfx::init(init);
78 
79 		// Enable debug text.
80 		bgfx::setDebug(m_debug);
81 
82 		// Set view 0 clear state.
83 		bgfx::setViewClear(0
84 						   , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
85 						   , 0x303030ff
86 						   , 1.0f
87 						   , 0
88 						   );
89 
90 		// Init the text rendering system.
91 		m_fontManager = new FontManager(512);
92 		m_textBufferManager = new TextBufferManager(m_fontManager);
93 
94 		// Load some TTF files.
95 		for (uint32_t ii = 0; ii < numFonts; ++ii)
96 		{
97 			// Instantiate a usable font.
98 			m_fontFiles[ii] = loadTtf(m_fontManager, s_fontFilePath[ii]);
99 			m_fonts[ii] = m_fontManager->createFontByPixelSize(m_fontFiles[ii], 0, 32);
100 
101 			// Preload glyphs and blit them to atlas.
102 			m_fontManager->preloadGlyph(m_fonts[ii], L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ. \n");
103 
104 			// You can unload the truetype files at this stage, but in that
105 			// case, the set of glyph's will be limited to the set of preloaded
106 			// glyph.
107 			m_fontManager->destroyTtf(m_fontFiles[ii]);
108 		}
109 
110 		m_fontAwesomeTtf = loadTtf(m_fontManager, "font/fontawesome-webfont.ttf");
111 		m_fontKenneyTtf  = loadTtf(m_fontManager, "font/kenney-icon-font.ttf");
112 
113 		// This font doesn't have any preloaded glyph's but the truetype file
114 		// is loaded so glyph will be generated as needed.
115 		m_fontAwesome72 = m_fontManager->createFontByPixelSize(m_fontAwesomeTtf, 0, 72);
116 		m_fontKenney64  = m_fontManager->createFontByPixelSize(m_fontKenneyTtf,  0, 64);
117 
118 		m_visitorTtf = loadTtf(m_fontManager, "font/visitor1.ttf");
119 
120 		// This font doesn't have any preloaded glyph's but the truetype file
121 		// is loaded so glyph will be generated as needed.
122 		m_visitor10 = m_fontManager->createFontByPixelSize(m_visitorTtf, 0, 10);
123 
124 		//create a static text buffer compatible with alpha font
125 		//a static text buffer content cannot be modified after its first submit.
126 		m_staticText = m_textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, BufferType::Static);
127 
128 		// The pen position represent the top left of the box of the first line
129 		// of text.
130 		m_textBufferManager->setPenPosition(m_staticText, 24.0f, 100.0f);
131 
132 		for (uint32_t ii = 0; ii < numFonts; ++ii)
133 		{
134 			// Add some text to the buffer.
135 			// The position of the pen is adjusted when there is an endline.
136 			m_textBufferManager->appendText(m_staticText, m_fonts[ii], L"The quick brown fox jumps over the lazy dog\n");
137 		}
138 
139 		// Now write some styled text.
140 
141 		// Setup style colors.
142 		m_textBufferManager->setBackgroundColor(m_staticText, 0x551111ff);
143 		m_textBufferManager->setUnderlineColor(m_staticText, 0xff2222ff);
144 		m_textBufferManager->setOverlineColor(m_staticText, 0x2222ffff);
145 		m_textBufferManager->setStrikeThroughColor(m_staticText, 0x22ff22ff);
146 
147 		// Background.
148 		m_textBufferManager->setStyle(m_staticText, STYLE_BACKGROUND);
149 		m_textBufferManager->appendText(m_staticText, m_fonts[0], L"The quick ");
150 
151 		// Strike-through.
152 		m_textBufferManager->setStyle(m_staticText, STYLE_STRIKE_THROUGH);
153 		m_textBufferManager->appendText(m_staticText, m_fonts[0], L"brown fox ");
154 
155 		// Overline.
156 		m_textBufferManager->setStyle(m_staticText, STYLE_OVERLINE);
157 		m_textBufferManager->appendText(m_staticText, m_fonts[0], L"jumps over ");
158 
159 		// Underline.
160 		m_textBufferManager->setStyle(m_staticText, STYLE_UNDERLINE);
161 		m_textBufferManager->appendText(m_staticText, m_fonts[0], L"the lazy ");
162 
163 		// Background + strike-through.
164 		m_textBufferManager->setStyle(m_staticText, STYLE_BACKGROUND | STYLE_STRIKE_THROUGH);
165 		m_textBufferManager->appendText(m_staticText, m_fonts[0], L"dog\n");
166 
167 		m_textBufferManager->setStyle(m_staticText, STYLE_NORMAL);
168 		m_textBufferManager->appendText(m_staticText, m_fontAwesome72,
169 			" " ICON_FA_POWER_OFF
170 			" " ICON_FA_TWITTER_SQUARE
171 			" " ICON_FA_CERTIFICATE
172 			" " ICON_FA_FLOPPY_O
173 			" " ICON_FA_GITHUB
174 			" " ICON_FA_GITHUB_ALT
175 			"\n"
176 			);
177 		m_textBufferManager->appendText(m_staticText, m_fontKenney64,
178 			" " ICON_KI_COMPUTER
179 			" " ICON_KI_JOYSTICK
180 			" " ICON_KI_EXLAMATION
181 			" " ICON_KI_STAR
182 			" " ICON_KI_BUTTON_START
183 			" " ICON_KI_DOWNLOAD
184 			"\n"
185 			);
186 
187 		// Create a transient buffer for real-time data.
188 		m_transientText = m_textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, BufferType::Transient);
189 
190 		imguiCreate();
191 	}
192 
shutdown()193 	virtual int shutdown() override
194 	{
195 		imguiDestroy();
196 
197 		m_fontManager->destroyTtf(m_fontKenneyTtf);
198 		m_fontManager->destroyTtf(m_fontAwesomeTtf);
199 		m_fontManager->destroyTtf(m_visitorTtf);
200 
201 		// Destroy the fonts.
202 		m_fontManager->destroyFont(m_fontKenney64);
203 		m_fontManager->destroyFont(m_fontAwesome72);
204 		m_fontManager->destroyFont(m_visitor10);
205 		for (uint32_t ii = 0; ii < numFonts; ++ii)
206 		{
207 			m_fontManager->destroyFont(m_fonts[ii]);
208 		}
209 
210 		m_textBufferManager->destroyTextBuffer(m_staticText);
211 		m_textBufferManager->destroyTextBuffer(m_transientText);
212 
213 		delete m_textBufferManager;
214 		delete m_fontManager;
215 
216 		// Shutdown bgfx.
217 		bgfx::shutdown();
218 
219 		return 0;
220 	}
221 
update()222 	bool update() override
223 	{
224 		if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
225 		{
226 			imguiBeginFrame(m_mouseState.m_mx
227 				,  m_mouseState.m_my
228 				, (m_mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT   : 0)
229 				| (m_mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT  : 0)
230 				| (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
231 				,  m_mouseState.m_mz
232 				, uint16_t(m_width)
233 				, uint16_t(m_height)
234 				);
235 
236 			showExampleDialog(this);
237 
238 			imguiEndFrame();
239 
240 			// This dummy draw call is here to make sure that view 0 is cleared
241 			// if no other draw calls are submitted to view 0.
242 			bgfx::touch(0);
243 
244 			int64_t now = bx::getHPCounter();
245 			static int64_t last = now;
246 			const int64_t frameTime = now - last;
247 			last = now;
248 			const double freq = double(bx::getHPFrequency() );
249 			const double toMs = 1000.0 / freq;
250 
251 			// Use transient text to display debug information.
252 			char fpsText[64];
253 			bx::snprintf(fpsText, BX_COUNTOF(fpsText), "Frame: % 7.3f[ms]", double(frameTime) * toMs);
254 
255 			m_textBufferManager->clearTextBuffer(m_transientText);
256 			m_textBufferManager->setPenPosition(m_transientText, m_width - 150.0f, 10.0f);
257 			m_textBufferManager->appendText(m_transientText, m_visitor10, "Transient\n");
258 			m_textBufferManager->appendText(m_transientText, m_visitor10, "text buffer\n");
259 			m_textBufferManager->appendText(m_transientText, m_visitor10, fpsText);
260 
261 			const bx::Vec3 at  = { 0.0f, 0.0f,  0.0f };
262 			const bx::Vec3 eye = { 0.0f, 0.0f, -1.0f };
263 
264 			float view[16];
265 			bx::mtxLookAt(view, eye, at);
266 
267 			const float centering = 0.5f;
268 
269 			// Setup a top-left ortho matrix for screen space drawing.
270 			const bgfx::Caps* caps = bgfx::getCaps();
271 			{
272 				float ortho[16];
273 				bx::mtxOrtho(
274 					  ortho
275 					, centering
276 					, m_width  + centering
277 					, m_height + centering
278 					, centering
279 					, 0.0f
280 					, 100.0f
281 					, 0.0f
282 					, caps->homogeneousDepth
283 					);
284 				bgfx::setViewTransform(0, view, ortho);
285 				bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) );
286 			}
287 
288 			// Submit the debug text.
289 			m_textBufferManager->submitTextBuffer(m_transientText, 0);
290 
291 			// Submit the static text.
292 			m_textBufferManager->submitTextBuffer(m_staticText, 0);
293 
294 			// Advance to next frame. Rendering thread will be kicked to
295 			// process submitted rendering primitives.
296 			bgfx::frame();
297 
298 			return true;
299 		}
300 
301 		return false;
302 	}
303 
304 	entry::MouseState m_mouseState;
305 
306 	uint32_t m_width;
307 	uint32_t m_height;
308 	uint32_t m_debug;
309 	uint32_t m_reset;
310 
311 	FontManager* m_fontManager;
312 	TextBufferManager* m_textBufferManager;
313 
314 	FontHandle m_visitor10;
315 	TrueTypeHandle m_fontAwesomeTtf;
316 	TrueTypeHandle m_fontKenneyTtf;
317 	FontHandle m_fontAwesome72;
318 	FontHandle m_fontKenney64;
319 	TrueTypeHandle m_visitorTtf;
320 
321 	TextBufferHandle m_transientText;
322 	TextBufferHandle m_staticText;
323 
324 	static const uint32_t numFonts = BX_COUNTOF(s_fontFilePath);
325 
326 	TrueTypeHandle m_fontFiles[numFonts];
327 	FontHandle m_fonts[numFonts];
328 };
329 
330 } // namespace
331 
332 ENTRY_IMPLEMENT_MAIN(
333 	  ExampleFont
334 	, "10-font"
335 	, "Use the font system to display text and styled text."
336 	, "https://bkaradzic.github.io/bgfx/examples.html#font"
337 	);
338