wireframe.cpp 13 KB

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