diff options
Diffstat (limited to '3rdparty/bgfx/examples/30-picking/picking.cpp')
-rw-r--r-- | 3rdparty/bgfx/examples/30-picking/picking.cpp | 381 |
1 files changed, 199 insertions, 182 deletions
diff --git a/3rdparty/bgfx/examples/30-picking/picking.cpp b/3rdparty/bgfx/examples/30-picking/picking.cpp index 563e44bf684..22e4af9bb00 100644 --- a/3rdparty/bgfx/examples/30-picking/picking.cpp +++ b/3rdparty/bgfx/examples/30-picking/picking.cpp @@ -9,6 +9,9 @@ #include <bx/rng.h> #include <map> +namespace +{ + #define RENDER_PASS_SHADING 0 // Default forward rendered geo with simple shading #define RENDER_PASS_ID 1 // ID buffer for picking #define RENDER_PASS_BLIT 2 // Blit GPU render target to CPU texture @@ -17,13 +20,19 @@ class ExamplePicking : public entry::AppI { - void init(int _argc, char** _argv) BX_OVERRIDE +public: + ExamplePicking(const char* _name, const char* _description) + : entry::AppI(_name, _description) + { + } + + void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override { Args args(_argc, _argv); - m_width = 1280; - m_height = 720; - m_debug = BGFX_DEBUG_TEXT; + m_width = _width; + m_height = _height; + m_debug = BGFX_DEBUG_NONE; m_reset = BGFX_RESET_VSYNC; bgfx::init(args.m_type, args.m_pciId); @@ -144,7 +153,7 @@ class ExamplePicking : public entry::AppI imguiCreate(); } - int shutdown() BX_OVERRIDE + int shutdown() override { for (uint32_t ii = 0; ii < 12; ++ii) { @@ -152,16 +161,16 @@ class ExamplePicking : public entry::AppI } // Cleanup. - bgfx::destroyProgram(m_shadingProgram); - bgfx::destroyProgram(m_idProgram); + bgfx::destroy(m_shadingProgram); + bgfx::destroy(m_idProgram); - bgfx::destroyUniform(u_tint); - bgfx::destroyUniform(u_id); + bgfx::destroy(u_tint); + bgfx::destroy(u_id); - bgfx::destroyFrameBuffer(m_pickingFB); - bgfx::destroyTexture(m_pickingRT); - bgfx::destroyTexture(m_pickingRTDepth); - bgfx::destroyTexture(m_blitTex); + bgfx::destroy(m_pickingFB); + bgfx::destroy(m_pickingRT); + bgfx::destroy(m_pickingRTDepth); + bgfx::destroy(m_blitTex); imguiDestroy(); @@ -171,212 +180,218 @@ class ExamplePicking : public entry::AppI return 0; } - bool update() BX_OVERRIDE + bool update() override { if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) ) { - bgfx::setViewFrameBuffer(RENDER_PASS_ID, m_pickingFB); - - int64_t now = bx::getHPCounter(); - static int64_t last = now; - const int64_t frameTime = now - last; - last = now; - const double freq = double(bx::getHPFrequency()); - const double toMs = 1000.0 / freq; - float time = (float)( (bx::getHPCounter() - m_timeOffset) / double(bx::getHPFrequency() ) ); - - // Use debug font to print information about this example. - bgfx::dbgTextClear(); - bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/30-picking"); - bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Mouse picking via GPU texture readback."); - bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); - - // Set up matrices for basic forward renderer - const float camSpeed = 0.25; - float cameraSpin = (float)m_cameraSpin; - float eyeDist = 2.5f; - float eye[3] = - { - -eyeDist * bx::fsin(time*cameraSpin*camSpeed), - 0.0f, - -eyeDist * bx::fcos(time*cameraSpin*camSpeed), - }; - float at[3] = { 0.0f, 0.0f, 0.0f }; + // Draw UI + imguiBeginFrame( + m_mouseState.m_mx + , m_mouseState.m_my + , (m_mouseState.m_buttons[entry::MouseButton::Left] ? IMGUI_MBUT_LEFT : 0) + | (m_mouseState.m_buttons[entry::MouseButton::Right] ? IMGUI_MBUT_RIGHT : 0) + | (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0) + , m_mouseState.m_mz + , uint16_t(m_width) + , uint16_t(m_height) + ); + + const bgfx::Caps* caps = bgfx::getCaps(); + bool blitSupport = 0 != (caps->supported & BGFX_CAPS_TEXTURE_BLIT); - float view[16]; - bx::mtxLookAt(view, eye, at); + showExampleDialog(this + , !blitSupport + ? "BGFX_CAPS_TEXTURE_BLIT is not supported." + : NULL + ); - float proj[16]; - bx::mtxProj(proj, 60.0f, float(m_width) / float(m_height), 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth); + if (blitSupport) + { + ImGui::SetNextWindowPos( + ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f) + , ImGuiSetCond_FirstUseEver + ); + ImGui::Begin("Settings" + , NULL + , ImVec2(m_width / 5.0f, m_height / 2.0f) + , ImGuiWindowFlags_AlwaysAutoResize + ); - // Set up view rect and transform for the shaded pass - bgfx::setViewRect(RENDER_PASS_SHADING, 0, 0, uint16_t(m_width), uint16_t(m_height) ); - bgfx::setViewTransform(RENDER_PASS_SHADING, view, proj); + ImGui::Image(m_pickingRT, ImVec2(m_width / 5.0f - 16.0f, m_width / 5.0f - 16.0f) ); + ImGui::SliderFloat("Field of view", &m_fov, 1.0f, 60.0f); + ImGui::Checkbox("Spin Camera", &m_cameraSpin); - // Set up picking pass - float viewProj[16]; - bx::mtxMul(viewProj, view, proj); + ImGui::End(); - float invViewProj[16]; - bx::mtxInverse(invViewProj, viewProj); + bgfx::setViewFrameBuffer(RENDER_PASS_ID, m_pickingFB); - // Mouse coord in NDC - float mouseXNDC = ( m_mouseState.m_mx / (float)m_width ) * 2.0f - 1.0f; - float mouseYNDC = ((m_height - m_mouseState.m_my) / (float)m_height) * 2.0f - 1.0f; + float time = (float)( (bx::getHPCounter() - m_timeOffset) / double(bx::getHPFrequency() ) ); - float pickEye[3]; - float mousePosNDC[3] = { mouseXNDC, mouseYNDC, 0.0f }; - bx::vec3MulMtxH(pickEye, mousePosNDC, invViewProj); + // Set up matrices for basic forward renderer + const float camSpeed = 0.25; + float cameraSpin = (float)m_cameraSpin; + float eyeDist = 2.5f; + float eye[3] = + { + -eyeDist * bx::fsin(time*cameraSpin*camSpeed), + 0.0f, + -eyeDist * bx::fcos(time*cameraSpin*camSpeed), + }; + float at[3] = { 0.0f, 0.0f, 0.0f }; - float pickAt[3]; - float mousePosNDCEnd[3] = { mouseXNDC, mouseYNDC, 1.0f }; - bx::vec3MulMtxH(pickAt, mousePosNDCEnd, invViewProj); + float view[16]; + bx::mtxLookAt(view, eye, at); - // Look at our unprojected point - float pickView[16]; - bx::mtxLookAt(pickView, pickEye, pickAt); + float proj[16]; + bx::mtxProj(proj, 60.0f, float(m_width) / float(m_height), 0.1f, 100.0f, caps->homogeneousDepth); - // Tight FOV is best for picking - float pickProj[16]; - bx::mtxProj(pickProj, m_fov, 1, 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth); + // Set up view rect and transform for the shaded pass + bgfx::setViewRect(RENDER_PASS_SHADING, 0, 0, uint16_t(m_width), uint16_t(m_height) ); + bgfx::setViewTransform(RENDER_PASS_SHADING, view, proj); - // View rect and transforms for picking pass - bgfx::setViewRect(RENDER_PASS_ID, 0, 0, ID_DIM, ID_DIM); - bgfx::setViewTransform(RENDER_PASS_ID, pickView, pickProj); + // Set up picking pass + float viewProj[16]; + bx::mtxMul(viewProj, view, proj); - // Now that our passes are set up, we can finally draw each mesh + float invViewProj[16]; + bx::mtxInverse(invViewProj, viewProj); - // Picking highlights a mesh so we'll set up this tint color - const float tintBasic[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - const float tintHighlighted[4] = { 0.3f, 0.3f, 2.0f, 1.0f }; + // Mouse coord in NDC + float mouseXNDC = ( m_mouseState.m_mx / (float)m_width ) * 2.0f - 1.0f; + float mouseYNDC = ((m_height - m_mouseState.m_my) / (float)m_height) * 2.0f - 1.0f; - for (uint32_t mesh = 0; mesh < 12; ++mesh) - { - const float scale = m_meshScale[mesh]; - - // Set up transform matrix for each mesh - float mtx[16]; - bx::mtxSRT(mtx - , scale, scale, scale - , 0.0f - , time*0.37f*(mesh % 2 ? 1.0f : -1.0f) - , 0.0f - , (mesh % 4) - 1.5f - , (mesh / 4) - 1.25f - , 0.0f - ); + float pickEye[3]; + float mousePosNDC[3] = { mouseXNDC, mouseYNDC, 0.0f }; + bx::vec3MulMtxH(pickEye, mousePosNDC, invViewProj); - // Submit mesh to both of our render passes - // Set uniform based on if this is the highlighted mesh - bgfx::setUniform(u_tint - , mesh == m_highlighted - ? tintHighlighted - : tintBasic - ); - meshSubmit(m_meshes[mesh], RENDER_PASS_SHADING, m_shadingProgram, mtx); + float pickAt[3]; + float mousePosNDCEnd[3] = { mouseXNDC, mouseYNDC, 1.0f }; + bx::vec3MulMtxH(pickAt, mousePosNDCEnd, invViewProj); - // Submit ID pass based on mesh ID - bgfx::setUniform(u_id, m_idsF[mesh]); - meshSubmit(m_meshes[mesh], RENDER_PASS_ID, m_idProgram, mtx); - } + // Look at our unprojected point + float pickView[16]; + bx::mtxLookAt(pickView, pickEye, pickAt); - // If the user previously clicked, and we're done reading data from GPU, look at ID buffer on CPU - // Whatever mesh has the most pixels in the ID buffer is the one the user clicked on. - if (m_reading == m_currFrame) - { - m_reading = 0; - std::map<uint32_t, uint32_t> ids; // This contains all the IDs found in the buffer - uint32_t maxAmount = 0; - for (uint8_t *x = m_blitData; x < m_blitData + ID_DIM * ID_DIM * 4;) - { - uint8_t rr = *x++; - uint8_t gg = *x++; - uint8_t bb = *x++; - uint8_t aa = *x++; + // Tight FOV is best for picking + float pickProj[16]; + bx::mtxProj(pickProj, m_fov, 1, 0.1f, 100.0f, caps->homogeneousDepth); - const bgfx::Caps* caps = bgfx::getCaps(); - if (bgfx::RendererType::Direct3D9 == caps->rendererType) - { - // Comes back as BGRA - uint8_t temp = rr; - rr = bb; - bb = temp; - } + // View rect and transforms for picking pass + bgfx::setViewRect(RENDER_PASS_ID, 0, 0, ID_DIM, ID_DIM); + bgfx::setViewTransform(RENDER_PASS_ID, pickView, pickProj); - if (0 == (rr|gg|bb) ) // Skip background - { - continue; - } + // Now that our passes are set up, we can finally draw each mesh - uint32_t hashKey = rr + (gg << 8) + (bb << 16) + (aa << 24); - std::map<uint32_t, uint32_t>::iterator mapIter = ids.find(hashKey); - uint32_t amount = 1; - if (mapIter != ids.end() ) - { - amount = mapIter->second + 1; - } + // Picking highlights a mesh so we'll set up this tint color + const float tintBasic[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + const float tintHighlighted[4] = { 0.3f, 0.3f, 2.0f, 1.0f }; - ids[hashKey] = amount; // Amount of times this ID (color) has been clicked on in buffer - maxAmount = maxAmount > amount - ? maxAmount - : amount - ; + for (uint32_t mesh = 0; mesh < 12; ++mesh) + { + const float scale = m_meshScale[mesh]; + + // Set up transform matrix for each mesh + float mtx[16]; + bx::mtxSRT(mtx + , scale, scale, scale + , 0.0f + , time*0.37f*(mesh % 2 ? 1.0f : -1.0f) + , 0.0f + , (mesh % 4) - 1.5f + , (mesh / 4) - 1.25f + , 0.0f + ); + + // Submit mesh to both of our render passes + // Set uniform based on if this is the highlighted mesh + bgfx::setUniform(u_tint + , mesh == m_highlighted + ? tintHighlighted + : tintBasic + ); + meshSubmit(m_meshes[mesh], RENDER_PASS_SHADING, m_shadingProgram, mtx); + + // Submit ID pass based on mesh ID + bgfx::setUniform(u_id, m_idsF[mesh]); + meshSubmit(m_meshes[mesh], RENDER_PASS_ID, m_idProgram, mtx); } - uint32_t idKey = 0; - m_highlighted = UINT32_MAX; - if (maxAmount) + // If the user previously clicked, and we're done reading data from GPU, look at ID buffer on CPU + // Whatever mesh has the most pixels in the ID buffer is the one the user clicked on. + if (m_reading == m_currFrame) { - for (std::map<uint32_t, uint32_t>::iterator mapIter = ids.begin(); mapIter != ids.end(); mapIter++) + m_reading = 0; + std::map<uint32_t, uint32_t> ids; // This contains all the IDs found in the buffer + uint32_t maxAmount = 0; + for (uint8_t *x = m_blitData; x < m_blitData + ID_DIM * ID_DIM * 4;) { - if (mapIter->second == maxAmount) + uint8_t rr = *x++; + uint8_t gg = *x++; + uint8_t bb = *x++; + uint8_t aa = *x++; + + if (bgfx::RendererType::Direct3D9 == caps->rendererType) + { + // Comes back as BGRA + uint8_t temp = rr; + rr = bb; + bb = temp; + } + + if (0 == (rr|gg|bb) ) // Skip background { - idKey = mapIter->first; - break; + continue; } + + uint32_t hashKey = rr + (gg << 8) + (bb << 16) + (aa << 24); + std::map<uint32_t, uint32_t>::iterator mapIter = ids.find(hashKey); + uint32_t amount = 1; + if (mapIter != ids.end() ) + { + amount = mapIter->second + 1; + } + + ids[hashKey] = amount; // Amount of times this ID (color) has been clicked on in buffer + maxAmount = maxAmount > amount + ? maxAmount + : amount + ; } - for (uint32_t ii = 0; ii < 12; ++ii) + uint32_t idKey = 0; + m_highlighted = UINT32_MAX; + if (maxAmount) { - if (m_idsU[ii] == idKey) + for (std::map<uint32_t, uint32_t>::iterator mapIter = ids.begin(); mapIter != ids.end(); mapIter++) { - m_highlighted = ii; - break; + if (mapIter->second == maxAmount) + { + idKey = mapIter->first; + break; + } + } + + for (uint32_t ii = 0; ii < 12; ++ii) + { + if (m_idsU[ii] == idKey) + { + m_highlighted = ii; + break; + } } } } - } - - // Start a new readback? - if (!m_reading - && m_mouseState.m_buttons[entry::MouseButton::Left]) - { - // Blit and read - bgfx::blit(RENDER_PASS_BLIT, m_blitTex, 0, 0, m_pickingRT); - m_reading = bgfx::readTexture(m_blitTex, m_blitData); - } - - // Draw UI - imguiBeginFrame(m_mouseState.m_mx - , m_mouseState.m_my - , (m_mouseState.m_buttons[entry::MouseButton::Left] ? IMGUI_MBUT_LEFT : 0) - | (m_mouseState.m_buttons[entry::MouseButton::Right] ? IMGUI_MBUT_RIGHT : 0) - | (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0) - , m_mouseState.m_mz - , uint16_t(m_width) - , uint16_t(m_height) - ); - - imguiBeginArea("Picking Render Target:", 10, 100, 300, 400); - imguiImage(m_pickingRT, 1.0f, 1.0f, 1.0f); - imguiSlider("FOV", m_fov, 1.0f, 60.0f, 1.0f); - if (imguiCheck("Spin Camera", m_cameraSpin)) - { - m_cameraSpin = !m_cameraSpin; + // Start a new readback? + if (!m_reading + && m_mouseState.m_buttons[entry::MouseButton::Left]) + { + // Blit and read + bgfx::blit(RENDER_PASS_BLIT, m_blitTex, 0, 0, m_pickingRT); + m_reading = bgfx::readTexture(m_blitTex, m_blitData); + } } - imguiEndArea(); imguiEndFrame(); // Advance to next frame. Rendering thread will be kicked to @@ -389,14 +404,14 @@ class ExamplePicking : public entry::AppI return false; } + entry::MouseState m_mouseState; + uint32_t m_width; uint32_t m_height; uint32_t m_debug; uint32_t m_reset; int64_t m_timeOffset; - entry::MouseState m_mouseState; - Mesh* m_meshes[12]; float m_meshScale[12]; float m_idsF[12][4]; @@ -422,4 +437,6 @@ class ExamplePicking : public entry::AppI bool m_cameraSpin; }; -ENTRY_IMPLEMENT_MAIN(ExamplePicking); +} // namespace + +ENTRY_IMPLEMENT_MAIN(ExamplePicking, "30-picking", "Mouse picking via GPU texture readback."); |