wireframe.cpp 12 KB

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