diff --git a/examples/22-windows/windows.cpp b/examples/22-windows/windows.cpp index d0d3b5469..5f3beed3a 100644 --- a/examples/22-windows/windows.cpp +++ b/examples/22-windows/windows.cpp @@ -8,6 +8,8 @@ #include #include +#define MAX_WINDOWS 8 + struct PosColorVertex { float m_x; @@ -57,253 +59,307 @@ static const uint16_t s_cubeIndices[36] = 6, 3, 7, }; -#define MAX_WINDOWS 8 -entry::WindowState windows[MAX_WINDOWS]; +void cmdCreateWindow(const void* _userData); +void cmdDestroyWindow(const void* _userData); -void cmdCreateWindow(const void* /*_userData*/) +class ExampleWindows : public entry::AppI { - entry::WindowHandle handle = entry::createWindow(rand()%1280, rand()%720, 640, 480); - if (entry::isValid(handle) ) +public: + void init(int _argc, char** _argv) BX_OVERRIDE { - char str[256]; - bx::snprintf(str, BX_COUNTOF(str), "Window - handle %d", handle.idx); - entry::setWindowTitle(handle, str); - windows[handle.idx].m_handle = handle; - } -} + Args args(_argc, _argv); -void cmdDestroyWindow(const void* /*_userData*/) -{ - for (uint32_t ii = 0; ii < MAX_WINDOWS; ++ii) - { - if (entry::isValid(windows[ii].m_handle) ) - { - entry::destroyWindow(windows[ii].m_handle); - windows[ii].m_handle.idx = UINT16_MAX; - return; - } - } -} + m_width = 1280; + m_height = 720; + m_debug = BGFX_DEBUG_TEXT; + m_reset = BGFX_RESET_VSYNC; -static const InputBinding s_bindings[] = -{ - { entry::Key::KeyC, entry::Modifier::None, 1, cmdCreateWindow, NULL }, - { entry::Key::KeyD, entry::Modifier::None, 1, cmdDestroyWindow, NULL }, - INPUT_BINDING_END -}; + bgfx::init(args.m_type, args.m_pciId); + bgfx::reset(m_width, m_height, m_reset); -int _main_(int _argc, char** _argv) -{ - Args args(_argc, _argv); - - uint32_t width = 1280; - uint32_t height = 720; - uint32_t debug = BGFX_DEBUG_TEXT; - uint32_t reset = BGFX_RESET_VSYNC; - - bgfx::init(args.m_type, args.m_pciId); - bgfx::reset(width, height, reset); - - const bgfx::Caps* caps = bgfx::getCaps(); - bool swapChainSupported = 0 != (caps->supported & BGFX_CAPS_SWAP_CHAIN); - - if (swapChainSupported) - { - inputAddBindings("22-windows", s_bindings); - } - - // Enable debug text. - bgfx::setDebug(debug); - - // Set view 0 clear state. - bgfx::setViewClear(0 - , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH - , 0x303030ff - , 1.0f - , 0 - ); - - // Create vertex stream declaration. - PosColorVertex::init(); - - // Create static vertex buffer. - bgfx::VertexBufferHandle vbh = bgfx::createVertexBuffer( - // Static data can be passed with bgfx::makeRef - bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) ) - , PosColorVertex::ms_decl - ); - - // Create static index buffer. - bgfx::IndexBufferHandle ibh = bgfx::createIndexBuffer( - // Static data can be passed with bgfx::makeRef - bgfx::makeRef(s_cubeIndices, sizeof(s_cubeIndices) ) - ); - - // Create program from shaders. - bgfx::ProgramHandle program = loadProgram("vs_cubes", "fs_cubes"); - - float at[3] = { 0.0f, 0.0f, 0.0f }; - float eye[3] = { 0.0f, 0.0f, -35.0f }; - - int64_t timeOffset = bx::getHPCounter(); - - bgfx::FrameBufferHandle fbh[MAX_WINDOWS]; - memset(fbh, 0xff, sizeof(fbh) ); - - entry::WindowState state; - while (!entry::processWindowEvents(state, debug, reset) ) - { - if (isValid(state.m_handle) ) - { - if (0 == state.m_handle.idx) - { - width = state.m_width; - height = state.m_height; - } - else - { - uint8_t viewId = (uint8_t)state.m_handle.idx; - entry::WindowState& win = windows[viewId]; - - if (win.m_nwh != state.m_nwh - || (win.m_width != state.m_width - || win.m_height != state.m_height) ) - { - // When window changes size or native window handle changed - // frame buffer must be recreated. - if (bgfx::isValid(fbh[viewId]) ) - { - bgfx::destroyFrameBuffer(fbh[viewId]); - fbh[viewId].idx = bgfx::invalidHandle; - } - - win.m_nwh = state.m_nwh; - win.m_width = state.m_width; - win.m_height = state.m_height; - - if (NULL != win.m_nwh) - { - fbh[viewId] = bgfx::createFrameBuffer(win.m_nwh, win.m_width, win.m_height); - } - else - { - win.m_handle.idx = UINT16_MAX; - } - } - } - } - - float view[16]; - float proj[16]; - bx::mtxLookAt(view, eye, at); - bx::mtxProj(proj, 60.0f, float(width)/float(height), 0.1f, 100.0f); - - bgfx::setViewTransform(0, view, proj); - bgfx::setViewRect(0, 0, 0, width, height); - // This dummy draw call is here to make sure that view 0 is cleared - // if no other draw calls are submitted to view 0. - bgfx::touch(0); - - // Set view and projection matrix for view 0. - for (uint32_t ii = 1; ii < MAX_WINDOWS; ++ii) - { - bgfx::setViewTransform(ii, view, proj); - bgfx::setViewFrameBuffer(ii, fbh[ii]); - - if (!bgfx::isValid(fbh[ii]) ) - { - // Set view to default viewport. - bgfx::setViewRect(ii, 0, 0, width, height); - bgfx::setViewClear(ii, BGFX_CLEAR_NONE); - } - else - { - bgfx::setViewRect(ii, 0, 0, windows[ii].m_width, windows[ii].m_height); - bgfx::setViewClear(ii - , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH - , 0x303030ff - , 1.0f - , 0 - ); - } - } - - 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)( (now-timeOffset)/double(bx::getHPFrequency() ) ); - - // Use debug font to print information about this example. - bgfx::dbgTextClear(); - bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/22-windows"); - bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Rendering into multiple windows."); - bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + const bgfx::Caps* caps = bgfx::getCaps(); + bool swapChainSupported = 0 != (caps->supported & BGFX_CAPS_SWAP_CHAIN); if (swapChainSupported) { - bgfx::dbgTextPrintf(0, 5, 0x2f, "Press 'c' to create or 'd' to destroy window."); + m_bindings = (InputBinding*)BX_ALLOC(entry::getAllocator(), sizeof(InputBinding)*3); + m_bindings[0].set(entry::Key::KeyC, entry::Modifier::None, 1, cmdCreateWindow, this); + m_bindings[1].set(entry::Key::KeyD, entry::Modifier::None, 1, cmdDestroyWindow, this); + m_bindings[2].end(); + + inputAddBindings("22-windows", m_bindings); } else { - bool blink = uint32_t(time*3.0f)&1; - bgfx::dbgTextPrintf(0, 5, blink ? 0x1f : 0x01, " Multiple windows is not supported by `%s` renderer. ", bgfx::getRendererName(caps->rendererType) ); + m_bindings = NULL; } - uint32_t count = 0; + // Enable m_debug text. + bgfx::setDebug(m_debug); - // Submit 11x11 cubes. - for (uint32_t yy = 0; yy < 11; ++yy) + // Set view 0 clear state. + bgfx::setViewClear(0 + , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH + , 0x303030ff + , 1.0f + , 0 + ); + + // Create vertex stream declaration. + PosColorVertex::init(); + + // Create static vertex buffer. + m_vbh = bgfx::createVertexBuffer( + // Static data can be passed with bgfx::makeRef + bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) ) + , PosColorVertex::ms_decl + ); + + // Create static index buffer. + m_ibh = bgfx::createIndexBuffer( + // Static data can be passed with bgfx::makeRef + bgfx::makeRef(s_cubeIndices, sizeof(s_cubeIndices) ) + ); + + // Create program from shaders. + m_program = loadProgram("vs_cubes", "fs_cubes"); + + m_timeOffset = bx::getHPCounter(); + + memset(m_fbh, 0xff, sizeof(m_fbh) ); + } + + virtual int shutdown() BX_OVERRIDE + { + for (uint32_t ii = 0; ii < MAX_WINDOWS; ++ii) { - for (uint32_t xx = 0; xx < 11; ++xx) + if (bgfx::isValid(m_fbh[ii]) ) { - float mtx[16]; - bx::mtxRotateXY(mtx, time + xx*0.21f, time + yy*0.37f); - mtx[12] = -15.0f + float(xx)*3.0f; - mtx[13] = -15.0f + float(yy)*3.0f; - mtx[14] = 0.0f; - - // Set model matrix for rendering. - bgfx::setTransform(mtx); - - // Set vertex and index buffer. - bgfx::setVertexBuffer(vbh); - bgfx::setIndexBuffer(ibh); - - // Set render states. - bgfx::setState(BGFX_STATE_DEFAULT); - - // Submit primitive for rendering. - bgfx::submit(count%MAX_WINDOWS, program); - ++count; + bgfx::destroyFrameBuffer(m_fbh[ii]); } } - // Advance to next frame. Rendering thread will be kicked to - // process submitted rendering primitives. - bgfx::frame(); + BX_FREE(entry::getAllocator(), m_bindings); + + // Cleanup. + bgfx::destroyIndexBuffer(m_ibh); + bgfx::destroyVertexBuffer(m_vbh); + bgfx::destroyProgram(m_program); + + // Shutdown bgfx. + bgfx::shutdown(); + + return 0; } - for (uint32_t ii = 0; ii < MAX_WINDOWS; ++ii) + bool update() BX_OVERRIDE { - if (bgfx::isValid(fbh[ii]) ) + entry::WindowState state; + if (!entry::processWindowEvents(state, m_debug, m_reset) ) { - bgfx::destroyFrameBuffer(fbh[ii]); + if (isValid(state.m_handle) ) + { + if (0 == state.m_handle.idx) + { + m_width = state.m_width; + m_height = state.m_height; + } + else + { + uint8_t viewId = (uint8_t)state.m_handle.idx; + entry::WindowState& win = m_windows[viewId]; + + if (win.m_nwh != state.m_nwh + || (win.m_width != state.m_width + || win.m_height != state.m_height) ) + { + // When window changes size or native window handle changed + // frame buffer must be recreated. + if (bgfx::isValid(m_fbh[viewId]) ) + { + bgfx::destroyFrameBuffer(m_fbh[viewId]); + m_fbh[viewId].idx = bgfx::invalidHandle; + } + + win.m_nwh = state.m_nwh; + win.m_width = state.m_width; + win.m_height = state.m_height; + + if (NULL != win.m_nwh) + { + m_fbh[viewId] = bgfx::createFrameBuffer(win.m_nwh, win.m_width, win.m_height); + } + else + { + win.m_handle.idx = UINT16_MAX; + } + } + } + } + + float at[3] = { 0.0f, 0.0f, 0.0f }; + float eye[3] = { 0.0f, 0.0f, -35.0f }; + + float view[16]; + bx::mtxLookAt(view, eye, at); + + float proj[16]; + bx::mtxProj(proj, 60.0f, float(m_width)/float(m_height), 0.1f, 100.0f); + + bgfx::setViewTransform(0, view, proj); + bgfx::setViewRect(0, 0, 0, m_width, m_height); + // This dummy draw call is here to make sure that view 0 is cleared + // if no other draw calls are submitted to view 0. + bgfx::touch(0); + + // Set view and projection matrix for view 0. + for (uint32_t ii = 1; ii < MAX_WINDOWS; ++ii) + { + bgfx::setViewTransform(ii, view, proj); + bgfx::setViewFrameBuffer(ii, m_fbh[ii]); + + if (!bgfx::isValid(m_fbh[ii]) ) + { + // Set view to default viewport. + bgfx::setViewRect(ii, 0, 0, m_width, m_height); + bgfx::setViewClear(ii, BGFX_CLEAR_NONE); + } + else + { + bgfx::setViewRect(ii, 0, 0, m_windows[ii].m_width, m_windows[ii].m_height); + bgfx::setViewClear(ii + , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH + , 0x303030ff + , 1.0f + , 0 + ); + } + } + + 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)( (now-m_timeOffset)/double(bx::getHPFrequency() ) ); + + // Use debug font to print information about this example. + bgfx::dbgTextClear(); + bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/22-windows"); + bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Rendering into multiple windows."); + bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + + if (NULL != m_bindings) + { + bgfx::dbgTextPrintf(0, 5, 0x2f, "Press 'c' to create or 'd' to destroy window."); + } + else + { + bool blink = uint32_t(time*3.0f)&1; + bgfx::dbgTextPrintf(0, 5, blink ? 0x1f : 0x01, " Multiple windows is not supported by `%s` renderer. ", bgfx::getRendererName(bgfx::getCaps()->rendererType) ); + } + + uint32_t count = 0; + + // Submit 11x11 cubes. + for (uint32_t yy = 0; yy < 11; ++yy) + { + for (uint32_t xx = 0; xx < 11; ++xx) + { + float mtx[16]; + bx::mtxRotateXY(mtx, time + xx*0.21f, time + yy*0.37f); + mtx[12] = -15.0f + float(xx)*3.0f; + mtx[13] = -15.0f + float(yy)*3.0f; + mtx[14] = 0.0f; + + // Set model matrix for rendering. + bgfx::setTransform(mtx); + + // Set vertex and index buffer. + bgfx::setVertexBuffer(m_vbh); + bgfx::setIndexBuffer(m_ibh); + + // Set render states. + bgfx::setState(BGFX_STATE_DEFAULT); + + // Submit primitive for rendering. + bgfx::submit(count%MAX_WINDOWS, m_program); + ++count; + } + } + + // Advance to next frame. Rendering thread will be kicked to + // process submitted rendering primitives. + bgfx::frame(); + + return true; + } + + return false; + } + + void createWindow() + { + entry::WindowHandle handle = entry::createWindow(rand()%1280, rand()%720, 640, 480); + if (entry::isValid(handle) ) + { + char str[256]; + bx::snprintf(str, BX_COUNTOF(str), "Window - handle %d", handle.idx); + entry::setWindowTitle(handle, str); + m_windows[handle.idx].m_handle = handle; } } -// entry::destroyWindow(win.m_handle); + void destroyWindow() + { + for (uint32_t ii = 0; ii < MAX_WINDOWS; ++ii) + { + if (bgfx::isValid(m_fbh[ii]) ) + { + bgfx::destroyFrameBuffer(m_fbh[ii]); + m_fbh[ii].idx = bgfx::invalidHandle; - // Cleanup. - bgfx::destroyIndexBuffer(ibh); - bgfx::destroyVertexBuffer(vbh); - bgfx::destroyProgram(program); + // Flush destruction of swap chain before destroying window! + bgfx::frame(); + bgfx::frame(); + } - // Shutdown bgfx. - bgfx::shutdown(); + if (entry::isValid(m_windows[ii].m_handle) ) + { + entry::destroyWindow(m_windows[ii].m_handle); + m_windows[ii].m_handle.idx = UINT16_MAX; + return; + } + } + } - return 0; + uint32_t m_width; + uint32_t m_height; + uint32_t m_debug; + uint32_t m_reset; + + bgfx::VertexBufferHandle m_vbh; + bgfx::IndexBufferHandle m_ibh; + bgfx::ProgramHandle m_program; + + entry::WindowState m_windows[MAX_WINDOWS]; + bgfx::FrameBufferHandle m_fbh[MAX_WINDOWS]; + + InputBinding* m_bindings; + + int64_t m_timeOffset; +}; + +ENTRY_IMPLEMENT_MAIN(ExampleWindows); + +void cmdCreateWindow(const void* _userData) +{ + ( (ExampleWindows*)_userData)->createWindow(); +} + +void cmdDestroyWindow(const void* _userData) +{ + ( (ExampleWindows*)_userData)->destroyWindow(); } diff --git a/examples/common/entry/entry_windows.cpp b/examples/common/entry/entry_windows.cpp index 401e971e6..28e6f28fe 100644 --- a/examples/common/entry/entry_windows.cpp +++ b/examples/common/entry/entry_windows.cpp @@ -560,10 +560,15 @@ namespace entry case WM_USER_WINDOW_DESTROY: { WindowHandle handle = { (uint16_t)_wparam }; - PostMessageA(m_hwnd[_wparam], WM_CLOSE, 0, 0); m_eventQueue.postWindowEvent(handle); DestroyWindow(m_hwnd[_wparam]); m_hwnd[_wparam] = 0; + + if (0 == handle.idx) + { + m_exit = true; + m_eventQueue.postExitEvent(); + } } break; @@ -615,15 +620,7 @@ namespace entry case WM_QUIT: case WM_CLOSE: - if (_hwnd == m_hwnd[0]) - { - m_exit = true; - m_eventQueue.postExitEvent(); - } - else - { - destroyWindow(findHandle(_hwnd) ); - } + destroyWindow(findHandle(_hwnd) ); // Don't process message. Window will be destroyed later. return 0; diff --git a/examples/common/entry/input.h b/examples/common/entry/input.h index 66c60c091..f22bf57cf 100644 --- a/examples/common/entry/input.h +++ b/examples/common/entry/input.h @@ -12,6 +12,24 @@ typedef void (*InputBindingFn)(const void* _userData); struct InputBinding { + void set(entry::Key::Enum _key, uint8_t _modifiers, uint8_t _flags, InputBindingFn _fn, const void* _userData = NULL) + { + m_key = _key; + m_modifiers = _modifiers; + m_flags = _flags; + m_fn = _fn; + m_userData = _userData; + } + + void end() + { + m_key = entry::Key::None; + m_modifiers = entry::Modifier::None; + m_flags = 0; + m_fn = NULL; + m_userData = NULL; + } + entry::Key::Enum m_key; uint8_t m_modifiers; uint8_t m_flags;