You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
493 lines
12 KiB
493 lines
12 KiB
/* |
|
* Window.cpp |
|
* |
|
* Copyright (c) 2014-2015 SEACAVE |
|
* |
|
* Author(s): |
|
* |
|
* cDc <cdc.seacave@gmail.com> |
|
* |
|
* |
|
* This program is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU Affero General Public License as published by |
|
* the Free Software Foundation, either version 3 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU Affero General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU Affero General Public License |
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
* |
|
* |
|
* Additional Terms: |
|
* |
|
* You are required to preserve legal notices and author attributions in |
|
* that material or in the Appropriate Legal Notices displayed by works |
|
* containing it. |
|
*/ |
|
|
|
#include "Common.h" |
|
#include "Window.h" |
|
|
|
using namespace VIEWER; |
|
|
|
|
|
// D E F I N E S /////////////////////////////////////////////////// |
|
|
|
|
|
// S T R U C T S /////////////////////////////////////////////////// |
|
|
|
Window::WindowsMap Window::g_mapWindows; |
|
|
|
Window::Window() |
|
: |
|
window(NULL), |
|
pos(Eigen::Vector2d::Zero()), |
|
prevPos(Eigen::Vector2d::Zero()) |
|
{ |
|
} |
|
Window::~Window() |
|
{ |
|
Release(); |
|
} |
|
|
|
void Window::Release() |
|
{ |
|
if (IsValid()) { |
|
#ifdef _USE_NUKLEAR |
|
nk_glfw3_shutdown(); |
|
#endif |
|
glfwDestroyWindow(window); |
|
window = NULL; |
|
} |
|
clbkOpenScene.reset(); |
|
ReleaseClbk(); |
|
} |
|
|
|
void Window::ReleaseClbk() |
|
{ |
|
clbkSaveScene.reset(); |
|
clbkExportScene.reset(); |
|
clbkCenterScene.reset(); |
|
clbkRayScene.reset(); |
|
clbkCompilePointCloud.reset(); |
|
clbkCompileMesh.reset(); |
|
clbkCompileBounds.reset(); |
|
clbkTogleSceneBox.reset(); |
|
clbkCropToBounds.reset(); |
|
} |
|
|
|
bool Window::Init(const cv::Size& _size, LPCTSTR name) |
|
{ |
|
sizeScale = 1; |
|
size = _size; |
|
|
|
glfwDefaultWindowHints(); |
|
glfwWindowHint(GLFW_VISIBLE, 0); |
|
window = glfwCreateWindow(size.width, size.height, name, NULL, NULL); |
|
if (!window) |
|
return false; |
|
glfwMakeContextCurrent(window); |
|
glfwSetFramebufferSizeCallback(window, Window::Resize); |
|
glfwSetKeyCallback(window, Window::Key); |
|
glfwSetMouseButtonCallback(window, Window::MouseButton); |
|
glfwSetCursorPosCallback(window, Window::MouseMove); |
|
glfwSetScrollCallback(window, Window::Scroll); |
|
glfwSetDropCallback(window, Window::Drop); |
|
g_mapWindows[window] = this; |
|
|
|
Reset(); |
|
return true; |
|
} |
|
void Window::SetCamera(const Camera& cam) |
|
{ |
|
camera = cam; |
|
cv::Size _size; |
|
glfwGetFramebufferSize(window, &_size.width, &_size.height); |
|
Resize(_size); |
|
} |
|
void Window::SetName(LPCTSTR name) |
|
{ |
|
glfwSetWindowTitle(window, name); |
|
} |
|
void Window::SetVisible(bool v) |
|
{ |
|
if (v) |
|
glfwShowWindow(window); |
|
else |
|
glfwHideWindow(window); |
|
} |
|
bool Window::IsVisible() const |
|
{ |
|
return glfwGetWindowAttrib(window, GLFW_VISIBLE) != 0; |
|
} |
|
void Window::Reset(SPARSE _sparseType, unsigned _minViews) |
|
{ |
|
camera.Reset(); |
|
inputType = INP_NA; |
|
sparseType = _sparseType; |
|
minViews = _minViews; |
|
pointSize = 2.f; |
|
cameraBlend = 0.5f; |
|
bRenderCameras = true; |
|
bRenderCameraTrajectory = true; |
|
bRenderImageVisibility = false; |
|
bRenderViews = true; |
|
bRenderSolid = true; |
|
bRenderTexture = true; |
|
bRenderBounds = false; |
|
selectionType = SEL_NA; |
|
selectionIdx = NO_IDX; |
|
if (clbkCompilePointCloud != NULL) |
|
clbkCompilePointCloud(); |
|
if (clbkCompileMesh != NULL) |
|
clbkCompileMesh(); |
|
glfwPostEmptyEvent(); |
|
} |
|
|
|
|
|
void Window::CenterCamera(const Point3& pos) |
|
{ |
|
camera.center = pos; |
|
camera.dist *= 0.7; |
|
} |
|
|
|
|
|
void Window::UpdateView(const ImageArr& images, const MVS::ImageArr& sceneImagesMVS) |
|
{ |
|
if (camera.IsCameraViewMode()) { |
|
// enable camera view mode and apply current camera transform |
|
const Image& image = images[camera.currentCamID]; |
|
const MVS::Camera& camera = sceneImagesMVS[image.idx].camera; |
|
UpdateView((const Matrix3x3::EMat)camera.R, camera.GetT()); |
|
} else { |
|
// apply view point transform |
|
glMatrixMode(GL_MODELVIEW); |
|
const Eigen::Matrix4d trans(camera.GetLookAt()); |
|
glLoadMatrixd((GLdouble*)trans.data()); |
|
} |
|
} |
|
|
|
void Window::UpdateView(const Eigen::Matrix3d& R, const Eigen::Vector3d& t) |
|
{ |
|
glMatrixMode(GL_MODELVIEW); |
|
transform = gs_convert * TransW2L(R, t); |
|
glLoadMatrixd((GLdouble*)transform.data()); |
|
} |
|
|
|
void Window::UpdateMousePosition(double xpos, double ypos) |
|
{ |
|
prevPos = pos; |
|
pos.x() = xpos; |
|
pos.y() = ypos; |
|
// normalize position to [-1:1] range |
|
const int w(camera.size.width); |
|
const int h(camera.size.height); |
|
pos.x() = (2.0 * pos.x() - w) / w; |
|
pos.y() = (h - 2.0 * pos.y()) / h; |
|
} |
|
|
|
|
|
void Window::GetFrame(Image8U3& image) const |
|
{ |
|
image.create(GetSize()); |
|
glReadPixels(0, 0, image.width(), image.height(), GL_BGR_EXT, GL_UNSIGNED_BYTE, image.ptr()); |
|
cv::flip(image, image, 0); |
|
} |
|
|
|
|
|
cv::Size Window::GetSize() const |
|
{ |
|
cv::Size _size; |
|
glfwGetWindowSize(window, &_size.width, &_size.height); |
|
return _size; |
|
} |
|
void Window::Resize(const cv::Size& _size) |
|
{ |
|
// detect scaled window |
|
sizeScale = (double)GetSize().width/_size.width; |
|
size = _size; |
|
// update resolution |
|
glfwMakeContextCurrent(window); |
|
glViewport(0, 0, size.width, size.height); |
|
camera.Resize(cv::Size(ROUND2INT(size.width*sizeScale), ROUND2INT(size.height*sizeScale))); |
|
} |
|
void Window::Resize(GLFWwindow* window, int width, int height) |
|
{ |
|
g_mapWindows[window]->Resize(cv::Size(width, height)); |
|
} |
|
|
|
void Window::Key(int k, int /*scancode*/, int action, int mod) |
|
{ |
|
switch (k) { |
|
case GLFW_KEY_ESCAPE: |
|
if (action == GLFW_RELEASE) |
|
glfwSetWindowShouldClose(window, 1); |
|
break; |
|
case GLFW_KEY_DOWN: |
|
if (action == GLFW_RELEASE) { |
|
if (mod & GLFW_MOD_SHIFT) { |
|
if (minViews > 2) { |
|
minViews--; |
|
if (clbkCompilePointCloud != NULL) |
|
clbkCompilePointCloud(); |
|
} |
|
} else { |
|
pointSize = MAXF(pointSize-0.5f, 0.5f); |
|
} |
|
} |
|
break; |
|
case GLFW_KEY_UP: |
|
if (action == GLFW_RELEASE) { |
|
if (mod & GLFW_MOD_SHIFT) { |
|
minViews++; |
|
if (clbkCompilePointCloud != NULL) |
|
clbkCompilePointCloud(); |
|
} else { |
|
pointSize += 0.5f; |
|
} |
|
} |
|
break; |
|
case GLFW_KEY_LEFT: |
|
if (action != GLFW_RELEASE) { |
|
camera.prevCamID = camera.currentCamID; |
|
camera.currentCamID--; |
|
if (camera.currentCamID < NO_ID && camera.currentCamID >= camera.maxCamID) |
|
camera.currentCamID = camera.maxCamID-1; |
|
} |
|
break; |
|
case GLFW_KEY_RIGHT: |
|
if (action != GLFW_RELEASE) { |
|
camera.prevCamID = camera.currentCamID; |
|
camera.currentCamID++; |
|
if (camera.currentCamID >= camera.maxCamID) |
|
camera.currentCamID = NO_ID; |
|
} |
|
break; |
|
case GLFW_KEY_B: |
|
if (action == GLFW_RELEASE) { |
|
if (mod & GLFW_MOD_CONTROL) { |
|
if (clbkCropToBounds != NULL) |
|
clbkCropToBounds(); |
|
} else if (mod & GLFW_MOD_SHIFT) { |
|
if (clbkTogleSceneBox != NULL) |
|
clbkTogleSceneBox(); |
|
} else { |
|
if (clbkCompileBounds != NULL) |
|
clbkCompileBounds(); |
|
} |
|
} |
|
break; |
|
case GLFW_KEY_C: |
|
if (action == GLFW_RELEASE) { |
|
if (mod & GLFW_MOD_SHIFT) { |
|
bRenderCameraTrajectory = !bRenderCameraTrajectory; |
|
} else if (mod & GLFW_MOD_CONTROL) { |
|
if (clbkCenterScene != NULL) |
|
clbkCenterScene(); |
|
} else { |
|
bRenderCameras = !bRenderCameras; |
|
} |
|
} |
|
break; |
|
case GLFW_KEY_E: |
|
if (action == GLFW_RELEASE && clbkExportScene != NULL) |
|
clbkExportScene(NULL, NULL); |
|
break; |
|
case GLFW_KEY_P: |
|
switch (sparseType) { |
|
case SPR_POINTS: sparseType = SPR_LINES; break; |
|
case SPR_LINES: sparseType = SPR_ALL; break; |
|
case SPR_ALL: sparseType = SPR_POINTS; break; |
|
} |
|
if (clbkCompilePointCloud != NULL) |
|
clbkCompilePointCloud(); |
|
break; |
|
case GLFW_KEY_R: |
|
if (action == GLFW_RELEASE) |
|
Reset(); |
|
break; |
|
case GLFW_KEY_S: |
|
if (action == GLFW_RELEASE) { |
|
if (clbkSaveScene != NULL) |
|
clbkSaveScene(NULL, (mod & GLFW_MOD_SHIFT) != 0); |
|
} |
|
break; |
|
case GLFW_KEY_T: |
|
if (action == GLFW_RELEASE) { |
|
bRenderTexture = !bRenderTexture; |
|
if (clbkCompileMesh != NULL) |
|
clbkCompileMesh(); |
|
} |
|
break; |
|
case GLFW_KEY_V: |
|
if (action == GLFW_RELEASE) { |
|
if (mod & GLFW_MOD_SHIFT) { |
|
bRenderImageVisibility = !bRenderImageVisibility; |
|
} else { |
|
bRenderViews = !bRenderViews; |
|
} |
|
} |
|
break; |
|
case GLFW_KEY_W: |
|
if (action == GLFW_RELEASE) { |
|
if (bRenderSolid) { |
|
bRenderSolid = false; |
|
glPolygonMode(GL_FRONT, GL_LINE); |
|
} else { |
|
bRenderSolid = true; |
|
glPolygonMode(GL_FRONT, GL_FILL); |
|
} |
|
} |
|
break; |
|
case GLFW_KEY_KP_SUBTRACT: |
|
if (action == GLFW_RELEASE) { |
|
if (mod & GLFW_MOD_CONTROL) |
|
camera.SetFOV(camera.fov-5.f); |
|
else if (mod & GLFW_MOD_SHIFT) |
|
camera.scaleF *= 0.9f; |
|
else |
|
cameraBlend = MAXF(cameraBlend-0.1f, 0.f); |
|
} |
|
break; |
|
case GLFW_KEY_KP_ADD: |
|
if (action == GLFW_RELEASE) { |
|
if (mod & GLFW_MOD_CONTROL) |
|
camera.SetFOV(camera.fov+5.f); |
|
else if (mod & GLFW_MOD_SHIFT) |
|
camera.scaleF *= 1.1111f; |
|
else |
|
cameraBlend = MINF(cameraBlend+0.1f, 1.f); |
|
} |
|
break; |
|
} |
|
} |
|
void Window::Key(GLFWwindow* window, int k, int scancode, int action, int mod) |
|
{ |
|
g_mapWindows[window]->Key(k, scancode, action, mod); |
|
} |
|
|
|
void Window::MouseButton(int button, int action, int /*mods*/) |
|
{ |
|
switch (button) { |
|
case GLFW_MOUSE_BUTTON_LEFT: { |
|
if (action == GLFW_PRESS) { |
|
inputType.set(INP_MOUSE_LEFT); |
|
} else |
|
if (action == GLFW_RELEASE) { |
|
inputType.unset(INP_MOUSE_LEFT); |
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); |
|
} |
|
if (clbkRayScene != NULL) { |
|
typedef Eigen::Matrix<double,4,4,Eigen::ColMajor> Mat4; |
|
Mat4 P, V; |
|
glGetDoublev(GL_MODELVIEW_MATRIX, V.data()); |
|
glGetDoublev(GL_PROJECTION_MATRIX, P.data()); |
|
// 4d Homogeneous Clip Coordinates |
|
const Eigen::Vector4d ray_clip(pos.x(), pos.y(), -1.0, 1.0); |
|
// 4d Eye (Camera) Coordinates |
|
Eigen::Vector4d ray_eye(P.inverse()*ray_clip); |
|
ray_eye.z() = -1.0; |
|
ray_eye.w() = 0.0; |
|
// 4d World Coordinates |
|
const Mat4 invV(V.inverse()); |
|
ASSERT(ISEQUAL(invV(3,3),1.0)); |
|
const Eigen::Vector3d start(invV.topRightCorner<3,1>()); |
|
const Eigen::Vector4d ray_wor(invV*ray_eye); |
|
const Eigen::Vector3d dir(ray_wor.topRows<3>().normalized()); |
|
clbkRayScene(Ray3d(start, dir), action); |
|
} |
|
} break; |
|
case GLFW_MOUSE_BUTTON_MIDDLE: { |
|
if (action == GLFW_PRESS) { |
|
inputType.set(INP_MOUSE_MIDDLE); |
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); |
|
} else |
|
if (action == GLFW_RELEASE) { |
|
inputType.unset(INP_MOUSE_MIDDLE); |
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); |
|
} |
|
} break; |
|
case GLFW_MOUSE_BUTTON_RIGHT: { |
|
if (action == GLFW_PRESS) { |
|
inputType.set(INP_MOUSE_RIGHT); |
|
} else |
|
if (action == GLFW_RELEASE) { |
|
inputType.unset(INP_MOUSE_RIGHT); |
|
} |
|
} |
|
} |
|
} |
|
void Window::MouseButton(GLFWwindow* window, int button, int action, int mods) |
|
{ |
|
g_mapWindows[window]->MouseButton(button, action, mods); |
|
} |
|
|
|
void Window::MouseMove(double xpos, double ypos) |
|
{ |
|
UpdateMousePosition(xpos, ypos); |
|
if (inputType.isSet(INP_MOUSE_LEFT)) { |
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); |
|
camera.Rotate(pos, prevPos); |
|
} else |
|
if (inputType.isSet(INP_MOUSE_MIDDLE)) { |
|
camera.Translate(pos, prevPos); |
|
} |
|
} |
|
void Window::MouseMove(GLFWwindow* window, double xpos, double ypos) |
|
{ |
|
g_mapWindows[window]->MouseMove(xpos, ypos); |
|
} |
|
|
|
void Window::Scroll(double /*xoffset*/, double yoffset) |
|
{ |
|
camera.dist *= (yoffset>0 ? POW(1.11,yoffset) : POW(0.9,-yoffset)); |
|
} |
|
void Window::Scroll(GLFWwindow* window, double xoffset, double yoffset) |
|
{ |
|
g_mapWindows[window]->Scroll(xoffset, yoffset); |
|
} |
|
|
|
void Window::Drop(int count, const char** paths) |
|
{ |
|
if (clbkOpenScene && count > 0) { |
|
SetVisible(false); |
|
String fileName(paths[0]); |
|
Util::ensureUnifySlash(fileName); |
|
if (count > 1) { |
|
String geometryFileName(paths[1]); |
|
Util::ensureUnifySlash(geometryFileName); |
|
clbkOpenScene(fileName, geometryFileName); |
|
} else { |
|
clbkOpenScene(fileName, NULL); |
|
} |
|
SetVisible(true); |
|
} |
|
} |
|
void Window::Drop(GLFWwindow* window, int count, const char** paths) |
|
{ |
|
g_mapWindows[window]->Drop(count, paths); |
|
} |
|
|
|
bool Window::IsShiftKeyPressed() const |
|
{ |
|
return |
|
glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || |
|
glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS; |
|
} |
|
bool Window::IsCtrlKeyPressed() const |
|
{ |
|
return |
|
glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || |
|
glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS; |
|
} |
|
bool Window::IsAltKeyPressed() const |
|
{ |
|
return |
|
glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || |
|
glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS; |
|
} |
|
/*----------------------------------------------------------------*/
|
|
|