From 7e2ee081aca1235e7649170164ea6458cc5fcc38 Mon Sep 17 00:00:00 2001 From: ponchio Date: Thu, 25 Mar 2004 14:50:08 +0000 Subject: [PATCH] first release --- wrap/gui/frustum.h | 94 +++++++++++++++++ wrap/gui/trackball.cpp | 224 +++++++++++++++++++++++++++++++++++++++++ wrap/gui/trackball.h | 121 ++++++++++++++++++++++ wrap/gui/trackmode.cpp | 72 +++++++++++++ wrap/gui/trackmode.h | 54 ++++++++++ wrap/gui/view.h | 108 ++++++++++++++++++++ 6 files changed, 673 insertions(+) create mode 100644 wrap/gui/frustum.h create mode 100644 wrap/gui/trackball.cpp create mode 100644 wrap/gui/trackball.h create mode 100644 wrap/gui/trackmode.cpp create mode 100644 wrap/gui/trackmode.h create mode 100644 wrap/gui/view.h diff --git a/wrap/gui/frustum.h b/wrap/gui/frustum.h new file mode 100644 index 00000000..4741f9db --- /dev/null +++ b/wrap/gui/frustum.h @@ -0,0 +1,94 @@ +#ifndef FRUSTUM_H +#define FRUSTUM_H + +#include +#include +#include + + +namespace vcg { + + template class Frustum: public Camera { +public: + void GetView(); + bool IsOutside(Point3 &point); + bool IsOutside(Point3 &point, T radius); + T Distance(Point3 &point, int plane); + Point3 ViewPoint(); + +protected: + T resolution; + Plane3 planes[6]; + Point3 view_point; +}; + + +//Implementation +template Point3 Frustum::ViewPoint() { + return view_point; +} + +template bool Frustum::IsOutside(Point3 &point) { + Point3 r = Project(point); + if(r[0] < viewport[0] || r[0] > viewport[0]+viewport[2] || + r[1] < viewport[1] || r[1] > viewport[1]+viewport[3]) + return true; + return false; +} + +template bool Frustum::IsOutside(Point3 &point, T radius) { + for(int i = 0; i < 4; i++) { + T dist = Distance(point, i); + if(dist < -radius) + return true; + } + return false; +} + +template T Frustum::Distance(Point3 &point, int plane) { + return Distance(point, planes[plane]); +} + +template void Frustum::GetView() { + Camera::GetView(); + + Point3d NE, SE, SW, NW, ne, se, sw, nw; + int t = viewport[1] + viewport[3]; + int b = viewport[1]; + int r = viewport[0] + viewport[2]; + int l = viewport[0]; + + Point3d NE, SE, SW, NW, ne, se, sw, nw; + gluUnProject(l, b, 0, model_matrix, proj_matrix, viewport, &nw[0], &nw[1], &nw[2]); + gluUnProject(l, t, 0, model_matrix, proj_matrix, viewport, &sw[0], &sw[1], &sw[2]); + gluUnProject(r, b, 0, model_matrix, proj_matrix, viewport, &ne[0], &ne[1], &ne[2]); + gluUnProject(r, t, 0, model_matrix, proj_matrix, viewport, &se[0], &se[1], &se[2]); + gluUnProject(l, b, 1, model_matrix, proj_matrix, viewport, &NW[0], &NW[1], &NW[2]); + gluUnProject(l, t, 1, model_matrix, proj_matrix, viewport, &SW[0], &SW[1], &SW[2]); + gluUnProject(r, b, 1, model_matrix, proj_matrix, viewport, &NE[0], &NE[1], &NE[2]); + gluUnProject(r, t, 1, model_matrix, proj_matrix, viewport, &SE[0], &SE[1], &SE[2]); + + view_point = Camera::ViewPoint(); + + planes[0].init(view_point, Point3().Import(nw), Point3().Import(ne)); + planes[1].init(view_point, Point3().Import(ne), Point3().Import(se)); + planes[2].init(view_point, Point3().Import(se), Point3().Import(sw)); + planes[3].init(view_point, Point3().Import(sw), Point3().Import(nw)); + planes[4].init(Point3().Import(se), Point3().Import(sw), Point3().Import(nw)); + planes[5].init(Point3().Import(SW), Point3().Import(SE), Point3().Import(NE)); + + for(int i = 0; i < 6; i++) + planes[i].Normalize(); + + //calcoliamo la risoluzione: dimenzione di un pixel a distanza 1 dal view_point + resolution = (T)((ne + NE) - (nw + NW)).Norm() /( viewport[2] * ((ne + NE) - (nw + NW)).Norm()); +} + +}//namespace + +#endif + + + + + diff --git a/wrap/gui/trackball.cpp b/wrap/gui/trackball.cpp new file mode 100644 index 00000000..0c7d7896 --- /dev/null +++ b/wrap/gui/trackball.cpp @@ -0,0 +1,224 @@ +#include "trackball.h" +#include +using namespace vcg; + +#include //debug! +using namespace std; + +Transform::Transform() { + local.SetIdentity(); + track.SetIdentity(); +} + +Trackball::Trackball(): current_button(0), last_x(-1), last_y(-1), dragging(false), + spinnable(true), spinning(false), history_size(10) { + //qui si aggiungono tutte le actions + actions[0] = Action(LOCAL, NONE); + actions[BUTTON_LEFT] = Action(VIEW, ROTATE); + actions[BUTTON_LEFT | KEY_CTRL] = Action(VIEW, DRAG_XY); + actions[BUTTON_LEFT | KEY_SHIFT] = Action(VIEW, SCALE); + actions[WHEEL] = Action(SCREEN, SCALE); + current_action = Action(LOCAL, NONE); +} + +void Trackball::SetIdentity() { + local.SetIdentity(); + Reset(); +} +void Trackball::SetPosition(const Similarityf &m, int millisec) { + local = m; + //millisec ignored at the moment. +} + +//operating +void Trackball::GetView() { + camera.GetView(); + + //lets get view matrix + Similarityf m = local * last_track; + Point3f c_obj = Point3f(0, 0, 0) * m; //coordinate of the center of the trackball in obj coords + Point3f c_view = camera.Project(c_obj); //center of the trackball in screen coords. + Point3f X, Y, Z, C; + X = camera.UnProject(Point3f(c_view[0] + 100, c_view[1], c_view[2])); + Y = camera.UnProject(Point3f(c_view[0], c_view[1] - 100, c_view[2])); + Z = camera.UnProject(Point3f(c_view[0], c_view[1], c_view[2] + 0.1)); + C = c_obj; + X = X - C; X.Normalize(); + Y = Y - C; Y.Normalize(); + Z = X ^ Y; + + Matrix44f view_axis; //this is before applying last (or track...) + view_axis.SetIdentity(); + view_axis.element(0, 0) = X[0]; view_axis.element(0, 1) = X[1]; view_axis.element(0, 2) = X[2]; + view_axis.element(1, 0) = Y[0]; view_axis.element(1, 1) = Y[1]; view_axis.element(1, 2) = Y[2]; + view_axis.element(2, 0) = Z[0]; view_axis.element(2, 1) = Z[1]; view_axis.element(2, 2) = Z[2]; + view.SetIdentity(); + view.FromMatrix(view_axis); + //view = view * Inverse(Similarityf(track.rot)); + //spinning ignored +} +void Trackball::Apply() { + glMultMatrix(track.Matrix()); +} + +void Trackball::Draw() { + glPushMatrix(); + glMultMatrix(local.Matrix()); + //Disegnamo un cubo: + glColor3f(1, 0, 0); + glScalef(0.5, 0.5, 0.5); + glBegin(GL_LINE_STRIP); + glVertex3f(-1, -1, -1); + glVertex3f( 1, -1, -1); + glVertex3f( 1, 1, -1); + glVertex3f(-1, 1, -1); + glVertex3f(-1, 1, 1); + glVertex3f( 1, 1, 1); + glVertex3f( 1, -1, 1); + glVertex3f(-1, -1, 1); + glVertex3f(-1, -1, 1); + glEnd(); + glPopMatrix(); +} + +void Trackball::Reset() { + track.SetIdentity(); +} + +//interface +void Trackball::MouseDown(int x, int y, Trackball::Button button) { + current_button |= button; + SetCurrentAction(); + last_x = x; + last_y = y; +} + +void Trackball::MouseMove(int x, int y) { + if(current_action.motion == NONE) return; + if(last_x == -1 && last_y == -1) { //changed mode in the middle of moving + last_x = x; + last_y = y; + return; + } + + Point3f origin = camera.ViewportToScreen(ScreenOrigin()); + Point3f new_point = camera.ViewportToScreen(Point3f(x, y, 0)) - origin; + Point3f old_point = camera.ViewportToScreen(Point3f(last_x, last_y, 0)) - origin; + new_point *= 2; + old_point *= 2; + + Similarityf u; + TrackMode *mode = CurrentMode(); + Similarityf new_track = mode->Apply(new_point, u); + Similarityf old_track = mode->Apply(old_point, u); + delete mode; + + Invert(old_track); + new_track = old_track * new_track; + + Similarityf diff; + switch(current_action.system) { + case VIEW: + u = last_view * Similarityf((-local.tra) * Similarityf(last_track.rot)) * Similarityf(-last_track.tra); + diff = Inverse(u) * new_track * u; + break; + default: break; + } + + track = diff * last_track; + +} + +void Trackball::MouseUp(int x, int y, Trackball::Button button) { + current_button &= (~button); + SetCurrentAction(); +} + +void Trackball::MouseWheel(Trackball::Button notch) { +} + +void Trackball::ButtonDown(Trackball::Button button) { + current_button |= button; + SetCurrentAction(); +} + +void Trackball::ButtonUp(Trackball::Button button) { + current_button &= (~button); + SetCurrentAction(); +} + + + +//spinning interface +void Trackball::SetSpinnable(bool on){} +bool Trackball::IsSpinnable() { + return spinnable; +} +void Trackball::SetSpinning(Quaternionf &spin){} +void Trackball::StopSpinning(){} +bool Trackball::IsSpinning() { + return spinning; +} + +//interfaccia navigation: +void Trackball::Back(){} +void Trackball::Forward(){} +void Trackball::Home(){} +void Trackball::HistorySize(int lenght){} + +void Trackball::SetCurrentAction() { + //I use strict matching. + assert(actions.count(0)); + if(!actions.count(current_button)) + current_action = actions[0]; + else + current_action = actions[current_button]; + + last_x = -1; + last_y = -1; + last_track = track; + last_view = view; +} + +TrackMode *Trackball::CurrentMode() { + Point3f x(1, 0, 0), y(0, 1, 0), z(0, 0, 1); + TrackMode *mode = NULL; + switch(current_action.motion) { + case NONE: mode = new TrackMode(); break; + case ROTATE: mode = new SphereMode(); break; + case ROTATE_DUMMY: mode = new GravityMode(); break; + case ROTATE_X: mode = new CylinderMode(x); break; + case ROTATE_Y: mode = new CylinderMode(y); break; + case ROTATE_Z: mode = new CylinderMode(z); break; + case DRAG_X: mode = new LineMode(x); break; + case DRAG_Y: mode = new LineMode(y); break; + case DRAG_Z: mode = new LineMode(z); break; + case DRAG_XY: mode = new PlaneMode(x, y); break; + case DRAG_YZ: mode = new PlaneMode(y, z); break; + case DRAG_XZ: mode = new PlaneMode(z, x); break; + case SCALE: mode = new ScaleMode(); break; + default: break; + } + return mode; +} +//return center of trackball in Screen coordinates. +Point3f Trackball::ScreenOrigin() { + return camera.Project(ModelOrigin()); +} + +//return center of trackball in Model coordinates +Point3f Trackball::ModelOrigin() { + Similarityf m = local * last_track; + return Point3f(0, 0, 0) * m; +} + +Matrix44f Trackball::ScreenToModel() { + return camera.inverse; +} + +Similarityf Trackball::ModelToLocal() { + Similarityf m = local * last_track; + return m; +} + + diff --git a/wrap/gui/trackball.h b/wrap/gui/trackball.h new file mode 100644 index 00000000..7268ac4c --- /dev/null +++ b/wrap/gui/trackball.h @@ -0,0 +1,121 @@ +#ifndef TRACKBALL_H +#define TRACKBALL_H + +#include +#include +#include +#include +#include + +namespace vcg { + +class Transform { +public: + Transform(); + Similarityf track; + Similarityf local; +}; + +Transform interpolate(const Transform &a, const Transform &b, float t); + +class Trackball: public Transform { +public: + enum Button { BUTTON_LEFT = 1, BUTTON_MIDDLE = 2, BUTTON_RIGHT = 4, WHEEL = 8, + KEY_SHIFT = 16, KEY_CTRL = 32, KEY_ALT = 64, HANDLE = 128 }; + + Trackball(); + void SetIdentity(); + void SetPosition(const Similarityf &local, int millisec = 0); + void SetTransform(const Transform &transform, int miilisec = 0); + + //operating + void GetView(); + void Apply(); + void Draw(); + void Reset(); + + //interface + void MouseDown(int x, int y, Button button); + void MouseMove(int x, int y); + void MouseUp(int x, int y, Button button); + void MouseWheel(Button notch); + void ButtonUp(Button button); + void ButtonDown(Button button); + + //default sensitivity 1 + void SetSensitivity(float s); + + //spinning interface + void SetSpinnable(bool on); + bool IsSpinnable(); + void SetSpinning(Quaternionf &spin); + void StopSpinning(); + bool IsSpinning(); + + //interfaccia navigation: + void Back(); + void Forward(); + void Home(); + void Store(); + void HistorySize(int lenght); + + //internals + + enum System { LOCAL, VIEW, SCREEN }; + + enum Motion { NONE = 0, ROTATE = 1, ROTATE_DUMMY = 2, //really makes sense only in VIEW system + ROTATE_X = 3, ROTATE_Y = 4, ROTATE_Z = 5, // Axis Constrained Rotation + DRAG_X = 6, DRAG_Y = 7, DRAG_Z = 8, // Drag constrained to an axis (trackball axis) + DRAG_XY = 9, DRAG_YZ = 10, DRAG_XZ = 11, // Drag constrained to a plane + SCALE = 12 //scale respect to center of trackball + }; + + + + struct Action { + System system; + Motion motion; + Action() {} + Action(System s, Motion m): system(s), motion(m) {} + }; + ///Find the current action ussing the current button + void SetCurrentAction(); + +protected: + View camera; + Similarityf view; //Rotate LOCAL coordinate into VIEW coordinates + + int current_button; + Action current_action; + + TrackMode *CurrentMode(); + std::map actions; + + Similarityf last_track; + Similarityf last_view; + int last_x, last_y; + bool dragging; + int button_mask; + + Quaternionf spin; + bool spinnable; + bool spinning; + + std::list history; + int history_size; + + + Point3f ScreenOrigin(); //center of trackball in Screen coord + Point3f ModelOrigin(); //center of trackball in Model coord + + Matrix44f ScreenToModel(); //forse non serve..... + Similarityf ModelToLocal(); + + //Point3f ScreenToLocal(const Point3f &p); + //Point3f LocalToScreen(const Point3f &p); +}; + + +}//namespace + +#endif \ No newline at end of file diff --git a/wrap/gui/trackmode.cpp b/wrap/gui/trackmode.cpp new file mode 100644 index 00000000..afdb13a4 --- /dev/null +++ b/wrap/gui/trackmode.cpp @@ -0,0 +1,72 @@ +#include "trackmode.h" +#include +#include + +using namespace vcg; + +Similarityf SphereMode::Apply(const Point3f &p, const Similarityf &m) { + float u = p[0]; + float w = p[1]; + float thr = 1/math::Sqrt(2.0f); //in the plane x-y distance from origin, above this use hyperboloid + + float dist = math::Sqrt(u * u + w * w); + Point3f result; + if(dist < thr) { // First case: The ray is nearer to the sphere than r/sqrt(2) + float z = math::Sqrt(1 - u * u - w* w); + result = Point3f(u, w, z); + } else { // Second case: The ray should hit the 1/d hyperboloid + float a = thr; + result = Point3f(u, w, -a*(u*u + w * w) + 3*a/2); + result.Normalize(); + } + if(result == Point3f(0, 0, 1)) + return Similarityf().SetIdentity(); + + Point3f axis = Point3f(0, 0, 1)^result; /* Axis of rotation */ + axis.Normalize(); + Point3f d = result - Point3f(0, 0, 1); + float t = d.Norm() / 2.0f; + if(t > thr) + t += (t - thr) * 0.7f; + if (t > 1.0f) t = 1.0f; + if (t < -1.0f) t = -1.0f; + float phi = 2 * math::Asin(t); + //return Similarityf().SetRotate(phi * 180/(float)M_PI, axis); + return Similarityf().SetRotate(phi, axis); +} + +Similarityf PlaneMode::Apply(const Point3f &p, const Similarityf &a) { + return Similarityf(Point3f(p[0], p[1], 0)); + Point3f r = x * a; + Point3f u = y * a; + int leading = 0; //leadiing x. + if(fabs(u[2]) < fabs(r[2])) //sceglie l'asse principale: quello che piu' e' parallelo al piano di vista. + leading = 1; + r[2] = 0; + u[2] = 0; + if(r == Point3f(0,0,0)) //casi degeneri: un asse e' perpendicolare al piano di vista. + r = Point3f(0, 1, 0); + if(u == Point3f(0,0,0)) + u = Point3f(0, 1, 0); + r.Normalize(); + u.Normalize(); + float cu, cr; + if(leading == 0) { //leading x + if(u == r || u == -r) { //caso degenere: i due assi si proiettano sullo stesso + u[0] = -r[1]; + u[1] = r[0]; + } + u = u - r * (r * u); + u.Normalize(); + } else { + if(r == u || r == -u) { //caso degenere: i due assi si proiettano sullo stesso + r[0] = -u[1]; + r[1] = u[0]; + } + r = r - u * (u * r); + r.Normalize(); + } + cr = r * p; + cu = u * p; + return Similarityf(x * cr + y * cu); +} \ No newline at end of file diff --git a/wrap/gui/trackmode.h b/wrap/gui/trackmode.h new file mode 100644 index 00000000..b1d5f59d --- /dev/null +++ b/wrap/gui/trackmode.h @@ -0,0 +1,54 @@ +#ifndef TRACKMODE_H +#define TRACKMODE_H + +#include +#include + +namespace vcg { + +class TrackMode { +public: + virtual ~TrackMode() {} + virtual void Draw() {} + virtual Similarityf Apply(const Point3f &p, const Similarityf &a) { return Similarityf().SetIdentity(); } +}; + +class SphereMode: public TrackMode { +public: + Similarityf Apply(const Point3f &p, const Similarityf &a); +}; + +class GravityMode: public TrackMode { +public: +}; + +class CylinderMode: public TrackMode { +public: + CylinderMode(const Point3f _axis): axis(_axis) { axis.Normalize(); } +protected: + Point3f axis; +}; + +class PlaneMode: public TrackMode { +public: + PlaneMode(const Point3f _x, const Point3f _y): x(_x), y(_y) { x.Normalize(); y.Normalize(); } + Similarityf Apply(const Point3f &p, const Similarityf &a); +protected: + Point3f x; + Point3f y; +}; + +class LineMode: public TrackMode { +public: + LineMode(const Point3f _axis): axis(_axis) { axis.Normalize();} +protected: + Point3f axis; +}; + +class ScaleMode: public TrackMode { +public: +}; + +}//namespace + +#endif \ No newline at end of file diff --git a/wrap/gui/view.h b/wrap/gui/view.h new file mode 100644 index 00000000..a256ec70 --- /dev/null +++ b/wrap/gui/view.h @@ -0,0 +1,108 @@ +#ifndef CAMERA_H +#define CAMERA_H + +#include +#include + +#include +#include + +namespace vcg { + +template class View { +public: + void GetView(); + void SetView(); + Point3 Project(const Point3 &p) const; + Point3 UnProject(const Point3 &p) const; + Point3 ViewPoint(); + //convert coordinates range 0-1 to range 0 viewport[2] + Point3 ScreenToViewport(const Point3 &p) const; + //viceversa + Point3 ViewportToScreen(const Point3 &p) const; + + Matrix44 proj; + Matrix44 model; + Matrix44 matrix; + Matrix44 inverse; + int viewport[4]; +}; + +template void View::GetView() { + double m[16]; + glGetDoublev(GL_PROJECTION_MATRIX, m); + for(int i = 0; i < 16; i++) + proj[i] = (T)m[i]; + glGetDoublev(GL_MODELVIEW_MATRIX, m); + for(int i = 0; i < 16; i++) + model[i] = (T)m[i]; + + glGetIntegerv(GL_VIEWPORT, viewport); + + matrix = model * proj; + inverse = matrix; + Invert(inverse); +} + +template void View::SetView() { + +} + +template Point3 View::ViewPoint() { + return inverse * Point3(0, 0, 0); + /*Matrix44d model(model_matrix); + model.Invert(); + Point3d view = model * Point3d(0, 0, 0); + return Point3(view[0], view[1], view[2]); */ +} + +template Point3 View::Project(const Point3 &p) const { + Point3 r; + r = p * matrix; + r[0] = (r[0]+1)*(viewport[2]/(T)2.0)+viewport[0]; + r[1] =(r[1]+1)*(viewport[3]/(T)2.0)+viewport[1]; + r[1] = viewport[3]-r[1]; + return r; + /*double r[3]; + gluProject(p[0], p[1], p[2], model_matrix, proj_matrix, viewport, &r[0], &r[1], &r[2]); + return Point3((T)r[0], (T)r[1], (T)r[2]);*/ +} + +template Point3 View::UnProject(const Point3 &p) const { + Point3 s = p; + s[0] = (p[0]- viewport[0])/ (viewport[2]/(T)2.0) - 1; + s[1] = (p[1]- viewport[1])/ (viewport[3]/(T)2.0) - 1; + s[1] = -s[1]; + s[2] = p[2]; + //s[1] = -s[1]; // pezza aggiunta per il tan2.... ????????????? + + s = s * inverse; + return s; + /*double r[3]; + gluUnProject(p[0], p[1], p[2], model_matrix, proj_matrix, viewport, &r[0], &r[1], &r[2]); + return Point3((T)r[0], (T)r[1], (T)r[2]);*/ +} + +template Point3 View::ScreenToViewport(const Point3 &p) const { + Point3 a; + a[0] = (p[0]+1)*(viewport[2]/(T)2.0)+viewport[0]; + a[1] =(p[1]+1)*(viewport[3]/(T)2.0)+viewport[1]; + a[1] = viewport[3] - a[1]; + a[2] = p[2]; + return a; +} + //viceversa +template Point3 View::ViewportToScreen(const Point3 &p) const { + Point3 a; + a[0] = (p[0]- viewport[0])/ (viewport[2]/(T)2.0) - 1; + a[1] = (p[1]- viewport[1])/ (viewport[3]/(T)2.0) - 1; + a[1] = -a[1]; + a[2] = p[2]; + //a[1] = -a[1]; // pezza aggiunta per il tan2.... ????????????? + return a; +} + + +}//namespace + +#endif \ No newline at end of file