Encapsulated platform dependent part of studio in an interface - closes #593

This commit is contained in:
Mikulas Florek 2015-10-25 13:07:53 +01:00
parent db8475909d
commit 202dd3d339
9 changed files with 675 additions and 327 deletions

View file

@ -27,8 +27,6 @@
#include "renderer/texture_manager.h"
#include "universe/universe.h"
#include <bgfx/bgfx.h>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <cstdio>
@ -198,10 +196,10 @@ struct RendererImpl : public Renderer
, m_frame_allocator(m_allocator, 10 * 1024 * 1024)
{
bgfx::PlatformData d;
if (s_hwnd)
if (s_platform_data)
{
memset(&d, 0, sizeof(d));
d.nwh = s_hwnd;
d.nwh = s_platform_data;
bgfx::setPlatformData(d);
}
bgfx::init(bgfx::RendererType::Count, 0, 0, &m_callback_stub/*, &m_bgfx_allocator*/);
@ -569,16 +567,16 @@ struct RendererImpl : public Renderer
int m_view_counter;
BGFXAllocator m_bgfx_allocator;
static HWND s_hwnd;
static void* s_platform_data;
};
HWND RendererImpl::s_hwnd = nullptr;
void* RendererImpl::s_platform_data = nullptr;
void Renderer::setInitData(void* data)
{
RendererImpl::s_hwnd = (HWND)data;
RendererImpl::s_platform_data = data;
}

View file

@ -5,6 +5,7 @@
#include "core/resource_manager.h"
#include "engine/engine.h"
#include "ocornut-imgui/imgui.h"
#include "platform_interface.h"
#include "renderer/frame_buffer.h"
#include "renderer/pipeline.h"
#include "renderer/render_scene.h"
@ -18,7 +19,6 @@ GameView::GameView()
, m_is_mouse_captured(false)
, m_editor(nullptr)
, m_is_mouse_hovering_window(false)
, m_hwnd(NULL)
{
}
@ -41,9 +41,8 @@ void GameView::onUniverseDestroyed()
}
void GameView::init(HWND hwnd, Lumix::WorldEditor& editor)
void GameView::init(Lumix::WorldEditor& editor)
{
m_hwnd = hwnd;
m_editor = &editor;
auto& engine = editor.getEngine();
auto* pipeline_manager = engine.getResourceManager().get(Lumix::ResourceManager::PIPELINE);
@ -79,8 +78,8 @@ void GameView::captureMouse(bool capture)
{
m_is_mouse_captured = capture;
m_editor->getEngine().getInputSystem().enable(m_is_mouse_captured);
ShowCursor(!m_is_mouse_captured);
if (!m_is_mouse_captured) ClipCursor(NULL);
PlatformInterface::showCursor(!m_is_mouse_captured);
if (!m_is_mouse_captured) PlatformInterface::unclipCursor();
}
@ -92,9 +91,9 @@ void GameView::onGui()
auto& io = ImGui::GetIO();
HWND foreground_win = GetForegroundWindow();
if (m_is_mouse_captured &&
(io.KeysDown[VK_ESCAPE] || !m_editor->isGameMode() || foreground_win != m_hwnd))
bool is_foreground_win = PlatformInterface::isForegroundWindow();
if (m_is_mouse_captured && (io.KeysDown[ImGui::GetKeyIndex(ImGuiKey_Escape)] ||
!m_editor->isGameMode() || !is_foreground_win))
{
captureMouse(false);
}
@ -122,21 +121,13 @@ void GameView::onGui()
if (m_is_mouse_captured)
{
POINT min;
POINT max;
min.x = LONG(content_min.x);
min.y = LONG(content_min.y);
max.x = LONG(content_max.x);
max.y = LONG(content_max.y);
ClientToScreen(m_hwnd, &min);
ClientToScreen(m_hwnd, &max);
RECT rect;
rect.left = min.x;
rect.right = max.x;
rect.top = min.y;
rect.bottom = max.y;
ClipCursor(&rect);
if (io.KeysDown[VK_ESCAPE] || !m_editor->isGameMode()) captureMouse(false);
PlatformInterface::clipCursor(
content_min.x, content_min.y, content_max.x, content_max.y);
if (io.KeysDown[ImGui::GetKeyIndex(ImGuiKey_Escape)] || !m_editor->isGameMode())
{
captureMouse(false);
}
}
if (ImGui::IsMouseHoveringRect(content_min, content_max) && m_is_mouse_hovering_window &&

View file

@ -3,8 +3,9 @@
#include "editor/world_editor.h"
#include <bgfx/bgfx.h>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
struct PlatformData;
namespace Lumix
@ -21,7 +22,7 @@ public:
GameView();
~GameView();
void init(HWND hwnd, Lumix::WorldEditor& editor);
void init(Lumix::WorldEditor& editor);
void shutdown();
void onGui();
void setScene(Lumix::RenderScene* scene);
@ -42,5 +43,4 @@ private:
bgfx::TextureHandle m_texture_handle;
Lumix::WorldEditor* m_editor;
bool m_is_mouse_hovering_window;
HWND m_hwnd;
};

View file

@ -24,6 +24,7 @@
#include "log_ui.h"
#include "metadata.h"
#include "ocornut-imgui/imgui.h"
#include "platform_interface.h"
#include "profiler_ui.h"
#include "property_grid.h"
#include "renderer/frame_buffer.h"
@ -39,16 +40,12 @@
#include "utils.h"
#include <bgfx/bgfx.h>
#include <cstdio>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <mmsystem.h>
// http://prideout.net/blog/?p=36
void imGuiCallback(ImDrawData* draw_data);
LRESULT WINAPI msgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
class StudioApp
@ -70,7 +67,6 @@ public:
, m_metadata(m_allocator)
, m_gui_pipeline(nullptr)
, m_is_welcome_screen_opened(true)
, m_is_mouse_tracked(false)
{
m_entity_list_search[0] = '\0';
m_template_name[0] = '\0';
@ -119,10 +115,8 @@ public:
{
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
RECT client_rect;
GetClientRect(m_hwnd, &client_rect);
ImVec2 size(float(client_rect.right - client_rect.left),
float(client_rect.bottom - client_rect.top));
ImVec2 size((float)PlatformInterface::getWindowWidth(),
(float)PlatformInterface::getWindowHeight());
if (ImGui::Begin("Welcome", nullptr, size, -1, flags))
{
ImGui::Text("Welcome to Lumix Studio");
@ -210,18 +204,18 @@ public:
if (!m_gui_pipeline_source->isReady()) return;
ImGuiIO& io = ImGui::GetIO();
RECT rect;
GetClientRect(m_hwnd, &rect);
io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
io.DisplaySize = ImVec2((float)PlatformInterface::getWindowWidth(),
(float)PlatformInterface::getWindowHeight());
io.DeltaTime = m_engine->getLastTimeDelta();
io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
io.KeyAlt = (GetKeyState(VK_MENU) & 0x8000) != 0;
io.KeysDown[VK_MENU] = io.KeyAlt;
io.KeysDown[VK_SHIFT] = io.KeyShift;
io.KeysDown[VK_CONTROL] = io.KeyCtrl;
io.KeyCtrl = PlatformInterface::isPressed((int)PlatformInterface::Keys::CONTROL);
io.KeyShift = PlatformInterface::isPressed((int)PlatformInterface::Keys::SHIFT);
io.KeyAlt = PlatformInterface::isPressed((int)PlatformInterface::Keys::ALT);
io.KeysDown[(int)PlatformInterface::Keys::ALT] = io.KeyAlt;
io.KeysDown[(int)PlatformInterface::Keys::SHIFT] = io.KeyShift;
io.KeysDown[(int)PlatformInterface::Keys::CONTROL] = io.KeyCtrl;
SetCursor(io.MouseDrawCursor ? NULL : LoadCursor(NULL, IDC_ARROW));
PlatformInterface::setCursor(io.MouseDrawCursor ? PlatformInterface::Cursor::NONE
: PlatformInterface::Cursor::DEFAULT);
ImGui::NewFrame();
@ -255,7 +249,7 @@ public:
char tmp[100];
Lumix::copyString(tmp, "Lumix Studio - ");
Lumix::catString(tmp, title);
SetWindowTextA(m_hwnd, tmp);
PlatformInterface::setWindowTitle(tmp);
}
@ -265,7 +259,7 @@ public:
for (int i = 0; i < Lumix::lengthOf(action.shortcut); ++i)
{
char str[30];
getKeyName(action.shortcut[i], str, Lumix::lengthOf(str));
PlatformInterface::getKeyName(action.shortcut[i], str, Lumix::lengthOf(str));
if (str[0] == 0) return;
if (i > 0) Lumix::catString(buf, max_size, " - ");
Lumix::catString(buf, max_size, str);
@ -316,7 +310,7 @@ public:
}
void exit() { PostQuitMessage(0); }
void exit() { m_finished = true; }
void newUniverse()
{
@ -709,7 +703,7 @@ public:
m_gui_pipeline_source = nullptr;
m_editor = nullptr;
UnregisterClassA("lmxa", m_instance);
PlatformInterface::shutdown();
}
@ -726,20 +720,8 @@ public:
}
void trackMouse()
{
TRACKMOUSEEVENT track_event;
track_event.cbSize = sizeof(TRACKMOUSEEVENT);
track_event.dwFlags = TME_LEAVE;
track_event.hwndTrack = m_hwnd;
m_is_mouse_tracked = TrackMouseEvent(&track_event) == TRUE;
}
void initIMGUI()
{
trackMouse();
ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontFromFileTTF("editor/VeraMono.ttf", 13);
@ -749,19 +731,19 @@ public:
.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
.end();
io.KeyMap[ImGuiKey_Tab] = VK_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN;
io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR;
io.KeyMap[ImGuiKey_PageDown] = VK_NEXT;
io.KeyMap[ImGuiKey_Home] = VK_HOME;
io.KeyMap[ImGuiKey_End] = VK_END;
io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
io.KeyMap[ImGuiKey_Tab] = (int)PlatformInterface::Keys::TAB;
io.KeyMap[ImGuiKey_LeftArrow] = (int)PlatformInterface::Keys::LEFT;
io.KeyMap[ImGuiKey_RightArrow] = (int)PlatformInterface::Keys::RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = (int)PlatformInterface::Keys::UP;
io.KeyMap[ImGuiKey_DownArrow] = (int)PlatformInterface::Keys::DOWN;
io.KeyMap[ImGuiKey_PageUp] = (int)PlatformInterface::Keys::PAGE_UP;
io.KeyMap[ImGuiKey_PageDown] = (int)PlatformInterface::Keys::PAGE_DOWN;
io.KeyMap[ImGuiKey_Home] = (int)PlatformInterface::Keys::HOME;
io.KeyMap[ImGuiKey_End] = (int)PlatformInterface::Keys::END;
io.KeyMap[ImGuiKey_Delete] = (int)PlatformInterface::Keys::DEL;
io.KeyMap[ImGuiKey_Backspace] = (int)PlatformInterface::Keys::BACKSPACE;
io.KeyMap[ImGuiKey_Enter] = (int)PlatformInterface::Keys::ENTER;
io.KeyMap[ImGuiKey_Escape] = (int)PlatformInterface::Keys::ESCAPE;
io.KeyMap[ImGuiKey_A] = 'A';
io.KeyMap[ImGuiKey_C] = 'C';
io.KeyMap[ImGuiKey_V] = 'V';
@ -770,7 +752,6 @@ public:
io.KeyMap[ImGuiKey_Z] = 'Z';
io.RenderDrawListsFn = ::imGuiCallback;
io.ImeWindowHandle = m_hwnd;
unsigned char* pixels;
int width, height;
@ -819,16 +800,14 @@ public:
if (m_settings.m_is_maximized)
{
ShowWindow(m_hwnd, SW_MAXIMIZE);
PlatformInterface::maximizeWindow();
}
else if (m_settings.m_window.w > 0)
{
MoveWindow(m_hwnd,
m_settings.m_window.x,
PlatformInterface::moveWindow(m_settings.m_window.x,
m_settings.m_window.y,
m_settings.m_window.w,
m_settings.m_window.h,
FALSE);
m_settings.m_window.h);
}
}
@ -836,21 +815,31 @@ public:
void addActions()
{
addAction<&StudioApp::newUniverse>("New", "newUniverse");
addAction<&StudioApp::save>("Save", "save", VK_CONTROL, 'S', -1);
addAction<&StudioApp::saveAs>("Save As", "saveAs", VK_CONTROL, VK_SHIFT, 'S');
addAction<&StudioApp::exit>("Exit", "exit", VK_CONTROL, 'X', -1);
addAction<&StudioApp::save>("Save", "save", (int)PlatformInterface::Keys::CONTROL, 'S', -1);
addAction<&StudioApp::saveAs>("Save As",
"saveAs",
(int)PlatformInterface::Keys::CONTROL,
(int)PlatformInterface::Keys::SHIFT,
'S');
addAction<&StudioApp::exit>("Exit", "exit", (int)PlatformInterface::Keys::CONTROL, 'X', -1);
addAction<&StudioApp::redo>("Redo", "redo", VK_CONTROL, VK_SHIFT, 'Z');
addAction<&StudioApp::undo>("Undo", "undo", VK_CONTROL, 'Z', -1);
addAction<&StudioApp::copy>("Copy", "copy", VK_CONTROL, 'C', -1);
addAction<&StudioApp::paste>("Paste", "paste", VK_CONTROL, 'V', -1);
addAction<&StudioApp::redo>("Redo",
"redo",
(int)PlatformInterface::Keys::CONTROL,
(int)PlatformInterface::Keys::SHIFT,
'Z');
addAction<&StudioApp::undo>("Undo", "undo", (int)PlatformInterface::Keys::CONTROL, 'Z', -1);
addAction<&StudioApp::copy>("Copy", "copy", (int)PlatformInterface::Keys::CONTROL, 'C', -1);
addAction<&StudioApp::paste>(
"Paste", "paste", (int)PlatformInterface::Keys::CONTROL, 'V', -1);
addAction<&StudioApp::toggleOrbitCamera>("Orbit camera", "orbitCamera");
addAction<&StudioApp::toggleGizmoMode>("Translate/Rotate", "toggleGizmoMode");
addAction<&StudioApp::togglePivotMode>("Center/Pivot", "togglePivotMode");
addAction<&StudioApp::toggleCoordSystem>("Local/Global", "toggleCoordSystem");
addAction<&StudioApp::createEntity>("Create", "createEntity");
addAction<&StudioApp::destroyEntity>("Destroy", "destroyEntity", VK_DELETE, -1, -1);
addAction<&StudioApp::destroyEntity>(
"Destroy", "destroyEntity", (int)PlatformInterface::Keys::DEL, -1, -1);
addAction<&StudioApp::showEntities>("Show", "showEntities");
addAction<&StudioApp::hideEntities>("Hide", "hideEntities");
@ -889,22 +878,6 @@ public:
}
void processSystemEvents()
{
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
{
m_finished = true;
}
}
}
void run()
{
Lumix::Timer* timer = Lumix::Timer::create(m_allocator);
@ -916,7 +889,7 @@ public:
float frame_time;
{
PROFILE_BLOCK("tick");
processSystemEvents();
m_finished = !PlatformInterface::processSystemEvents();
update();
frame_time = timer->tick();
}
@ -951,38 +924,119 @@ public:
}
void createWindow(HINSTANCE hInst)
struct SystemEventHandler : public PlatformInterface::SystemEventHandler
{
WNDCLASSEX wnd;
memset(&wnd, 0, sizeof(wnd));
wnd.cbSize = sizeof(wnd);
wnd.style = CS_HREDRAW | CS_VREDRAW;
wnd.lpfnWndProc = msgProc;
wnd.hInstance = hInst;
wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
wnd.lpszClassName = "lmxa";
wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
auto x = RegisterClassExA(&wnd);
m_hwnd = CreateWindowA(
"lmxa", "lmxa", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 800, 600, NULL, NULL, hInst, 0);
ASSERT(m_hwnd);
SetWindowTextA(m_hwnd, "Lumix Studio");
}
void onWindowTransformed(int x, int y, int w, int h) override
{
m_app->onWindowTransformed(x, y, w, h);
}
void onMouseLeftWindow() override { m_app->clearInputs(); }
void init(HINSTANCE hInst)
void onMouseMove(int x, int y, int rel_x, int rel_y) override
{
m_mouse_x = x;
m_mouse_y = y;
auto& input_system = m_app->m_editor->getEngine().getInputSystem();
input_system.injectMouseXMove(float(rel_x));
input_system.injectMouseYMove(float(rel_y));
if (m_app->m_gameview.isMouseCaptured()) return;
m_app->m_sceneview.onMouseMove(x, y, rel_x, rel_y);
ImGuiIO& io = ImGui::GetIO();
io.MousePos.x = (float)x;
io.MousePos.y = (float)y;
}
void onMouseWheel(int amount) override
{
ImGui::GetIO().MouseWheel = amount / 600.0f;
}
void onMouseButtonDown(MouseButton button) override
{
switch (button)
{
case PlatformInterface::SystemEventHandler::MouseButton::LEFT:
m_app->m_editor->setAdditiveSelection(ImGui::GetIO().KeyCtrl);
if (!m_app->m_sceneview.onMouseDown(
m_mouse_x, m_mouse_y, Lumix::MouseButton::LEFT) &&
!m_app->m_gameview.isMouseCaptured())
{
ImGui::GetIO().MouseDown[0] = true;
}
break;
case PlatformInterface::SystemEventHandler::MouseButton::RIGHT:
if (!m_app->m_sceneview.onMouseDown(
m_mouse_x, m_mouse_y, Lumix::MouseButton::RIGHT) &&
!m_app->m_gameview.isMouseCaptured())
{
ImGui::GetIO().MouseDown[1] = true;
}
break;
}
}
void onMouseButtonUp(MouseButton button) override
{
switch (button)
{
case PlatformInterface::SystemEventHandler::MouseButton::LEFT:
m_app->m_sceneview.onMouseUp(Lumix::MouseButton::LEFT);
ImGui::GetIO().MouseDown[0] = false;
break;
case PlatformInterface::SystemEventHandler::MouseButton::RIGHT:
m_app->m_sceneview.onMouseUp(Lumix::MouseButton::RIGHT);
ImGui::GetIO().MouseDown[1] = false;
break;
}
}
void onKeyDown(int key) override
{
ImGui::GetIO().KeysDown[key] = true;
m_app->checkShortcuts();
}
void onKeyUp(int key) override
{
ImGui::GetIO().KeysDown[key] = false;
}
void onChar(int key)
{
ImGui::GetIO().AddInputCharacter(key);
}
int m_mouse_x;
int m_mouse_y;
StudioApp* m_app;
};
SystemEventHandler m_handler;
void init()
{
checkWorkingDirector();
m_handler.m_app = this;
PlatformInterface::createWindow(&m_handler);
m_instance = hInst;
createWindow(hInst);
Lumix::Renderer::setInitData(m_hwnd);
m_engine = Lumix::Engine::create(nullptr, m_allocator);
char current_dir[MAX_PATH];
GetCurrentDirectory(sizeof(current_dir), current_dir);
char current_dir[Lumix::MAX_PATH_LENGTH];
PlatformInterface::getCurrentDirectory(current_dir, Lumix::lengthOf(current_dir));
m_editor = Lumix::WorldEditor::create(current_dir, *m_engine, m_allocator);
loadUserPlugins();
@ -1009,28 +1063,20 @@ public:
Lumix::PipelineInstance::create(*m_gui_pipeline_source, m_engine->getAllocator());
m_sceneview.init(*m_editor, m_actions);
m_gameview.init(m_hwnd, *m_editor);
m_gameview.init(*m_editor);
RECT rect;
GetClientRect(m_hwnd, &rect);
m_gui_pipeline->setViewport(0, 0, rect.right, rect.bottom);
int w = PlatformInterface::getWindowWidth();
int h = PlatformInterface::getWindowHeight();
m_gui_pipeline->setViewport(0, 0, w, h);
auto& plugin_manager = m_editor->getEngine().getPluginManager();
auto* renderer = static_cast<Lumix::Renderer*>(plugin_manager.getPlugin("renderer"));
renderer->resize(rect.right, rect.bottom);
renderer->resize(w, h);
onUniverseCreated();
initIMGUI();
loadSettings();
if (!m_metadata.load()) Lumix::g_log_info.log("studio") << "Could not load metadata";
timeBeginPeriod(1);
RAWINPUTDEVICE Rid;
Rid.usUsagePage = 0x01;
Rid.usUsage = 0x02;
Rid.dwFlags = 0;
Rid.hwndTarget = 0;
RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
}
@ -1057,146 +1103,25 @@ public:
}
void onWindowTransformed()
void onWindowTransformed(int x, int y, int width, int height)
{
RECT rect;
GetWindowRect(m_hwnd, &rect);
m_settings.m_window.x = rect.left;
m_settings.m_window.y = rect.top;
m_settings.m_window.w = rect.right - rect.left;
m_settings.m_window.h = rect.bottom - rect.top;
WINDOWPLACEMENT wndpl;
wndpl.length = sizeof(wndpl);
if (GetWindowPlacement(m_hwnd, &wndpl))
{
m_settings.m_is_maximized = wndpl.showCmd == SW_MAXIMIZE;
}
}
m_settings.m_window.x = x;
m_settings.m_window.y = y;
m_settings.m_window.w = width;
m_settings.m_window.h = height;
m_settings.m_is_maximized = PlatformInterface::isMaximized();
void handleRawInput(LPARAM lParam)
{
UINT dwSize;
char data[sizeof(RAWINPUT) * 10];
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
if (dwSize > sizeof(data)) return;
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &dwSize, sizeof(RAWINPUTHEADER)) !=
dwSize) return;
RAWINPUT* raw = (RAWINPUT*)data;
if (raw->header.dwType == RIM_TYPEMOUSE &&
raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE)
{
m_editor->getEngine().getInputSystem().injectMouseXMove(float(raw->data.mouse.lLastX));
m_editor->getEngine().getInputSystem().injectMouseYMove(float(raw->data.mouse.lLastY));
}
}
LRESULT windowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
int x = LOWORD(lParam);
int y = HIWORD(lParam);
static int old_x = x;
static int old_y = y;
if (!m_gui_pipeline)
{
return DefWindowProc(hWnd, msg, wParam, lParam);
}
switch (msg)
{
case WM_INPUT: handleRawInput(lParam); break;
case WM_CLOSE: PostQuitMessage(0); break;
case WM_MOVE: onWindowTransformed(); break;
case WM_SIZE:
{
onWindowTransformed();
uint32_t width = ((int)(short)LOWORD(lParam));
uint32_t height = ((int)(short)HIWORD(lParam));
m_gui_pipeline->setViewport(0, 0, width, height);
auto& plugin_manager = m_editor->getEngine().getPluginManager();
auto* renderer =
static_cast<Lumix::Renderer*>(plugin_manager.getPlugin("renderer"));
renderer->resize(width, height);
}
break;
case WM_MOUSEWHEEL:
ImGui::GetIO().MouseWheel = GET_WHEEL_DELTA_WPARAM(wParam) / 600.0f;
break;
case WM_ERASEBKGND: return 1;
case WM_LBUTTONUP:
m_sceneview.onMouseUp(Lumix::MouseButton::LEFT);
ImGui::GetIO().MouseDown[0] = false;
break;
case WM_LBUTTONDOWN:
m_editor->setAdditiveSelection(ImGui::GetIO().KeyCtrl);
if (!m_sceneview.onMouseDown(old_x, old_y, Lumix::MouseButton::LEFT) &&
!m_gameview.isMouseCaptured())
{
ImGui::GetIO().MouseDown[0] = true;
}
break;
case WM_RBUTTONDOWN:
if (!m_sceneview.onMouseDown(old_x, old_y, Lumix::MouseButton::RIGHT) &&
!m_gameview.isMouseCaptured())
{
ImGui::GetIO().MouseDown[1] = true;
}
break;
case WM_RBUTTONUP:
m_sceneview.onMouseUp(Lumix::MouseButton::RIGHT);
ImGui::GetIO().MouseDown[1] = false;
break;
case WM_MOUSEMOVE:
{
if (!m_is_mouse_tracked) trackMouse();
if (!m_gameview.isMouseCaptured())
{
POINT p;
p.x = x;
p.y = y;
ClientToScreen(m_hwnd, &p);
m_sceneview.onMouseMove(old_x, old_y, x - old_x, y - old_y);
old_x = x;
old_y = y;
ImGuiIO& io = ImGui::GetIO();
io.MousePos.x = (float)x;
io.MousePos.y = (float)y;
}
}
break;
case WM_MOUSELEAVE:
clearInputs();
break;
case WM_CHAR: ImGui::GetIO().AddInputCharacter((ImWchar)wParam); break;
case WM_KEYUP: ImGui::GetIO().KeysDown[wParam] = false; break;
case WM_SYSKEYDOWN: ImGui::GetIO().KeysDown[wParam] = true; break;
case WM_SYSKEYUP: ImGui::GetIO().KeysDown[wParam] = false; break;
case WM_KEYDOWN:
{
ImGui::GetIO().KeysDown[wParam] = true;
checkShortcuts();
break;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
m_gui_pipeline->setViewport(0, 0, width, height);
auto& plugin_manager = m_editor->getEngine().getPluginManager();
auto* renderer =
static_cast<Lumix::Renderer*>(plugin_manager.getPlugin("renderer"));
renderer->resize(width, height);
}
void clearInputs()
{
m_is_mouse_tracked = false;
auto& io = ImGui::GetIO();
io.KeyAlt = false;
io.KeyCtrl = false;
@ -1284,8 +1209,6 @@ public:
Lumix::DefaultAllocator m_allocator;
HWND m_hwnd;
HINSTANCE m_instance;
bgfx::VertexDecl m_decl;
Lumix::Material* m_material;
Lumix::Engine* m_engine;
@ -1319,7 +1242,6 @@ public:
bool m_is_entity_template_list_opened;
bool m_is_style_editor_opened;
bool m_is_wireframe;
bool m_is_mouse_tracked;
};
@ -1332,18 +1254,12 @@ static void imGuiCallback(ImDrawData* draw_data)
}
static LRESULT WINAPI msgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return g_app->windowProc(hWnd, msg, wParam, lParam);
}
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
int studioMain()
{
StudioApp app;
g_app = &app;
app.init(hInst);
app.init();
app.run();
app.shutdown();

View file

@ -0,0 +1,400 @@
#include "platform_interface.h"
#include "ocornut-imgui/imgui.h"
#include "renderer/renderer.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <mmsystem.h>
namespace PlatformInterface
{
struct PlatformData
{
PlatformData()
{
for (int i = 0; i < Lumix::lengthOf(m_key_map); ++i)
{
m_key_map[i] = -1;
m_system_key_map[i] = -1;
}
m_key_map[(int)Keys::ALT] = VK_MENU;
m_key_map[(int)Keys::CONTROL] = VK_CONTROL;
m_key_map[(int)Keys::SHIFT] = VK_SHIFT;
m_key_map[(int)Keys::TAB] = VK_TAB;
m_key_map[(int)Keys::LEFT] = VK_LEFT;
m_key_map[(int)Keys::RIGHT] = VK_RIGHT;
m_key_map[(int)Keys::UP] = VK_UP;
m_key_map[(int)Keys::DOWN] = VK_DOWN;
m_key_map[(int)Keys::PAGE_UP] = VK_PRIOR;
m_key_map[(int)Keys::PAGE_DOWN] = VK_NEXT;
m_key_map[(int)Keys::HOME] = VK_HOME;
m_key_map[(int)Keys::END] = VK_END;
m_key_map[(int)Keys::DEL] = VK_DELETE;
m_key_map[(int)Keys::BACKSPACE] = VK_BACK;
m_key_map[(int)Keys::ENTER] = VK_RETURN;
m_key_map[(int)Keys::ESCAPE] = VK_ESCAPE;
for (int i = 0; i < Lumix::lengthOf(m_key_map); ++i)
{
if (m_key_map[i] != -1) m_system_key_map[m_key_map[i]] = i;
}
}
HWND m_hwnd;
bool m_is_mouse_tracked;
SystemEventHandler* m_handler;
int m_key_map[512];
int m_system_key_map[512];
};
static PlatformData g_platform_data;
static int getSystemKey(int key)
{
if (g_platform_data.m_key_map[key] != -1)
{
return g_platform_data.m_key_map[key];
}
else
{
return key;
}
}
static int getKeyFromSystem(int key)
{
if (g_platform_data.m_system_key_map[key] != -1)
{
return g_platform_data.m_system_key_map[key];
}
else
{
return key;
}
}
static void trackMouse()
{
TRACKMOUSEEVENT track_event;
track_event.cbSize = sizeof(TRACKMOUSEEVENT);
track_event.dwFlags = TME_LEAVE;
track_event.hwndTrack = g_platform_data.m_hwnd;
g_platform_data.m_is_mouse_tracked = TrackMouseEvent(&track_event) == TRUE;
}
void getCurrentDirectory(char* buffer, int buffer_size)
{
GetCurrentDirectory(buffer_size, buffer);
}
void shutdown()
{
HINSTANCE hInst = GetModuleHandle(NULL);
UnregisterClassA("lmxa", hInst);
}
void moveWindow(int x, int y, int w, int h)
{
MoveWindow(g_platform_data.m_hwnd, x, y, w, h, FALSE);
}
bool isMaximized()
{
WINDOWPLACEMENT wndpl;
wndpl.length = sizeof(wndpl);
if (GetWindowPlacement(g_platform_data.m_hwnd, &wndpl))
{
return wndpl.showCmd == SW_MAXIMIZE;
}
return false;
}
void maximizeWindow()
{
ShowWindow(g_platform_data.m_hwnd, SW_MAXIMIZE);
}
bool isForegroundWindow()
{
return GetForegroundWindow() == g_platform_data.m_hwnd;
}
void clipCursor(float min_x, float min_y, float max_x, float max_y)
{
POINT min;
POINT max;
min.x = LONG(min_x);
min.y = LONG(min_y);
max.x = LONG(max_x);
max.y = LONG(max_y);
ClientToScreen(g_platform_data.m_hwnd, &min);
ClientToScreen(g_platform_data.m_hwnd, &max);
RECT rect;
rect.left = min.x;
rect.right = max.x;
rect.top = min.y;
rect.bottom = max.y;
ClipCursor(&rect);
}
void showCursor(bool show)
{
ShowCursor(show);
}
void unclipCursor()
{
ClipCursor(NULL);
}
int getWindowX()
{
RECT rect;
GetClientRect(g_platform_data.m_hwnd, &rect);
return int(rect.left);
}
int getWindowY()
{
RECT rect;
GetClientRect(g_platform_data.m_hwnd, &rect);
return int(rect.top);
}
int getWindowWidth()
{
RECT rect;
GetClientRect(g_platform_data.m_hwnd, &rect);
return int(rect.right - rect.left);
}
int getWindowHeight()
{
RECT rect;
GetClientRect(g_platform_data.m_hwnd, &rect);
return int(rect.bottom - rect.top);
}
void handleRawInput(LPARAM lParam)
{
UINT dwSize;
char data[sizeof(RAWINPUT) * 10];
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
if (dwSize > sizeof(data)) return;
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &dwSize, sizeof(RAWINPUTHEADER)) !=
dwSize) return;
RAWINPUT* raw = (RAWINPUT*)data;
if (raw->header.dwType == RIM_TYPEMOUSE &&
raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE)
{
POINT p;
GetCursorPos(&p);
ScreenToClient(g_platform_data.m_hwnd, &p);
g_platform_data.m_handler->onMouseMove(
int(p.x), int(p.y), int(raw->data.mouse.lLastX), int(raw->data.mouse.lLastY));
}
}
static LRESULT WINAPI msgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (!g_platform_data.m_handler) return DefWindowProc(hWnd, msg, wParam, lParam);
int x = LOWORD(lParam);
int y = HIWORD(lParam);
switch (msg)
{
case WM_LBUTTONUP:
g_platform_data.m_handler->onMouseButtonUp(SystemEventHandler::MouseButton::LEFT);
break;
case WM_LBUTTONDOWN:
g_platform_data.m_handler->onMouseButtonDown(SystemEventHandler::MouseButton::LEFT);
break;
case WM_RBUTTONDOWN:
g_platform_data.m_handler->onMouseButtonDown(SystemEventHandler::MouseButton::RIGHT);
break;
case WM_RBUTTONUP:
g_platform_data.m_handler->onMouseButtonUp(SystemEventHandler::MouseButton::RIGHT);
break;
case WM_MOUSEWHEEL:
g_platform_data.m_handler->onMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
break;
case WM_INPUT: handleRawInput(lParam); break;
case WM_MOUSEMOVE:
{
if (!g_platform_data.m_is_mouse_tracked) trackMouse();
}
break;
case WM_ERASEBKGND: return 1;
case WM_MOVE:
case WM_SIZE:
{
RECT rect;
GetClientRect(g_platform_data.m_hwnd, &rect);
g_platform_data.m_handler->onWindowTransformed(
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
}
break;
case WM_CLOSE: PostQuitMessage(0); break;
case WM_MOUSELEAVE:
{
g_platform_data.m_is_mouse_tracked = false;
g_platform_data.m_handler->onMouseLeftWindow();
}
break;
case WM_KEYUP:
case WM_SYSKEYUP: g_platform_data.m_handler->onKeyUp(getKeyFromSystem(wParam)); break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN: g_platform_data.m_handler->onKeyDown(getKeyFromSystem(wParam)); break;
case WM_CHAR: g_platform_data.m_handler->onChar(getKeyFromSystem(wParam)); break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
void getKeyName(int key, char* out, int max_size)
{
int virtualKey = getSystemKey(key);
unsigned int scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);
// because MapVirtualKey strips the extended bit for some keys
switch (virtualKey)
{
case VK_LEFT:
case VK_UP:
case VK_RIGHT:
case VK_DOWN: // arrow keys
case VK_PRIOR:
case VK_NEXT: // page up and page down
case VK_END:
case VK_HOME:
case VK_INSERT:
case VK_DELETE:
case VK_DIVIDE: // numpad slash
case VK_NUMLOCK:
{
scanCode |= 0x100; // set extended bit
break;
}
}
GetKeyNameText(scanCode << 16, out, max_size);
}
bool processSystemEvents()
{
bool want_quit = false;
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
{
want_quit = true;
}
}
return !want_quit;
}
void createWindow(SystemEventHandler* handler)
{
g_platform_data.m_handler = handler;
HINSTANCE hInst = GetModuleHandle(NULL);
WNDCLASSEX wnd;
memset(&wnd, 0, sizeof(wnd));
wnd.cbSize = sizeof(wnd);
wnd.style = CS_HREDRAW | CS_VREDRAW;
wnd.lpfnWndProc = msgProc;
wnd.hInstance = hInst;
wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
wnd.lpszClassName = "lmxa";
wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
auto x = RegisterClassExA(&wnd);
g_platform_data.m_hwnd = CreateWindowA(
"lmxa", "lmxa", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 800, 600, NULL, NULL, hInst, 0);
SetWindowTextA(g_platform_data.m_hwnd, "Lumix Studio");
RAWINPUTDEVICE Rid;
Rid.usUsagePage = 0x01;
Rid.usUsage = 0x02;
Rid.dwFlags = 0;
Rid.hwndTarget = 0;
RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
timeBeginPeriod(1);
trackMouse();
Lumix::Renderer::setInitData(g_platform_data.m_hwnd);
ImGui::GetIO().ImeWindowHandle = g_platform_data.m_hwnd;
}
void setWindowTitle(const char* title)
{
SetWindowTextA(g_platform_data.m_hwnd, title);
}
bool isPressed(int key)
{
return (GetKeyState(getSystemKey(key)) & 0x8000) != 0;
}
void setCursor(Cursor cursor)
{
switch (cursor)
{
case Cursor::NONE:
SetCursor(NULL);
break;
default:
SetCursor(LoadCursor(NULL, IDC_ARROW));
break;
}
}
} // namespace PlatformInterface
INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
{
int studioMain();
return studioMain();
}

View file

@ -0,0 +1,74 @@
#pragma once
namespace PlatformInterface
{
enum class Keys
{
CONTROL,
ALT,
SHIFT,
TAB,
LEFT,
RIGHT,
UP,
DOWN,
PAGE_UP,
PAGE_DOWN,
HOME,
END,
DEL,
BACKSPACE,
ENTER,
ESCAPE
};
enum class Cursor
{
NONE,
DEFAULT
};
struct SystemEventHandler
{
enum class MouseButton
{
LEFT,
RIGHT
};
virtual void onWindowTransformed(int x, int y, int w, int h) = 0;
virtual void onMouseLeftWindow() = 0;
virtual void onMouseMove(int x, int y, int rel_x, int rel_y) = 0;
virtual void onMouseWheel(int amount) = 0;
virtual void onMouseButtonDown(MouseButton button) = 0;
virtual void onMouseButtonUp(MouseButton button) = 0;
virtual void onKeyDown(int key) = 0;
virtual void onKeyUp(int key) = 0;
virtual void onChar(int key) = 0;
};
bool processSystemEvents();
bool isForegroundWindow();
void clipCursor(float min_x, float min_y, float max_x, float max_y);
void showCursor(bool show);
void unclipCursor();
int getWindowX();
int getWindowY();
int getWindowWidth();
int getWindowHeight();
void createWindow(SystemEventHandler* handler);
void setWindowTitle(const char* title);
bool isMaximized();
void maximizeWindow();
void moveWindow(int x, int y, int w, int h);
void getCurrentDirectory(char* buffer, int buffer_size);
void shutdown();
bool isPressed(int key);
void getKeyName(int key, char* out, int max_size);
void setCursor(Cursor cursor);
} // namespace PlatformInterface

View file

@ -2,6 +2,7 @@
#include "core/log.h"
#include "debug/debug.h"
#include "ocornut-imgui/imgui.h"
#include "platform_interface.h"
#include "utils.h"
#include <cstdio>
#include <lua.hpp>
@ -16,7 +17,7 @@ static void shortcutInput(int& shortcut)
popup_name << (int64_t)&shortcut;
char key_string[30];
getKeyName(shortcut, key_string, 30);
PlatformInterface::getKeyName(shortcut, key_string, 30);
StringBuilder<50> button_label(key_string);
button_label << "##" << (int64_t)&shortcut;

View file

@ -6,37 +6,6 @@
#include "ocornut-imgui/imgui.h"
#include "renderer/render_scene.h"
#include "universe/universe.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
void getKeyName(int virtualKey, char* out, int max_size)
{
unsigned int scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);
// because MapVirtualKey strips the extended bit for some keys
switch (virtualKey)
{
case VK_LEFT:
case VK_UP:
case VK_RIGHT:
case VK_DOWN: // arrow keys
case VK_PRIOR:
case VK_NEXT: // page up and page down
case VK_END:
case VK_HOME:
case VK_INSERT:
case VK_DELETE:
case VK_DIVIDE: // numpad slash
case VK_NUMLOCK:
{
scanCode |= 0x100; // set extended bit
break;
}
}
GetKeyNameText(scanCode << 16, out, max_size);
}
void getEntityListDisplayName(Lumix::WorldEditor& editor,

View file

@ -165,7 +165,6 @@ namespace Lumix
}
bool ColorPicker(const char* label, float col[3]);
void getKeyName(int virtualKey, char* out, int max_size);
void getEntityListDisplayName(Lumix::WorldEditor& editor,
char* buf,
int max_size,