1 /*
2  * Copyright 2011-2019 Branimir Karadzic. 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 #include "imgui/imgui.h"
9 
10 namespace
11 {
12 
13 struct PosColorVertex
14 {
15 	float m_x;
16 	float m_y;
17 	float m_z;
18 	uint32_t m_abgr;
19 
init__anon19554fc80111::PosColorVertex20 	static void init()
21 	{
22 		ms_layout
23 			.begin()
24 			.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
25 			.add(bgfx::Attrib::Color0,   4, bgfx::AttribType::Uint8, true)
26 			.end();
27 	};
28 
29 	static bgfx::VertexLayout ms_layout;
30 };
31 
32 bgfx::VertexLayout PosColorVertex::ms_layout;
33 
34 static PosColorVertex s_cubeVertices[] =
35 {
36 	{-1.0f,  1.0f,  1.0f, 0xff000000 },
37 	{ 1.0f,  1.0f,  1.0f, 0xff0000ff },
38 	{-1.0f, -1.0f,  1.0f, 0xff00ff00 },
39 	{ 1.0f, -1.0f,  1.0f, 0xff00ffff },
40 	{-1.0f,  1.0f, -1.0f, 0xffff0000 },
41 	{ 1.0f,  1.0f, -1.0f, 0xffff00ff },
42 	{-1.0f, -1.0f, -1.0f, 0xffffff00 },
43 	{ 1.0f, -1.0f, -1.0f, 0xffffffff },
44 };
45 
46 static const uint16_t s_cubeTriList[] =
47 {
48 	0, 1, 2, // 0
49 	1, 3, 2,
50 	4, 6, 5, // 2
51 	5, 6, 7,
52 	0, 2, 4, // 4
53 	4, 2, 6,
54 	1, 5, 3, // 6
55 	5, 7, 3,
56 	0, 4, 1, // 8
57 	4, 5, 1,
58 	2, 3, 6, // 10
59 	6, 3, 7,
60 };
61 
62 static const uint16_t s_cubeTriStrip[] =
63 {
64 	0, 1, 2,
65 	3,
66 	7,
67 	1,
68 	5,
69 	0,
70 	4,
71 	2,
72 	6,
73 	7,
74 	4,
75 	5,
76 };
77 
78 static const uint16_t s_cubeLineList[] =
79 {
80 	0, 1,
81 	0, 2,
82 	0, 4,
83 	1, 3,
84 	1, 5,
85 	2, 3,
86 	2, 6,
87 	3, 7,
88 	4, 5,
89 	4, 6,
90 	5, 7,
91 	6, 7,
92 };
93 
94 static const uint16_t s_cubeLineStrip[] =
95 {
96 	0, 2, 3, 1, 5, 7, 6, 4,
97 	0, 2, 6, 4, 5, 7, 3, 1,
98 	0,
99 };
100 
101 static const uint16_t s_cubePoints[] =
102 {
103 	0, 1, 2, 3, 4, 5, 6, 7
104 };
105 
106 static const char* s_ptNames[]
107 {
108 	"Triangle List",
109 	"Triangle Strip",
110 	"Lines",
111 	"Line Strip",
112 	"Points",
113 };
114 
115 static const uint64_t s_ptState[]
116 {
117 	UINT64_C(0),
118 	BGFX_STATE_PT_TRISTRIP,
119 	BGFX_STATE_PT_LINES,
120 	BGFX_STATE_PT_LINESTRIP,
121 	BGFX_STATE_PT_POINTS,
122 };
123 BX_STATIC_ASSERT(BX_COUNTOF(s_ptState) == BX_COUNTOF(s_ptNames) );
124 
125 class ExampleCubes : public entry::AppI
126 {
127 public:
ExampleCubes(const char * _name,const char * _description,const char * _url)128 	ExampleCubes(const char* _name, const char* _description, const char* _url)
129 		: entry::AppI(_name, _description, _url)
130 		, m_pt(0)
131 		, m_r(true)
132 		, m_g(true)
133 		, m_b(true)
134 		, m_a(true)
135 	{
136 	}
137 
init(int32_t _argc,const char * const * _argv,uint32_t _width,uint32_t _height)138 	void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
139 	{
140 		Args args(_argc, _argv);
141 
142 		m_width  = _width;
143 		m_height = _height;
144 		m_debug  = BGFX_DEBUG_NONE;
145 		m_reset  = BGFX_RESET_VSYNC;
146 
147 		bgfx::Init init;
148 		init.type     = args.m_type;
149 		init.vendorId = args.m_pciId;
150 		init.resolution.width  = m_width;
151 		init.resolution.height = m_height;
152 		init.resolution.reset  = m_reset;
153 		bgfx::init(init);
154 
155 		// Enable debug text.
156 		bgfx::setDebug(m_debug);
157 
158 		// Set view 0 clear state.
159 		bgfx::setViewClear(0
160 			, BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
161 			, 0x303030ff
162 			, 1.0f
163 			, 0
164 			);
165 
166 		// Create vertex stream declaration.
167 		PosColorVertex::init();
168 
169 		// Create static vertex buffer.
170 		m_vbh = bgfx::createVertexBuffer(
171 			// Static data can be passed with bgfx::makeRef
172 			  bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) )
173 			, PosColorVertex::ms_layout
174 			);
175 
176 		// Create static index buffer for triangle list rendering.
177 		m_ibh[0] = bgfx::createIndexBuffer(
178 			// Static data can be passed with bgfx::makeRef
179 			bgfx::makeRef(s_cubeTriList, sizeof(s_cubeTriList) )
180 			);
181 
182 		// Create static index buffer for triangle strip rendering.
183 		m_ibh[1] = bgfx::createIndexBuffer(
184 			// Static data can be passed with bgfx::makeRef
185 			bgfx::makeRef(s_cubeTriStrip, sizeof(s_cubeTriStrip) )
186 			);
187 
188 		// Create static index buffer for line list rendering.
189 		m_ibh[2] = bgfx::createIndexBuffer(
190 			// Static data can be passed with bgfx::makeRef
191 			bgfx::makeRef(s_cubeLineList, sizeof(s_cubeLineList) )
192 			);
193 
194 		// Create static index buffer for line strip rendering.
195 		m_ibh[3] = bgfx::createIndexBuffer(
196 			// Static data can be passed with bgfx::makeRef
197 			bgfx::makeRef(s_cubeLineStrip, sizeof(s_cubeLineStrip) )
198 			);
199 
200 		// Create static index buffer for point list rendering.
201 		m_ibh[4] = bgfx::createIndexBuffer(
202 			// Static data can be passed with bgfx::makeRef
203 			bgfx::makeRef(s_cubePoints, sizeof(s_cubePoints) )
204 			);
205 
206 		// Create program from shaders.
207 		m_program = loadProgram("vs_cubes", "fs_cubes");
208 
209 		m_timeOffset = bx::getHPCounter();
210 
211 		imguiCreate();
212 	}
213 
shutdown()214 	virtual int shutdown() override
215 	{
216 		imguiDestroy();
217 
218 		// Cleanup.
219 		for (uint32_t ii = 0; ii < BX_COUNTOF(m_ibh); ++ii)
220 		{
221 			bgfx::destroy(m_ibh[ii]);
222 		}
223 
224 		bgfx::destroy(m_vbh);
225 		bgfx::destroy(m_program);
226 
227 		// Shutdown bgfx.
228 		bgfx::shutdown();
229 
230 		return 0;
231 	}
232 
update()233 	bool update() override
234 	{
235 		if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
236 		{
237 			imguiBeginFrame(m_mouseState.m_mx
238 				,  m_mouseState.m_my
239 				, (m_mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT   : 0)
240 				| (m_mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT  : 0)
241 				| (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
242 				,  m_mouseState.m_mz
243 				, uint16_t(m_width)
244 				, uint16_t(m_height)
245 				);
246 
247 			showExampleDialog(this);
248 
249 			ImGui::SetNextWindowPos(
250 				  ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f)
251 				, ImGuiCond_FirstUseEver
252 				);
253 			ImGui::SetNextWindowSize(
254 				  ImVec2(m_width / 5.0f, m_height / 3.5f)
255 				, ImGuiCond_FirstUseEver
256 				);
257 			ImGui::Begin("Settings"
258 				, NULL
259 				, 0
260 				);
261 
262 			ImGui::Checkbox("Write R", &m_r);
263 			ImGui::Checkbox("Write G", &m_g);
264 			ImGui::Checkbox("Write B", &m_b);
265 			ImGui::Checkbox("Write A", &m_a);
266 
267 			ImGui::Text("Primitive topology:");
268 			ImGui::Combo("", (int*)&m_pt, s_ptNames, BX_COUNTOF(s_ptNames) );
269 
270 			ImGui::End();
271 
272 			imguiEndFrame();
273 
274 			float time = (float)( (bx::getHPCounter()-m_timeOffset)/double(bx::getHPFrequency() ) );
275 
276 			const bx::Vec3 at  = { 0.0f, 0.0f,   0.0f };
277 			const bx::Vec3 eye = { 0.0f, 0.0f, -35.0f };
278 
279 			// Set view and projection matrix for view 0.
280 			{
281 				float view[16];
282 				bx::mtxLookAt(view, eye, at);
283 
284 				float proj[16];
285 				bx::mtxProj(proj, 60.0f, float(m_width)/float(m_height), 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth);
286 				bgfx::setViewTransform(0, view, proj);
287 
288 				// Set view 0 default viewport.
289 				bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) );
290 			}
291 
292 			// This dummy draw call is here to make sure that view 0 is cleared
293 			// if no other draw calls are submitted to view 0.
294 			bgfx::touch(0);
295 
296 			bgfx::IndexBufferHandle ibh = m_ibh[m_pt];
297 			uint64_t state = 0
298 				| (m_r ? BGFX_STATE_WRITE_R : 0)
299 				| (m_g ? BGFX_STATE_WRITE_G : 0)
300 				| (m_b ? BGFX_STATE_WRITE_B : 0)
301 				| (m_a ? BGFX_STATE_WRITE_A : 0)
302 				| BGFX_STATE_WRITE_Z
303 				| BGFX_STATE_DEPTH_TEST_LESS
304 				| BGFX_STATE_CULL_CW
305 				| BGFX_STATE_MSAA
306 				| s_ptState[m_pt]
307 				;
308 
309 			// Submit 11x11 cubes.
310 			for (uint32_t yy = 0; yy < 11; ++yy)
311 			{
312 				for (uint32_t xx = 0; xx < 11; ++xx)
313 				{
314 					float mtx[16];
315 					bx::mtxRotateXY(mtx, time + xx*0.21f, time + yy*0.37f);
316 					mtx[12] = -15.0f + float(xx)*3.0f;
317 					mtx[13] = -15.0f + float(yy)*3.0f;
318 					mtx[14] = 0.0f;
319 
320 					// Set model matrix for rendering.
321 					bgfx::setTransform(mtx);
322 
323 					// Set vertex and index buffer.
324 					bgfx::setVertexBuffer(0, m_vbh);
325 					bgfx::setIndexBuffer(ibh);
326 
327 					// Set render states.
328 					bgfx::setState(state);
329 
330 					// Submit primitive for rendering to view 0.
331 					bgfx::submit(0, m_program);
332 				}
333 			}
334 
335 			// Advance to next frame. Rendering thread will be kicked to
336 			// process submitted rendering primitives.
337 			bgfx::frame();
338 
339 			return true;
340 		}
341 
342 		return false;
343 	}
344 
345 	entry::MouseState m_mouseState;
346 
347 	uint32_t m_width;
348 	uint32_t m_height;
349 	uint32_t m_debug;
350 	uint32_t m_reset;
351 	bgfx::VertexBufferHandle m_vbh;
352 	bgfx::IndexBufferHandle m_ibh[BX_COUNTOF(s_ptState)];
353 	bgfx::ProgramHandle m_program;
354 	int64_t m_timeOffset;
355 	int32_t m_pt;
356 
357 	bool m_r;
358 	bool m_g;
359 	bool m_b;
360 	bool m_a;
361 };
362 
363 } // namespace
364 
365 ENTRY_IMPLEMENT_MAIN(
366 	  ExampleCubes
367 	, "01-cubes"
368 	, "Rendering simple static mesh."
369 	, "https://bkaradzic.github.io/bgfx/examples.html#cubes"
370 	);
371