2020-10-21 17:24:01 +02:00

882 lines
24 KiB
C++

/****************************************************************************
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2008 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 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 General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log$
Revision 1.5 2008/02/27 14:50:24 benedetti
fixed on_freehand_mesh_dragging, minor cleanups, now all functionality works
Revision 1.4 2008/02/26 21:35:17 benedetti
corrected after quaternion/similarity/trackball changes, on_freehand_mesh_dragging still doesn't work
Revision 1.3 2008/02/22 20:24:42 benedetti
refactored, cleaned up a bit, few feats added
Revision 1.2 2008/02/17 20:57:33 benedetti
updated following new specs (still got to clean up)
Revision 1.1 2008/02/16 14:29:35 benedetti
first version
****************************************************************************/
#include <QtGui>
#include <math.h>
#include <stdlib.h>
#include <meshlab/glarea.h>
#include <vcg/complex/algorithms/update/position.h>
#include <vcg/complex/algorithms/update/bounding.h>
#include <vcg/complex/algorithms/update/selection.h>
#include <vcg/space/fitting3.h>
#include <wrap/qt/trackball.h>
#include "editstraightener.h"
using namespace vcg;
EditStraightener::EditStraightener()
:dialog(NULL),dialog_dock(NULL),
gla(NULL),mm(NULL),refsize(0),currentmode(ES_Normal),
origin(NULL),old_origin(NULL),dragged_origin(NULL),
dragged_mesh(NULL),drawned_axes(NULL),undosystem(NULL),draw_bbox(true)
{}
const QString EditStraightener::Info()
{
return tr("Change the coordinate frame of a mesh.");
}
bool EditStraightener::StartEdit(MeshModel &m, GLArea *g )
{
//cleanup:
gla=NULL;
mm=NULL;
EndEdit(m,g);
gla = g;
mm = &m;
assert( (gla!=NULL) && (mm != NULL));
gla->setCursor(QCursor(QPixmap(":/images/cur_straightener.png"),15,15));
refsize=mm->cm.bbox.Diag()/2.0;
assert(origin==NULL);
origin=new MovableCoordinateFrame(refsize);
origin->basecolor=Color4b(170,170,0,255);
origin->xcolor=Color4b(170,0,0,255);
origin->ycolor=Color4b(0,170,0,255);
origin->zcolor=Color4b(0,0,170,255);
origin->linewidth=1.5;
currentmode=ES_Normal;
assert(dialog==NULL);
dialog = new EditStraightenerDialog(gla->window());
dialog_dock = new QDockWidget(gla->window());
dialog_dock->setAllowedAreas(Qt::NoDockWidgetArea);
dialog_dock->setWidget(dialog);
QPoint p = gla->window()->mapToGlobal(QPoint(0,0));
int x = -5 + p.x() + gla->window()->width() - dialog->width();
int y = p.y();
int w = dialog->width();
int h = dialog->height();
dialog_dock->setGeometry(x,y,w,h);
dialog_dock->setFloating(true);
connect(dialog, SIGNAL( begin_action() ),
this, SLOT( on_begin_action() ) );
connect(dialog, SIGNAL( apply() ),
this, SLOT( on_apply() ) );
connect(dialog, SIGNAL( freeze() ),
this, SLOT( on_freeze() ) );
connect(dialog, SIGNAL( undo() ),
this, SLOT( on_undo() ) );
connect(dialog, SIGNAL( rot(float,Point3f) ),
this, SLOT( on_rot(float,Point3f) ) );
connect(dialog, SIGNAL( align_with_view() ),
this, SLOT( on_align_with_view() ) );
connect(dialog, SIGNAL( move_axis_to_bbox(int,float) ),
this, SLOT( on_move_axis_to_bbox(int,float) ) );
connect(dialog, SIGNAL( center_on_trackball() ),
this, SLOT( on_center_on_trackball() ) );
connect(dialog, SIGNAL( draw_on_mesh(bool,char,char) ),
this, SLOT( on_draw_on_mesh(bool,char,char) ) );
connect(dialog, SIGNAL( freehand_axis_dragging(bool) ),
this, SLOT( on_freehand_axis_dragging(bool) ) );
connect(dialog, SIGNAL( set_snap(float) ),
this, SLOT( on_set_snap(float) ) );
connect(dialog, SIGNAL( freehand_mesh_dragging(bool) ),
this, SLOT( on_freehand_mesh_dragging(bool) ) );
connect(dialog, SIGNAL( get_plane_from_selection(char,char) ),
this, SLOT( on_get_plane_from_selection(char,char) ) );
connect(dialog, SIGNAL( update_show(bool,bool,bool,bool,bool,bool,bool,bool,bool) ),
this, SLOT( on_update_show(bool,bool,bool,bool,bool,bool,bool,bool,bool) ) );
dialog->shoutShow();
dialog->SetFreeze(freezable());
dialog_dock->setVisible(true);
dialog_dock->layout()->update();
assert(undosystem==NULL);
undosystem=new UndoSystem(this);
gla->update();
assert(origin!=NULL);
return true;
}
void EditStraightener::EndEdit(MeshModel &, GLArea *)
{
if (dialog!=NULL) { delete dialog; dialog=NULL; }
if (dialog_dock!=NULL) { delete dialog_dock; dialog_dock=NULL; }
if (origin!=NULL) { delete origin; origin=NULL; }
if (old_origin!=NULL) { delete old_origin; old_origin=NULL; }
if (dragged_origin!=NULL) { delete dragged_origin; dragged_origin=NULL; }
if (dragged_mesh!=NULL) { delete dragged_mesh; dragged_mesh=NULL; }
if (drawned_axes!=NULL) { delete drawned_axes; drawned_axes=NULL; }
if (undosystem!=NULL) { delete undosystem; undosystem=NULL; }
if(gla!=NULL){
gla->releaseKeyboard();
gla->update();
}
gla=NULL;
mm=NULL;
}
void EditStraightener::Decorate(MeshModel &, GLArea *)
{
dialog->updateSfn(mm->cm.sfn);
if (currentmode == ES_FreehandAxisDragging){
old_origin->Render(gla);
dragged_origin->Render(gla);
} else {
origin->Render(gla);
}
if(currentmode == ES_FreehandMeshDragging)
dragged_mesh->Render();
if( (currentmode == ES_DrawOnMesh) && (drawned_axes!=NULL) ){
drawned_axes->Render(gla);
if (drawned_axes->IsReady()){
Point3f a1,a2,b1,b2;
drawned_axes->GetAxes(a1,a2,b1,b2);
origin->AlignWith(a2-a1,b2-b1,drawned_axes->firstchar,drawned_axes->secondchar);
on_apply();
delete drawned_axes;
drawned_axes=NULL;
currentmode=ES_Normal;
dialog->endSpecialMode();
gla->trackball.Reset();
gla->update();
}
}
if(draw_bbox){
Box3f bbox = mm->cm.trBB();
float mx=bbox.min[0],my=bbox.min[1],mz=bbox.min[2];
float Mx=bbox.max[0],My=bbox.max[1],Mz=bbox.max[2];
float x=math::Clamp(.0f,mx,Mx);
float y=math::Clamp(.0f,my,My);
float z=math::Clamp(.0f,mz,Mz);
glPushAttrib(GL_ALL_ATTRIB_BITS);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POINT_SMOOTH);
glLineWidth(2);
glPointSize(5);
glBegin(GL_LINES);
if(mx<0){ // negative x
glColor3f(.3f,.0f,.0f);
glVertex3f(mx,my,mz); glVertex3f(x,my,mz);
glVertex3f(mx,my,Mz); glVertex3f(x,my,Mz);
glVertex3f(mx,My,mz); glVertex3f(x,My,mz);
glVertex3f(mx,My,Mz); glVertex3f(x,My,Mz);
}
if(Mx>0){ // positive x
glColor3f(.6f,.3f,.3f);
glVertex3f(x,my,mz); glVertex3f(Mx,my,mz);
glVertex3f(x,my,Mz); glVertex3f(Mx,my,Mz);
glVertex3f(x,My,mz); glVertex3f(Mx,My,mz);
glVertex3f(x,My,Mz); glVertex3f(Mx,My,Mz);
}
if(my<0){ // negative y
glColor3f(.0f,.3f,.0f);
glVertex3f(mx,my,mz); glVertex3f(mx,y,mz);
glVertex3f(mx,my,Mz); glVertex3f(mx,y,Mz);
glVertex3f(Mx,my,mz); glVertex3f(Mx,y,mz);
glVertex3f(Mx,my,Mz); glVertex3f(Mx,y,Mz);
}
if(My>0) { // positive y
glColor3f(.3f,.6f,.3f);
glVertex3f(mx,y,mz); glVertex3f(mx,My,mz);
glVertex3f(mx,y,Mz); glVertex3f(mx,My,Mz);
glVertex3f(Mx,y,mz); glVertex3f(Mx,My,mz);
glVertex3f(Mx,y,Mz); glVertex3f(Mx,My,Mz);
}
if(mz<0) { // negative z
glColor3f(.0f,.0f,.3f);
glVertex3f(mx,my,mz); glVertex3f(mx,my,z);
glVertex3f(mx,My,mz); glVertex3f(mx,My,z);
glVertex3f(Mx,my,mz); glVertex3f(Mx,my,z);
glVertex3f(Mx,My,mz); glVertex3f(Mx,My,z);
}
if(Mz>0) { // positive z
glColor3f(.3f,.3f,.6f);
glVertex3f(mx,my,z); glVertex3f(mx,my,Mz);
glVertex3f(mx,My,z); glVertex3f(mx,My,Mz);
glVertex3f(Mx,my,z); glVertex3f(Mx,my,Mz);
glVertex3f(Mx,My,z); glVertex3f(Mx,My,Mz);
}
glEnd();
glBegin(GL_POINTS);
if((mx<0)&&(Mx>0)){ // x crosses 0
glColor3f(1.0f,.6f,.6f);
glVertex3f(x,my,mz);
glVertex3f(x,my,Mz);
glVertex3f(x,My,mz);
glVertex3f(x,My,Mz);
}
if((my<0)&&(My>0)){ // y crosses 0
glColor3f(.6f,1.0f,.6f);
glVertex3f(mx,y,mz);
glVertex3f(mx,y,Mz);
glVertex3f(Mx,y,mz);
glVertex3f(Mx,y,Mz);
}
if((mz<0)&&(Mz>0)){ // z crosses 0
glColor3f(.6f,.6f,1.0f);
glVertex3f(mx,my,z);
glVertex3f(mx,My,z);
glVertex3f(Mx,my,z);
glVertex3f(Mx,My,z);
}
glEnd();
glPopAttrib();
}
assert(!glGetError());
}
void EditStraightener::mousePressEvent(QMouseEvent *e, MeshModel &, GLArea * )
{
switch (currentmode) {
case ES_FreehandAxisDragging:
dragged_origin->MouseDown(e->x(), gla->height() - e->y(), QT2VCG(e->button(), e->modifiers()));
break;
case ES_FreehandMeshDragging:
dragged_mesh->MouseDown(e->x(), gla->height() - e->y(), QT2VCG(e->button(), e->modifiers()));
break;
default:
break;
}
gla->update();
}
void EditStraightener::mouseMoveEvent(QMouseEvent *e, MeshModel &, GLArea * )
{
switch (currentmode) {
case ES_FreehandAxisDragging:
dragged_origin->MouseMove(e->x (),gla->height () - e->y ());
break;
case ES_DrawOnMesh:
drawned_axes->mouseMove(e->pos());
break;
case ES_FreehandMeshDragging:
dragged_mesh->MouseMove(e->x (),gla->height () - e->y ());
break;
default:
break;
}
gla->update();
}
void EditStraightener::mouseReleaseEvent(QMouseEvent *e, MeshModel &, GLArea *)
{
switch (currentmode) {
case ES_FreehandAxisDragging:
dragged_origin->MouseUp(e->x (),gla->height () - e->y (), QT2VCG (e->button (), 0));
break;
case ES_DrawOnMesh:
drawned_axes->mouseRelease(e->pos());
break;
case ES_FreehandMeshDragging:
dragged_mesh->MouseUp(e->x (),gla->height () - e->y (), QT2VCG (e->button (), e->modifiers ()));
break;
default:
break;
}
gla->update();
}
void EditStraightener::keyReleaseEvent (QKeyEvent * e, MeshModel &, GLArea *)
{
int button = 0;
if (e->key () == Qt::Key_Control){
button = QT2VCG (Qt::NoButton, Qt::ControlModifier);
} else if (e->key () == Qt::Key_Shift) {
button = QT2VCG (Qt::NoButton, Qt::ShiftModifier);
} else if (e->key () == Qt::Key_Alt) {
button = QT2VCG (Qt::NoButton, Qt::AltModifier);
} else {
e->ignore();
gla->update();
return;
}
switch (currentmode) {
case ES_FreehandAxisDragging:
dragged_origin->ButtonUp(button);
break;
case ES_FreehandMeshDragging:
dragged_mesh->ButtonUp(button);
default:
e->ignore();
}
gla->update();
}
void EditStraightener::keyPressEvent (QKeyEvent * e, MeshModel &, GLArea *)
{
int button;
if (e->key () == Qt::Key_Control){
button = QT2VCG (Qt::NoButton, Qt::ControlModifier);
} else if (e->key () == Qt::Key_Shift) {
button = QT2VCG (Qt::NoButton, Qt::ShiftModifier);
} else if (e->key () == Qt::Key_Alt) {
button = QT2VCG (Qt::NoButton, Qt::AltModifier);
} else {
e->ignore();
gla->update();
return;
}
switch (currentmode) {
case ES_FreehandAxisDragging:
dragged_origin->ButtonDown(button);
break;
case ES_FreehandMeshDragging:
dragged_mesh->ButtonDown(button);
default:
e->ignore();
}
gla->update();
}
bool EditStraightener::freezable()
{
const float EPSILON=1e-4;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if( math::Abs(mm->cm.Tr[i][j] - (i==j?1:0)) > EPSILON)
return true;
return false;
}
// slots:
void EditStraightener::on_begin_action()
{
assert(origin->GetPosition()==Point3f(0,0,0));
assert(origin->GetRotation()==Quaternionf(0,Point3f(1,0,0)));
undosystem->BeginAction();
}
void EditStraightener::on_apply()
{
Matrix44f tr;
origin->GetTransform(tr);
origin->Reset(true,true);
undosystem->SaveTR();
mm->cm.Tr = Inverse(tr) * mm->cm.Tr ;
dialog->SetFreeze(freezable());
gla->update();
}
void EditStraightener::on_freeze()
{
assert(origin->GetPosition()==Point3f(0,0,0));
assert(origin->GetRotation()==Quaternionf(0,Point3f(1,0,0)));
on_begin_action();
gla->setWindowModified(true);
undosystem->SaveFreeze();
tri::UpdatePosition<CMeshO>::Matrix(mm->cm, mm->cm.Tr);
tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(mm->cm);
tri::UpdateBounding<CMeshO>::Box(mm->cm);
undosystem->SaveTR();
mm->cm.Tr.SetIdentity();
dialog->SetFreeze(false);
gla->trackball.Reset();
gla->update();
}
void EditStraightener::on_undo()
{
assert(undosystem->CanUndo());
undosystem->Undo();
dialog->SetFreeze(freezable());
gla->update();
}
void EditStraightener::on_rot(float angle_deg,Point3f axis)
{
on_begin_action();
origin->Rot(angle_deg,axis);
on_apply();
gla->update();
}
void EditStraightener::on_align_with_view()
{
on_begin_action();
origin->SetRotation(gla->trackball.track.rot);
on_apply();
gla->trackball.Reset();
gla->update();
}
void EditStraightener::on_move_axis_to_bbox(int axis, float value)
{
Box3f bbox = mm->cm.trBB();
Point3f p = origin->GetPosition();
p[axis]=bbox.min[axis] + (bbox.max[axis]-bbox.min[axis]) * value;
origin->SetPosition(p); // della parte begin_action\apply si occupa EditStraightenerDialog
gla->update();
}
void EditStraightener::on_center_on_trackball()
{
Box3f bbox;
foreach(MeshModel * m, gla->meshDoc.meshList)
bbox.Add(m->cm.trBB());
on_begin_action();
origin->SetPosition(bbox.Center()-(gla->trackball.track.tra) * (0.5*bbox.Diag()));
on_apply();
gla->update();
}
void EditStraightener::on_draw_on_mesh(bool begin,char c1,char c2)
{
if(begin){
assert(currentmode==ES_Normal);
on_begin_action();
drawned_axes = new DrawAxes(c1,c2);
currentmode=ES_DrawOnMesh;
} else {
assert(currentmode==ES_DrawOnMesh);
delete drawned_axes;
drawned_axes=NULL;
on_undo();
currentmode=ES_Normal;
}
gla->update();
}
void EditStraightener::on_freehand_axis_dragging(bool begin)
{
if(begin){
assert(currentmode==ES_Normal);
assert(old_origin==NULL);
assert(dragged_origin==NULL);
on_begin_action();
gla->setMouseTracking(true);
gla->grabKeyboard ();
old_origin=new CoordinateFrame(refsize);
old_origin->basecolor=Color4b(128,128,0,255);
old_origin->xcolor=Color4b(128,0,0,255);
old_origin->ycolor=Color4b(0,128,0,255);
old_origin->zcolor=Color4b(0,0,128,255);
old_origin->linewidth=1;
dragged_origin=new ActiveCoordinateFrame(refsize);
dragged_origin->basecolor=Color4b(255,255,0,255);
dragged_origin->xcolor=Color4b(255,0,0,255);
dragged_origin->ycolor=Color4b(0,255,0,255);
dragged_origin->zcolor=Color4b(0,0,255,255);
dragged_origin->linewidth=3;
dragged_origin->SetSnap(dialog->getSnap());
dialog->shoutShow();
currentmode=ES_FreehandAxisDragging;
} else {
assert(currentmode==ES_FreehandAxisDragging);
origin->SetPosition(dragged_origin->GetPosition());
origin->SetRotation(dragged_origin->GetRotation());
delete (old_origin); old_origin=NULL;
delete (dragged_origin); dragged_origin=NULL;
currentmode=ES_Normal;
gla->releaseKeyboard();
gla->setMouseTracking(false);
on_apply();
}
gla->update();
}
void EditStraightener::on_set_snap(float rot_snap_deg)
{
if(dragged_origin!=NULL)
dragged_origin->SetSnap(rot_snap_deg);
gla->update();
}
void EditStraightener::on_freehand_mesh_dragging(bool begin)
{
if(begin){
assert(currentmode==ES_Normal);
on_begin_action();
dragged_mesh = new DrawPhantom(mm,refsize);
currentmode=ES_FreehandMeshDragging;
} else {
assert(currentmode==ES_FreehandMeshDragging);
assert(dragged_mesh!=NULL);
Matrix44f a,b,c;
a.SetTranslate( dragged_mesh->manipulator->center);
b = dragged_mesh->manipulator->track.Matrix();
c.SetTranslate(-dragged_mesh->manipulator->center);
undosystem->SaveTR();
mm->cm.Tr = mm->cm.Tr * a * b * c;
on_apply();
delete dragged_mesh;
dragged_mesh=NULL;
currentmode=ES_Normal;
}
gla->update();
}
void EditStraightener::on_get_plane_from_selection(char normal,char preserve)
{
assert(mm->cm.sfn > 0);
Box3f bbox; //il bbox delle facce selezionate
std::vector< Point3f > selected_pts; //devo copiare i punti per il piano di fitting
tri::UpdateSelection<CMeshO>::ClearVertex(mm->cm);
tri::UpdateSelection<CMeshO>::VertexFromFaceLoose(mm->cm);
CMeshO::VertexIterator vi;
for(vi=mm->cm.vert.begin();vi!=mm->cm.vert.end();++vi)
if(!(*vi).IsD() && (*vi).IsS() ){
Point3f p = mm->cm.Tr * (*vi).P();
bbox.Add(p);
selected_pts.push_back(p);
}
Plane3f plane;
PlaneFittingPoints(selected_pts,plane); //calcolo il piano di fitting
on_begin_action();
origin->SetPosition(plane.Projection(bbox.Center()));
origin->AlignWith(plane.Direction(),Point3f(0,0,0),normal,preserve);
on_apply();
gla->update();
}
void EditStraightener::on_update_show(bool db,bool ba, bool bl, bool bv, bool ca, bool cl, bool cv, bool m, bool r)
{
draw_bbox=db;
origin->drawaxis=ba;
origin->drawlabels=bl;
origin->drawvalues=bv;
if(dragged_origin!=NULL){
old_origin->drawaxis=ba;
old_origin->drawlabels=bl;
old_origin->drawvalues=bv;
dragged_origin->drawaxis=ca;
dragged_origin->drawlabels=cl;
dragged_origin->drawvalues=cv;
dragged_origin->drawmoves=m;
dragged_origin->drawrotations=r;
}
gla->update();
}
//////////////////////////////////////////////////////////////
DrawAxes::DrawAxes(char ch1,char ch2)
:firstchar(ch1),secondchar(ch2),
currentphase(DA_BEGIN),twoaxes(true),
first(Color4b(0,0,0,0)),second(Color4b(0,0,0,0)),
label1(QChar(ch1)),label2(QChar(ch2))
{
Color4b xc(255,128,128,255),yc(128,255,128,255),zc(128,128,255,255);
switch(ch1){
case 'X': first=Rubberband(xc); break;
case 'Y': first=Rubberband(yc); break;
case 'Z': first=Rubberband(zc); break;
default: assert(0);
}
switch(ch2){
case 'X': second=Rubberband(xc); break;
case 'Y': second=Rubberband(yc); break;
case 'Z': second=Rubberband(zc); break;
case ' ': twoaxes=false; break;
default: assert(0);
}
}
void DrawAxes::Render(QGLWidget *glw)
{
first.Render(glw);
second.Render(glw);
switch(currentphase){
case DA_BEGIN:
if(first.IsReady())
currentphase=DA_DONE_FIRST;
else first.RenderLabel(label1,glw);
break;
case DA_DONE_FIRST:
if(second.IsReady())
currentphase=DA_DONE_SECOND;
else second.RenderLabel(label2,glw);
break;
case DA_DONE_SECOND:
break;
default:
assert (0);
}
assert(!glGetError());
}
void DrawAxes::mouseMove(QPoint p)
{
if(IsReady())
return;
if(currentphase>=DA_DONE_FIRST)
second.Drag(p);
else
first.Drag(p);
}
void DrawAxes::mouseRelease(QPoint p)
{
if(IsReady())
return;
if(currentphase >= DA_DONE_FIRST)
second.Pin(p);
else
first.Pin(p);
}
bool DrawAxes::IsReady()
{
return currentphase >= ( twoaxes ? DA_DONE_SECOND : DA_DONE_FIRST);
}
void DrawAxes::GetAxes(Point3f &f1,Point3f &f2,Point3f &s1,Point3f &s2)
{
assert(IsReady());
first.GetPoints(f1,f2);
if(twoaxes){
second.GetPoints(s1,s2);
}else{
s1=s2=Point3f(0,0,0);
}
}
///////////////////////////////////
DrawPhantom::DrawPhantom(MeshModel* mm,float refsize)
{
glmesh.m = &(mm->cm);
glmesh.Update ();
tr=mm->cm.Tr;
manipulator = new Trackball();
manipulator->radius = refsize;
manipulator->center = Inverse(tr) * mm->cm.trBB().Center() ;
// rifaccio i modi senza le scalature
manipulator->ClearModes();
manipulator->modes[0] = NULL;
manipulator->modes[Trackball::BUTTON_LEFT] = new SphereMode ();
manipulator->modes[Trackball::BUTTON_LEFT |Trackball:: KEY_CTRL] = new PanMode ();
manipulator->modes[Trackball::BUTTON_MIDDLE] = new PanMode ();
manipulator->modes[Trackball::BUTTON_LEFT | Trackball::KEY_ALT] = new ZMode ();
manipulator->SetCurrentAction();
}
DrawPhantom::~DrawPhantom()
{
if(manipulator!=NULL) {
delete manipulator;
manipulator=NULL;
}
}
void DrawPhantom::Render()
{
glPushMatrix();
glPushAttrib (GL_ALL_ATTRIB_BITS);
glMultMatrix(tr);
manipulator->GetView();
manipulator->Apply(true);
float amb[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
float col[4] = { 0.5f, 0.5f, 0.8f, 1.0f };
float spe[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
glEnable (GL_LIGHTING);
glEnable (GL_LIGHT0);
glEnable (GL_NORMALIZE);
glEnable (GL_LINE_SMOOTH);
glEnable (GL_BLEND);
glEnable(GL_COLOR_MATERIAL);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor3f(0.4,0.4,0.8);
glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, amb);
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col);
glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,spe);
glmesh.Draw < GLW::DMWire , GLW::CMNone, GLW::TMNone > ();
glPopAttrib ();
glPopMatrix();
assert(!glGetError());
}
void DrawPhantom::MouseDown(int x, int y, /*Button*/ int button)
{
manipulator->MouseDown(x,y,button);
}
void DrawPhantom::MouseMove(int x, int y)
{
manipulator->MouseMove(x,y);
}
void DrawPhantom::MouseUp(int x, int y, /*Button */ int button)
{
manipulator->MouseUp(x, y, button);
}
void DrawPhantom::ButtonUp(int button)
{
manipulator->ButtonUp((Trackball::Button) button);
}
void DrawPhantom::ButtonDown(int button)
{
manipulator->ButtonDown((Trackball::Button) button);
}
////////////////////////////////////
UndoSystem::UndoSystem(EditStraightener const *e)
:marks(0),es(e),undotype_vec(),tr_vec()
{
}
void UndoSystem::BeginAction()
{
undotype_vec.push_back(US_MARK);
marks++;
if(marks>MAX_MARKS)
limitmarks();
if(marks==1)
es->dialog->SetUndo(true);
}
void UndoSystem::Undo()
{
assert(marks>0);
while(revert());
assert(undotype_vec.size()>0);
assert(undotype_vec.back()==US_MARK);
undotype_vec.pop_back();
marks--;
if(marks==0)
es->dialog->SetUndo(false);
}
bool UndoSystem::CanUndo()
{
return marks>0;
}
void UndoSystem::SaveTR()
{
assert(undotype_vec.size()>0);
undotype_vec.push_back(US_TR);
tr_vec.push_back(es->mm->cm.Tr);
}
void UndoSystem::SaveFreeze()
{
assert(undotype_vec.size()>0);
undotype_vec.push_back(US_FREEZE);
}
bool UndoSystem::revert()
{
assert(undotype_vec.size()>0);
UndoType undotype=undotype_vec.back();
switch(undotype){
case US_MARK:
return false;
case US_TR:
es->mm->cm.Tr=tr_vec.back();
tr_vec.pop_back();
break;
case US_FREEZE:
es->gla->setWindowModified(true);
tri::UpdatePosition<CMeshO>::Matrix(es->mm->cm, Inverse(es->mm->cm.Tr));
tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(es->mm->cm);
tri::UpdateBounding<CMeshO>::Box(es->mm->cm);
break;
}
undotype_vec.pop_back();
return true;
}
void UndoSystem::limitmarks()
{
if(undotype_vec.size()<=MAX_MARKS)
return;
assert(undotype_vec.size()>0);
assert(undotype_vec.front()==US_MARK);
// levo il mark di sotto
undotype_vec.pop_front();
marks--;
// levo tutto fino al prossimo mark (escluso)
while(true){
switch(undotype_vec.front()){
case US_MARK:
return;
case US_TR:
tr_vec.pop_front();
break;
case US_FREEZE:
break;
}
undotype_vec.pop_front();
}
}