wireframe.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. /*
  2. * Copyright 2016 Dario Manesku. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
  4. */
  5. #include "common.h"
  6. #include "bgfx_utils.h"
  7. #include "imgui/imgui.h"
  8. namespace
  9. {
  10. struct DrawMode
  11. {
  12. enum
  13. {
  14. WireframeShaded,
  15. Wireframe,
  16. Shaded,
  17. };
  18. };
  19. struct Camera
  20. {
  21. Camera()
  22. {
  23. reset();
  24. }
  25. void reset()
  26. {
  27. m_target.curr = bx::InitZero;
  28. m_target.dest = bx::InitZero;
  29. m_pos.curr = { 0.0f, 0.0f, -2.0f };
  30. m_pos.dest = { 0.0f, 0.0f, -2.0f };
  31. m_orbit[0] = 0.0f;
  32. m_orbit[1] = 0.0f;
  33. }
  34. void mtxLookAt(float* _outViewMtx)
  35. {
  36. bx::mtxLookAt(_outViewMtx, m_pos.curr, m_target.curr);
  37. }
  38. void orbit(float _dx, float _dy)
  39. {
  40. m_orbit[0] += _dx;
  41. m_orbit[1] += _dy;
  42. }
  43. void dolly(float _dz)
  44. {
  45. const float cnear = 1.0f;
  46. const float cfar = 100.0f;
  47. const bx::Vec3 toTarget = bx::sub(m_target.dest, m_pos.dest);
  48. const float toTargetLen = bx::length(toTarget);
  49. const float invToTargetLen = 1.0f / (toTargetLen + bx::kFloatSmallest);
  50. const bx::Vec3 toTargetNorm = bx::mul(toTarget, invToTargetLen);
  51. float delta = toTargetLen * _dz;
  52. float newLen = toTargetLen + delta;
  53. if ( (cnear < newLen || _dz < 0.0f)
  54. && (newLen < cfar || _dz > 0.0f) )
  55. {
  56. m_pos.dest = bx::mad(toTargetNorm, delta, m_pos.dest);
  57. }
  58. }
  59. void consumeOrbit(float _amount)
  60. {
  61. float consume[2];
  62. consume[0] = m_orbit[0] * _amount;
  63. consume[1] = m_orbit[1] * _amount;
  64. m_orbit[0] -= consume[0];
  65. m_orbit[1] -= consume[1];
  66. const bx::Vec3 toPos = bx::sub(m_pos.curr, m_target.curr);
  67. const float toPosLen = bx::length(toPos);
  68. const float invToPosLen = 1.0f / (toPosLen + bx::kFloatSmallest);
  69. const bx::Vec3 toPosNorm = bx::mul(toPos, invToPosLen);
  70. float ll[2];
  71. bx::toLatLong(&ll[0], &ll[1], toPosNorm);
  72. ll[0] += consume[0];
  73. ll[1] -= consume[1];
  74. ll[1] = bx::clamp(ll[1], 0.02f, 0.98f);
  75. const bx::Vec3 tmp = bx::fromLatLong(ll[0], ll[1]);
  76. const bx::Vec3 diff = bx::mul(bx::sub(tmp, toPosNorm), toPosLen);
  77. m_pos.curr = bx::add(m_pos.curr, diff);
  78. m_pos.dest = bx::add(m_pos.dest, diff);
  79. }
  80. void update(float _dt)
  81. {
  82. const float amount = bx::min(_dt / 0.12f, 1.0f);
  83. consumeOrbit(amount);
  84. m_target.curr = bx::lerp(m_target.curr, m_target.dest, amount);
  85. m_pos.curr = bx::lerp(m_pos.curr, m_pos.dest, amount);
  86. }
  87. void envViewMtx(float* _mtx)
  88. {
  89. const bx::Vec3 toTarget = bx::sub(m_target.curr, m_pos.curr);
  90. const float toTargetLen = bx::length(toTarget);
  91. const float invToTargetLen = 1.0f / (toTargetLen + bx::kFloatSmallest);
  92. const bx::Vec3 toTargetNorm = bx::mul(toTarget, invToTargetLen);
  93. const bx::Vec3 right = bx::normalize(bx::cross({ 0.0f, 1.0f, 0.0f }, toTargetNorm) );
  94. const bx::Vec3 up = bx::normalize(bx::cross(toTargetNorm, right) );
  95. _mtx[ 0] = right.x;
  96. _mtx[ 1] = right.y;
  97. _mtx[ 2] = right.z;
  98. _mtx[ 3] = 0.0f;
  99. _mtx[ 4] = up.x;
  100. _mtx[ 5] = up.y;
  101. _mtx[ 6] = up.z;
  102. _mtx[ 7] = 0.0f;
  103. _mtx[ 8] = toTargetNorm.x;
  104. _mtx[ 9] = toTargetNorm.y;
  105. _mtx[10] = toTargetNorm.z;
  106. _mtx[11] = 0.0f;
  107. _mtx[12] = 0.0f;
  108. _mtx[13] = 0.0f;
  109. _mtx[14] = 0.0f;
  110. _mtx[15] = 1.0f;
  111. }
  112. struct Interp3f
  113. {
  114. bx::Vec3 curr = bx::InitNone;
  115. bx::Vec3 dest = bx::InitNone;
  116. };
  117. Interp3f m_target;
  118. Interp3f m_pos;
  119. float m_orbit[2];
  120. };
  121. struct Mouse
  122. {
  123. Mouse()
  124. {
  125. m_dx = 0.0f;
  126. m_dy = 0.0f;
  127. m_prevMx = 0.0f;
  128. m_prevMx = 0.0f;
  129. m_scroll = 0;
  130. m_scrollPrev = 0;
  131. }
  132. void update(float _mx, float _my, int32_t _mz, uint32_t _width, uint32_t _height)
  133. {
  134. const float widthf = float(int32_t(_width));
  135. const float heightf = float(int32_t(_height));
  136. // Delta movement.
  137. m_dx = float(_mx - m_prevMx)/widthf;
  138. m_dy = float(_my - m_prevMy)/heightf;
  139. m_prevMx = _mx;
  140. m_prevMy = _my;
  141. // Scroll.
  142. m_scroll = _mz - m_scrollPrev;
  143. m_scrollPrev = _mz;
  144. }
  145. float m_dx; // Screen space.
  146. float m_dy;
  147. float m_prevMx;
  148. float m_prevMy;
  149. int32_t m_scroll;
  150. int32_t m_scrollPrev;
  151. };
  152. struct MeshMtx
  153. {
  154. MeshMtx()
  155. {
  156. m_mesh = NULL;
  157. }
  158. void init(const char* _path
  159. , float _scale = 1.0f
  160. , float _rotX = 0.0f
  161. , float _rotY = 0.0f
  162. , float _rotZ = 0.0f
  163. , float _transX = 0.0f
  164. , float _transY = 0.0f
  165. , float _transZ = 0.0f
  166. )
  167. {
  168. m_mesh = meshLoad(_path);
  169. bx::mtxSRT(m_mtx
  170. , _scale
  171. , _scale
  172. , _scale
  173. , _rotX
  174. , _rotY
  175. , _rotZ
  176. , _transX
  177. , _transY
  178. , _transZ
  179. );
  180. }
  181. void destroy()
  182. {
  183. if (NULL != m_mesh)
  184. {
  185. meshUnload(m_mesh);
  186. }
  187. }
  188. Mesh* m_mesh;
  189. float m_mtx[16];
  190. };
  191. struct Uniforms
  192. {
  193. enum { NumVec4 = 3 };
  194. void init()
  195. {
  196. m_camPos[0] = 0.0f;
  197. m_camPos[1] = 1.0f;
  198. m_camPos[2] = -2.5f;
  199. m_wfColor[0] = 1.0f;
  200. m_wfColor[1] = 0.0f;
  201. m_wfColor[2] = 0.0f;
  202. m_wfColor[3] = 1.0f;
  203. m_drawEdges = 0.0f;
  204. m_wfThickness = 1.5f;
  205. u_params = bgfx::createUniform("u_params", bgfx::UniformType::Vec4, NumVec4);
  206. }
  207. void submit()
  208. {
  209. bgfx::setUniform(u_params, m_params, NumVec4);
  210. }
  211. void destroy()
  212. {
  213. bgfx::destroy(u_params);
  214. }
  215. union
  216. {
  217. struct
  218. {
  219. /*0*/struct { float m_camPos[3], m_unused0; };
  220. /*1*/struct { float m_wfColor[4]; };
  221. /*2*/struct { float m_drawEdges, m_wfThickness, m_unused2[2]; };
  222. };
  223. float m_params[NumVec4*4];
  224. };
  225. bgfx::UniformHandle u_params;
  226. };
  227. class ExampleWireframe : public entry::AppI
  228. {
  229. public:
  230. ExampleWireframe(const char* _name, const char* _description, const char* _url)
  231. : entry::AppI(_name, _description, _url)
  232. {
  233. }
  234. void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
  235. {
  236. Args args(_argc, _argv);
  237. m_width = _width;
  238. m_height = _height;
  239. m_debug = BGFX_DEBUG_NONE;
  240. m_reset = 0
  241. | BGFX_RESET_VSYNC
  242. | BGFX_RESET_MSAA_X16
  243. ;
  244. bgfx::Init init;
  245. init.type = args.m_type;
  246. init.vendorId = args.m_pciId;
  247. init.platformData.nwh = entry::getNativeWindowHandle(entry::kDefaultWindowHandle);
  248. init.platformData.ndt = entry::getNativeDisplayHandle();
  249. init.platformData.type = entry::getNativeWindowHandleType(entry::kDefaultWindowHandle);
  250. init.resolution.width = m_width;
  251. init.resolution.height = m_height;
  252. init.resolution.reset = m_reset;
  253. bgfx::init(init);
  254. // Enable m_debug text.
  255. bgfx::setDebug(m_debug);
  256. // Set view 0 clear state.
  257. bgfx::setViewClear(0
  258. , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
  259. , 0x303030ff
  260. , 1.0f
  261. , 0
  262. );
  263. m_wfProgram = loadProgram("vs_wf_wireframe", "fs_wf_wireframe");
  264. m_meshProgram = loadProgram("vs_wf_mesh", "fs_wf_mesh");
  265. m_uniforms.init();
  266. m_meshes[0].init("meshes/bunny.bin", 1.0f, 0.0f, bx::kPi, 0.0f, 0.0f, -0.8f, 0.0f);
  267. m_meshes[1].init("meshes/hollowcube.bin", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
  268. m_meshes[2].init("meshes/orb.bin", 1.2f, 0.0f, 0.0f, 0.0f, 0.0f, -0.65f, 0.0f);
  269. // Imgui.
  270. imguiCreate();
  271. m_oldWidth = 0;
  272. m_oldHeight = 0;
  273. m_oldReset = m_reset;
  274. m_meshSelection = 1;
  275. m_drawMode = DrawMode::WireframeShaded;
  276. }
  277. virtual int shutdown() override
  278. {
  279. // Cleanup.
  280. imguiDestroy();
  281. m_meshes[0].destroy();
  282. m_meshes[1].destroy();
  283. m_meshes[2].destroy();
  284. bgfx::destroy(m_wfProgram);
  285. bgfx::destroy(m_meshProgram);
  286. m_uniforms.destroy();
  287. // Shutdown bgfx.
  288. bgfx::shutdown();
  289. return 0;
  290. }
  291. bool update() override
  292. {
  293. if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
  294. {
  295. if (m_oldWidth != m_width
  296. || m_oldHeight != m_height
  297. || m_oldReset != m_reset)
  298. {
  299. // Recreate variable size render targets when resolution changes.
  300. m_oldWidth = m_width;
  301. m_oldHeight = m_height;
  302. m_oldReset = m_reset;
  303. }
  304. imguiBeginFrame(m_mouseState.m_mx
  305. , m_mouseState.m_my
  306. , (m_mouseState.m_buttons[entry::MouseButton::Left ] ? IMGUI_MBUT_LEFT : 0)
  307. | (m_mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0)
  308. | (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
  309. , m_mouseState.m_mz
  310. , uint16_t(m_width)
  311. , uint16_t(m_height)
  312. );
  313. showExampleDialog(this);
  314. ImGui::SetNextWindowPos(
  315. ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f)
  316. , ImGuiCond_FirstUseEver
  317. );
  318. ImGui::SetNextWindowSize(
  319. ImVec2(m_width / 5.0f, m_height * 0.75f)
  320. , ImGuiCond_FirstUseEver
  321. );
  322. ImGui::Begin("Settings"
  323. , NULL
  324. , 0
  325. );
  326. ImGui::Separator();
  327. ImGui::Text("Draw mode:");
  328. ImGui::RadioButton("Wireframe + Shaded", &m_drawMode, 0);
  329. ImGui::RadioButton("Wireframe", &m_drawMode, 1);
  330. ImGui::RadioButton("Shaded", &m_drawMode, 2);
  331. const bool wfEnabled = (DrawMode::Shaded != m_drawMode);
  332. if ( wfEnabled )
  333. {
  334. ImGui::Separator();
  335. ImGui::ColorWheel("Color", m_uniforms.m_wfColor, 0.6f);
  336. ImGui::SliderFloat("Thickness", &m_uniforms.m_wfThickness, 0.6f, 2.2f);
  337. }
  338. ImGui::Separator();
  339. ImGui::Text("Mesh:");
  340. {
  341. bool meshChanged = false;
  342. meshChanged |= ImGui::RadioButton("Bunny", &m_meshSelection, 0);
  343. meshChanged |= ImGui::RadioButton("Hollowcubes", &m_meshSelection, 1);
  344. meshChanged |= ImGui::RadioButton("Orb", &m_meshSelection, 2);
  345. if (meshChanged)
  346. {
  347. m_camera.reset();
  348. }
  349. }
  350. ImGui::End();
  351. imguiEndFrame();
  352. // This dummy draw call is here to make sure that view 0 is cleared
  353. // if no other draw calls are submitted to view 0.
  354. bgfx::touch(0);
  355. int64_t now = bx::getHPCounter();
  356. static int64_t last = now;
  357. const int64_t frameTime = now - last;
  358. last = now;
  359. const double freq = double(bx::getHPFrequency() );
  360. const float deltaTimeSec = float(double(frameTime)/freq);
  361. // Setup view.
  362. bgfx::setViewRect(0, 0, 0, bgfx::BackbufferRatio::Equal);
  363. bgfx::setViewClear(0, BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH, 0x303030ff, 1.0f, 0);
  364. const bool mouseOverGui = ImGui::MouseOverArea();
  365. m_mouse.update(float(m_mouseState.m_mx), float(m_mouseState.m_my), m_mouseState.m_mz, m_width, m_height);
  366. if (!mouseOverGui)
  367. {
  368. if (m_mouseState.m_buttons[entry::MouseButton::Left])
  369. {
  370. m_camera.orbit(m_mouse.m_dx, m_mouse.m_dy);
  371. }
  372. else if (m_mouseState.m_buttons[entry::MouseButton::Right])
  373. {
  374. m_camera.dolly(m_mouse.m_dx + m_mouse.m_dy);
  375. }
  376. else if (0 != m_mouse.m_scroll)
  377. {
  378. m_camera.dolly(float(m_mouse.m_scroll)*0.1f);
  379. }
  380. }
  381. float view[16];
  382. float proj[16];
  383. m_camera.update(deltaTimeSec);
  384. bx::memCopy(m_uniforms.m_camPos, &m_camera.m_pos.curr.x, 3*sizeof(float));
  385. m_camera.mtxLookAt(view);
  386. bx::mtxProj(proj, 60.0f, float(m_width)/float(m_height), 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth);
  387. bgfx::setViewTransform(0, view, proj);
  388. m_uniforms.m_drawEdges = (DrawMode::WireframeShaded == m_drawMode) ? 1.0f : 0.0f;
  389. m_uniforms.submit();
  390. if (DrawMode::Wireframe == m_drawMode)
  391. {
  392. uint64_t state = 0
  393. | BGFX_STATE_WRITE_RGB
  394. | BGFX_STATE_WRITE_A
  395. | BGFX_STATE_WRITE_Z
  396. | BGFX_STATE_CULL_CCW
  397. | BGFX_STATE_MSAA
  398. | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA)
  399. ;
  400. meshSubmit(m_meshes[m_meshSelection].m_mesh, 0, m_wfProgram, m_meshes[m_meshSelection].m_mtx, state);
  401. }
  402. else
  403. {
  404. uint64_t state = 0
  405. | BGFX_STATE_WRITE_RGB
  406. | BGFX_STATE_WRITE_A
  407. | BGFX_STATE_DEPTH_TEST_LESS
  408. | BGFX_STATE_WRITE_Z
  409. | BGFX_STATE_CULL_CCW
  410. | BGFX_STATE_MSAA
  411. ;
  412. meshSubmit(m_meshes[m_meshSelection].m_mesh, 0, m_meshProgram, m_meshes[m_meshSelection].m_mtx, state);
  413. }
  414. // Advance to next frame. Rendering thread will be kicked to
  415. // process submitted rendering primitives.
  416. bgfx::frame();
  417. return true;
  418. }
  419. return false;
  420. }
  421. entry::MouseState m_mouseState;
  422. bgfx::ProgramHandle m_wfProgram;
  423. bgfx::ProgramHandle m_meshProgram;
  424. uint32_t m_width;
  425. uint32_t m_height;
  426. uint32_t m_debug;
  427. uint32_t m_reset;
  428. uint32_t m_oldWidth;
  429. uint32_t m_oldHeight;
  430. uint32_t m_oldReset;
  431. Camera m_camera;
  432. Mouse m_mouse;
  433. Uniforms m_uniforms;
  434. MeshMtx m_meshes[3];
  435. int32_t m_meshSelection;
  436. int32_t m_drawMode; // Holds data for 'DrawMode'.
  437. };
  438. } // namespace
  439. ENTRY_IMPLEMENT_MAIN(
  440. ExampleWireframe
  441. , "28-wirefame"
  442. , "Drawing wireframe mesh."
  443. , "https://bkaradzic.github.io/bgfx/examples.html#wireframe"
  444. );