Files
2022-04-05 11:42:28 +03:00

183 lines
5.4 KiB
C++

#pragma once
#include <pangolin/handler/handler.h>
#include <pangolin/scene/renderable.h>
#include <pangolin/scene/interactive_index.h>
namespace pangolin {
inline void gluPickMatrix(
GLdouble x, GLdouble y,
GLdouble width, GLdouble height,
GLint viewport[4]
) {
GLfloat m[16];
GLfloat sx, sy;
GLfloat tx, ty;
sx = viewport[2] / (GLfloat)width;
sy = viewport[3] / (GLfloat)height;
tx = (viewport[2] + 2.0f * (viewport[0] - (GLfloat)x)) / (GLfloat)width;
ty = (viewport[3] + 2.0f * (viewport[1] - (GLfloat)y)) / (GLfloat)height;
#define M(row, col) m[col*4+row]
M(0, 0) = sx;
M(0, 1) = 0.0f;
M(0, 2) = 0.0f;
M(0, 3) = tx;
M(1, 0) = 0.0f;
M(1, 1) = sy;
M(1, 2) = 0.0f;
M(1, 3) = ty;
M(2, 0) = 0.0f;
M(2, 1) = 0.0f;
M(2, 2) = 1.0f;
M(2, 3) = 0.0f;
M(3, 0) = 0.0f;
M(3, 1) = 0.0f;
M(3, 2) = 0.0f;
M(3, 3) = 1.0f;
#undef M
glMultMatrixf(m);
}
struct SceneHandler : public Handler3D
{
SceneHandler(
Renderable& scene,
OpenGlRenderState& cam_state
) : Handler3D(cam_state), scene(scene)
{
}
void ProcessHitBuffer(GLint hits, GLuint* buf, std::map<GLuint, Interactive*>& hit_map )
{
GLuint* closestNames = 0;
GLuint closestNumNames = 0;
GLuint closestZ = std::numeric_limits<GLuint>::max();
for (int i = 0; i < hits; i++) {
if (buf[1] < closestZ) {
closestNames = buf + 3;
closestNumNames = buf[0];
closestZ = buf[1];
}
buf += buf[0] + 3;
}
for (unsigned int i = 0; i < closestNumNames; i++) {
const int pickId = closestNames[i];
hit_map[pickId] = InteractiveIndex::I().Find(pickId);
}
}
void ComputeHits(pangolin::View& view,
const pangolin::OpenGlRenderState& cam_state,
int x, int y, int grab_width,
std::map<GLuint, Interactive*>& hit_objects )
{
// Get views viewport / modelview /projection
GLint viewport[4] = {view.v.l, view.v.b, view.v.w, view.v.h};
pangolin::OpenGlMatrix mv = cam_state.GetModelViewMatrix();
pangolin::OpenGlMatrix proj = cam_state.GetProjectionMatrix();
// Prepare hit buffer object
const unsigned int MAX_SEL_SIZE = 64;
GLuint vSelectBuf[MAX_SEL_SIZE];
glSelectBuffer(MAX_SEL_SIZE, vSelectBuf);
// Load and adjust modelview projection matrices
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPickMatrix(x, y, grab_width, grab_width, viewport);
proj.Multiply();
glMatrixMode(GL_MODELVIEW);
mv.Load();
// Render scenegraph in 'select' mode
glRenderMode(GL_SELECT);
glInitNames();
RenderParams select;
select.render_mode = GL_SELECT;
scene.Render(select);
glFlush();
GLint nHits = glRenderMode(GL_RENDER);
// std::cout << " -- Number of Hits are: " << nHits << std::endl;
// std::cout << " -- size of hitobjects: " << hit_objects.size() << std::endl;
if (nHits > 0) {
ProcessHitBuffer(nHits, vSelectBuf, hit_objects);
}
}
void Mouse(pangolin::View& view, pangolin::MouseButton button,
int x, int y, bool pressed, int button_state)
{
GetPosNormal(view, x, y, p, Pw, Pc, n);
bool handled = false;
if (pressed) {
m_selected_objects.clear();
ComputeHits(view, *cam_state, x, y, 2*hwin+1, m_selected_objects);
}
for (auto kv : m_selected_objects)
{
Interactive* ir = dynamic_cast<Interactive*>(kv.second);
handled |= ir && ir->Mouse( button, p, Pw, n, pressed, button_state, kv.first);
}
if (!handled) {
Handler3D::Mouse(view, button, x, y, pressed, button_state);
}
}
void MouseMotion(pangolin::View& view, int x, int y, int button_state)
{
GetPosNormal(view, x, y, p, Pw, Pc, n);
bool handled = false;
for (auto kv : m_selected_objects)
{
Interactive* ir = dynamic_cast<Interactive*>(kv.second);
handled |= ir && ir->MouseMotion( p, Pw, n, button_state, kv.first);
}
if (!handled) {
pangolin::Handler3D::MouseMotion(view, x, y, button_state);
}
}
void Special(pangolin::View& view, pangolin::InputSpecial inType,
float x, float y, float p1, float p2, float p3, float p4,
int button_state)
{
GetPosNormal(view, (int)x, (int)y, p, Pw, Pc, n);
bool handled = false;
if (inType == pangolin::InputSpecialScroll)
{
m_selected_objects.clear();
ComputeHits(view, *cam_state, (int)x, (int)y, 2*hwin+1, m_selected_objects);
const MouseButton button = p2 > 0 ? MouseWheelUp : MouseWheelDown;
for (auto kv : m_selected_objects)
{
Interactive* ir = dynamic_cast<Interactive*>(kv.second);
handled |= ir && ir->Mouse( button, p, Pw, n, true, button_state, kv.first);
}
}
if (!handled) {
pangolin::Handler3D::Special(view, inType, x, y,
p1, p2, p3, p4, button_state);
}
}
std::map<GLuint, Interactive*> m_selected_objects;
Renderable& scene;
unsigned int grab_width;
};
}