mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-13 08:09:39 +00:00
1455 lines
45 KiB
C++
1455 lines
45 KiB
C++
#include <QtGui>
|
|
#include "renderarea.h"
|
|
#include "textureeditor.h"
|
|
#include <wrap/qt/trackball.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
|
|
#define SELECTIONRECT 100
|
|
#define ORIGINRECT 200
|
|
#define MAX 100000
|
|
#define NOSEL -1
|
|
#define AREADIM 400
|
|
#define HRECT 6
|
|
#define MINZOOM 0.1
|
|
#define MAXZOOM 7
|
|
|
|
RenderArea::RenderArea(QWidget *parent, QString textureName, MeshModel *m, unsigned tnum) : QGLWidget(parent)
|
|
{
|
|
antialiased = true;
|
|
setBackgroundRole(QPalette::Base);
|
|
setAutoFillBackground(true);
|
|
image = QImage();
|
|
if(textureName != QString())
|
|
{
|
|
if (QFile(textureName).exists()) image = QImage(textureName);
|
|
else textureName = QString();
|
|
}
|
|
textNum = tnum;
|
|
model = m;
|
|
|
|
// Init
|
|
oldX = 0; oldY = 0;
|
|
viewport = vcg::Point2f(0,0);
|
|
tmpX = 0; tmpY = 0;
|
|
tb = new Trackball();
|
|
tb->center = Point3f(0, 0, 0);
|
|
tb->radius = 1;
|
|
panX = 0; panY = 0;
|
|
oldPX = 0; oldPY = 0;
|
|
posVX = 0; posVY = 0;
|
|
|
|
brush = QBrush(Qt::green);
|
|
mode = View;
|
|
editMode = Scale;
|
|
origin = QPointF();
|
|
start = QPoint();
|
|
end = QPoint();
|
|
|
|
selectMode = Area;
|
|
selBit = CFaceO::NewBitFlag();
|
|
selVertBit = CVertexO::NewBitFlag();
|
|
selected = false;
|
|
selectedV = false;
|
|
|
|
vertRect = QRect(0,0,RADIUS,RADIUS);
|
|
selRect = vector<QRect>();
|
|
for (int i = 0; i < 4; i++) selRect.push_back(QRect(0,0,RECTDIM,RECTDIM));
|
|
selStart = QPoint(0,0); selEnd = QPoint(0,0);
|
|
degree = 0.0f;
|
|
highlighted = NOSEL;
|
|
pressed = NOSEL;
|
|
posX = 0; posY = 0;
|
|
oScale = QPointF(0,0);
|
|
scaleX = 1; scaleY = 1;
|
|
orX = 0; orY = 0;
|
|
initVX = 0; initVY = 0;
|
|
|
|
zoom = 1;
|
|
|
|
rot = QImage(QString(":/images/rotate.png"));
|
|
scal = QImage(QString(":/images/scale.png"));
|
|
|
|
this->setMouseTracking(true);
|
|
this->setCursor(Qt::PointingHandCursor);
|
|
this->setAttribute(Qt::WA_NoSystemBackground);
|
|
this->setAttribute(Qt::WA_KeyCompression, true);
|
|
this->setFocusPolicy(Qt::ClickFocus);
|
|
}
|
|
|
|
RenderArea::~RenderArea()
|
|
{
|
|
CFaceO::DeleteBitFlag(selBit);
|
|
CVertexO::DeleteBitFlag(selVertBit);
|
|
}
|
|
|
|
void RenderArea::setPen(const QPen &pen)
|
|
{
|
|
this->pen = pen;
|
|
update();
|
|
}
|
|
|
|
void RenderArea::setBrush(const QBrush &brush)
|
|
{
|
|
this->brush = brush;
|
|
update();
|
|
}
|
|
|
|
void RenderArea::setAntialiased(bool antialiased)
|
|
{
|
|
this->antialiased = antialiased;
|
|
update();
|
|
}
|
|
|
|
void RenderArea::setTexture(QString path)
|
|
{
|
|
image = QImage(path);
|
|
fileName = path;
|
|
}
|
|
|
|
void RenderArea::paintEvent(QPaintEvent *)
|
|
{
|
|
QPainter painter(this);
|
|
painter.setPen(QPen(brush,2));
|
|
painter.setBrush(brush);
|
|
painter.setRenderHint(QPainter::Antialiasing, antialiased);
|
|
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
|
//painter.begin(painter.device()); // Initialize a GL context
|
|
|
|
tb->GetView();
|
|
tb->Apply(true);
|
|
|
|
maxX = 0; maxY = 0; minX = 0; minY = 0;
|
|
if (model->cm.HasPerWedgeTexCoord() && image != QImage())
|
|
{
|
|
glEnable(GL_COLOR_LOGIC_OP);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glLineWidth(1);
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
glLogicOp(GL_XOR);
|
|
glColor3f(1,1,1);
|
|
// First draw the model in u,v space
|
|
if (model->cm.face[i].WT(0).n() == textNum)
|
|
{
|
|
// While drawning, it counts the number of 'planes'
|
|
if (model->cm.face[i].WT(0).u() > maxX || model->cm.face[i].WT(1).u() > maxX || model->cm.face[i].WT(2).u() > maxX) maxX++;
|
|
if (model->cm.face[i].WT(0).v() > maxY || model->cm.face[i].WT(1).v() > maxY || model->cm.face[i].WT(2).v() > maxY) maxY++;
|
|
if (model->cm.face[i].WT(0).u() < minX || model->cm.face[i].WT(1).u() < minX || model->cm.face[i].WT(2).u() < minX) minX--;
|
|
if (model->cm.face[i].WT(0).v() < minY || model->cm.face[i].WT(1).v() < minY || model->cm.face[i].WT(2).v() < minY) minY--;
|
|
|
|
// Draw the edge of faces
|
|
glBegin(GL_LINE_LOOP);
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
if (mode != EditVert)
|
|
{
|
|
if (!model->cm.face[i].IsUserBit(selBit))
|
|
glVertex3f(model->cm.face[i].WT(j).u() * AREADIM , AREADIM - (model->cm.face[i].WT(j).v() * AREADIM), 1);
|
|
else if (editMode == Scale) glVertex3f((oScale.x() + (model->cm.face[i].WT(j).u() - oScale.x()) * scaleX) * AREADIM - panX/zoom,
|
|
AREADIM - ((oScale.y() + (model->cm.face[i].WT(j).v() - oScale.y()) * scaleY) * AREADIM) - panY/zoom, 1);
|
|
else glVertex3f((origin.x() + (cos(degree) * (model->cm.face[i].WT(j).u() - origin.x()) - sin(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM - panX/zoom,
|
|
AREADIM - ((origin.y() + (sin(degree) * (model->cm.face[i].WT(j).u() - origin.x()) + cos(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM) - panY/zoom, 1);
|
|
}
|
|
else
|
|
{
|
|
if (areaUV.contains(QPointF(model->cm.face[i].WT(j).u(), model->cm.face[i].WT(j).v())) && model->cm.face[i].V(j)->IsUserBit(selVertBit))
|
|
glVertex3f((origin.x() + (cos(degree) * (model->cm.face[i].WT(j).u() - origin.x()) - sin(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM - posVX/zoom,
|
|
AREADIM - ((origin.y() + (sin(degree) * (model->cm.face[i].WT(j).u() - origin.x()) + cos(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM) - posVY/zoom, 1);
|
|
else glVertex3f(model->cm.face[i].WT(j).u() * AREADIM , AREADIM - (model->cm.face[i].WT(j).v() * AREADIM), 1);
|
|
}
|
|
}
|
|
glEnd();
|
|
|
|
// Draw the selected faces
|
|
if (selected && model->cm.face[i].IsUserBit(selBit))
|
|
{
|
|
glLogicOp(GL_AND);
|
|
glColor3f(1,0,0);
|
|
glBegin(GL_TRIANGLES);
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
if (editMode == Scale)
|
|
glVertex3f((oScale.x() + (model->cm.face[i].WT(j).u() - oScale.x()) * scaleX) * AREADIM - panX/zoom,
|
|
AREADIM - ((oScale.y() + (model->cm.face[i].WT(j).v() - oScale.y()) * scaleY) * AREADIM) - panY/zoom, 1);
|
|
else glVertex3f((origin.x() + (cos(degree) * (model->cm.face[i].WT(j).u() - origin.x()) - sin(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM - panX/zoom,
|
|
AREADIM - ((origin.y() + (sin(degree) * (model->cm.face[i].WT(j).u() - origin.x()) + cos(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM) - panY/zoom, 1);
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
// Draw the selected vertex
|
|
if (selectedV)
|
|
{
|
|
glDisable(GL_COLOR_LOGIC_OP);
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
if(areaUV.contains(QPointF(model->cm.face[i].WT(j).u(), model->cm.face[i].WT(j).v())) && model->cm.face[i].V(j)->IsUserBit(selVertBit))
|
|
{
|
|
glColor3f(1,0,0);
|
|
DrawCircle(QPoint((origin.x() + (cos(degree) * (model->cm.face[i].WT(j).u() - origin.x()) - sin(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM - posVX/zoom,
|
|
AREADIM - ((origin.y() + (sin(degree) * (model->cm.face[i].WT(j).u() - origin.x()) + cos(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM) - posVY/zoom));
|
|
glColor3f(0,0,0);
|
|
}
|
|
}
|
|
glEnable(GL_COLOR_LOGIC_OP);
|
|
}
|
|
}
|
|
}
|
|
glDisable(GL_LOGIC_OP);
|
|
glDisable(GL_COLOR_LOGIC_OP);
|
|
|
|
// Draw the background behind the model
|
|
if (minX != 0 || minY != 0 || maxX != 0 || maxY != 0)
|
|
{
|
|
for (int x = minX; x < maxX; x++)
|
|
for (int y = minY; y < maxY; y++)
|
|
painter.drawImage(QRect(x*AREADIM,-y*AREADIM,AREADIM,AREADIM),image,QRect(0,0,image.width(),image.height()));
|
|
}
|
|
else painter.drawImage(QRect(0,0,AREADIM,AREADIM),image,QRect(0,0,image.width(),image.height()));
|
|
|
|
// and the axis, always in first plane
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glOrtho(0,this->width(),this->height(),0,-1,1);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glPushAttrib(GL_ENABLE_BIT);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_TEXTURE_2D);
|
|
// Line and text (native Qt)
|
|
int w = this->visibleRegion().boundingRect().width();
|
|
int h = this->visibleRegion().boundingRect().height();
|
|
painter.drawLine(0,h,w,h);
|
|
painter.drawLine(0,h,0,0);
|
|
// Calculate the coords and draw it
|
|
float ox = (float)-viewport.X()*zoom/(AREADIM*zoom), oy = (float)(AREADIM*zoom - h + viewport.Y()*zoom)/(AREADIM*zoom);
|
|
/*O:*/painter.drawText(TRANSLATE, h - TRANSLATE, QString("(%1,%2)").arg(ox).arg(oy));
|
|
/*Y:*/painter.drawText(TRANSLATE, TRANSLATE*3, QString("(%1,%2)").arg(ox).arg((float)(AREADIM*zoom + viewport.Y()*zoom)/(AREADIM*zoom)));
|
|
/*X:*/painter.drawText(w - TRANSLATE*18, h - TRANSLATE, QString("(%1,%2)").arg((float)(w-viewport.X()*zoom)/(AREADIM*zoom)).arg(oy));
|
|
painter.drawText(TRANSLATE, TRANSLATE*6, QString("V"));
|
|
painter.drawText(w - TRANSLATE*23, h - TRANSLATE, QString("U"));
|
|
|
|
// Draw the rectangle of selection
|
|
if (start != QPoint() && end != QPoint())
|
|
{
|
|
painter.setPen(QPen(QBrush(Qt::gray),1));
|
|
painter.setBrush(QBrush(Qt::NoBrush));
|
|
painter.drawRect(area);
|
|
}
|
|
|
|
if (selection != QRect() && (mode == Edit || mode == EditVert))
|
|
{
|
|
// The rectangle of editing
|
|
painter.setPen(QPen(QBrush(Qt::yellow),2));
|
|
painter.setBrush(QBrush(Qt::NoBrush));
|
|
if (mode == Edit)
|
|
{
|
|
painter.drawRect(QRect(selection.x() - posX, selection.y() - posY, selection.width(), selection.height()));
|
|
}
|
|
else
|
|
{
|
|
painter.drawRect(QRect(selection.x() - posVX, selection.y() - posVY, selection.width(), selection.height()));
|
|
/*painter.fillRect(QRect(selection.x() - HRECT/2 - posVX + selection.width()/2, selection.y() - HRECT/2 - posVY, HRECT, HRECT), QBrush(Qt::black));
|
|
painter.fillRect(QRect(selection.x() - HRECT/2 - posVX, selection.y() - HRECT/2 - posVY + selection.height()/2, HRECT, HRECT), QBrush(Qt::black));
|
|
painter.fillRect(QRect(selection.x() - HRECT/2 - posVX + selection.width(), selection.y() + selection.height()/2 - HRECT/2 - posVY, HRECT, HRECT), QBrush(Qt::black));
|
|
painter.fillRect(QRect(selection.x() + selection.width()/2 - HRECT/2 - posVX, selection.y() + selection.height() - HRECT/2 - posVY, HRECT, HRECT), QBrush(Qt::black));
|
|
*/
|
|
}
|
|
|
|
if (mode == Edit || (mode == EditVert && VCount > 1))
|
|
{
|
|
// Rectangle on the corner
|
|
painter.setPen(QPen(QBrush(Qt::black),1));
|
|
for (unsigned l = 0; l < selRect.size(); l++)
|
|
{
|
|
if (l == highlighted) painter.setBrush(QBrush(Qt::yellow));
|
|
else painter.setBrush(QBrush(Qt::NoBrush));
|
|
painter.drawRect(selRect[l]);
|
|
if (editMode == Scale && mode == Edit) painter.drawImage(selRect[l],scal,QRect(0,0,scal.width(),scal.height()));
|
|
else painter.drawImage(selRect[l],rot,QRect(0,0,rot.width(),rot.height()));
|
|
}
|
|
|
|
// and the origin of the rotation
|
|
if ((editMode == Rotate && mode == Edit) || mode == EditVert)
|
|
{
|
|
painter.setPen(QPen(QBrush(Qt::black),1));
|
|
if (highlighted == ORIGINRECT) painter.setBrush(QBrush(Qt::blue));
|
|
else painter.setBrush(QBrush(Qt::yellow));
|
|
if (mode == Edit) painter.drawEllipse(QRect(originR.x() - posX - orX, originR.y() - posY - orY, RADIUS, RADIUS));
|
|
else painter.drawEllipse(QRect(originR.x() - posVX - orX, originR.y() - posVY - orY, RADIUS, RADIUS));
|
|
}
|
|
}
|
|
}
|
|
|
|
glDisable(GL_LOGIC_OP);
|
|
glPopAttrib();
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
}
|
|
else painter.drawText(TEXTX, TEXTY, tr("NO TEXTURE"));
|
|
|
|
painter.setPen(palette().dark().color());
|
|
painter.setBrush(Qt::NoBrush);
|
|
|
|
//painter.end();
|
|
}
|
|
|
|
// Mouse Event:
|
|
void RenderArea::mousePressEvent(QMouseEvent *e)
|
|
{
|
|
if ((mode == Edit || mode == EditVert) && highlighted == NOSEL)
|
|
{
|
|
this->ChangeMode(3);
|
|
pressed = NOSEL;
|
|
selected = false;
|
|
selectedV = false;
|
|
selVertBit = CVertexO::NewBitFlag();
|
|
selBit = CFaceO::NewBitFlag();
|
|
}
|
|
switch(mode)
|
|
{
|
|
case View:
|
|
oldX = e->x(); oldY = e->y();
|
|
tmpX = viewport.X(); tmpY = viewport.Y();
|
|
tb->MouseDown(e->x(), AREADIM-e->y(), QT2VCG(e->button(), e->modifiers()));
|
|
this->update();
|
|
break;
|
|
case Edit:
|
|
tpanX = e->x();
|
|
tpanY = e->y();
|
|
pressed = highlighted;
|
|
if (highlighted > NOSEL && highlighted < selRect.size() && mode == Edit)
|
|
{
|
|
rectX = selRect[highlighted].center().x();
|
|
rectY = selRect[highlighted].center().y();
|
|
oldSRX = selection.width();
|
|
oldSRY = selection.height();
|
|
scaleX = 1; scaleY = 1;
|
|
int perno;
|
|
if (highlighted == 0) perno = 3;
|
|
else if (highlighted == 1) perno = 2;
|
|
else if (highlighted == 2) perno = 1;
|
|
else perno = 0;
|
|
oScale = ToUVSpace(selRect[perno].center().x(), selRect[perno].center().y());
|
|
B2 = (float)(rectX - originR.center().x())*(rectX - originR.center().x()) + (rectY - originR.center().y())*(rectY - originR.center().y());
|
|
Rm = (float)(rectY - originR.center().y()) / (rectX - originR.center().x());
|
|
Rq = (float) rectY - Rm * rectX;
|
|
}
|
|
case EditVert:
|
|
tpanX = e->x();
|
|
tpanY = e->y();
|
|
if (highlighted > NOSEL && highlighted < selRect.size())
|
|
{
|
|
rectX = selRect[highlighted].center().x();
|
|
rectY = selRect[highlighted].center().y();
|
|
int perno;
|
|
if (highlighted == 0) perno = 3;
|
|
else if (highlighted == 1) perno = 2;
|
|
else if (highlighted == 2) perno = 1;
|
|
else perno = 0;
|
|
B2 = (float)(rectX - originR.center().x())*(rectX - originR.center().x()) + (rectY - originR.center().y())*(rectY - originR.center().y());
|
|
Rm = (float)(rectY - originR.center().y()) / (rectX - originR.center().x());
|
|
Rq = (float) rectY - Rm * rectX;
|
|
}
|
|
pressed = highlighted;
|
|
break;
|
|
case Select:
|
|
start = e->pos();
|
|
end = e->pos();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RenderArea::mouseReleaseEvent(QMouseEvent *e)
|
|
{
|
|
switch(mode)
|
|
{
|
|
case View:
|
|
if (selection != QRect())
|
|
{
|
|
UpdateSelectionArea((viewport.X() - initVX)*zoom, (viewport.Y() - initVY)*zoom);
|
|
originR.moveCenter(QPoint(originR.x() + (viewport.X() - initVX)*zoom, originR.y() + (viewport.Y() - initVY)*zoom));
|
|
origin = ToUVSpace(originR.center().x(), originR.center().y());
|
|
}
|
|
initVX = viewport.X(); initVY = viewport.Y();
|
|
break;
|
|
case Edit:
|
|
oldPX = panX;
|
|
oldPY = panY;
|
|
if (pressed == ORIGINRECT) // Drag origin -> Update the position of the rectangle of rotation and the real point in UV
|
|
{
|
|
originR = QRect(originR.x() - posX - orX, originR.y() - posY - orY, RADIUS, RADIUS);
|
|
origin = ToUVSpace(originR.center().x(), originR.center().y());
|
|
orX = 0; orY = 0;
|
|
}
|
|
else if (pressed == SELECTIONRECT && posX != 0) // Drag selection -> Update the position of the selection area and the rotatation rect
|
|
{
|
|
selection = QRect(selection.x() - posX, selection.y() - posY, selection.width(), selection.height());
|
|
originR.moveCenter(QPoint(originR.center().x() - posX, originR.center().y() - posY));
|
|
origin = ToUVSpace(originR.center().x(), originR.center().y());
|
|
posX = 0; posY = 0;
|
|
if (selected) UpdateUV();
|
|
}
|
|
else if (pressed > NOSEL && pressed < selRect.size())
|
|
{
|
|
if (editMode == Rotate)
|
|
{
|
|
RotateComponent(degree);
|
|
RecalculateSelectionArea();
|
|
degree = 0;
|
|
}
|
|
else if (scaleX != 1 && scaleY != 1)
|
|
{
|
|
ScaleComponent(scaleX, scaleY);
|
|
RecalculateSelectionArea();
|
|
scaleX = 1;
|
|
scaleY = 1;
|
|
oScale = QPointF(0,0);
|
|
}
|
|
}
|
|
break;
|
|
case EditVert:
|
|
if (pressed == ORIGINRECT)
|
|
{
|
|
originR = QRect(originR.x() - posX - orX, originR.y() - posY - orY, RADIUS, RADIUS);
|
|
origin = ToUVSpace(originR.center().x(), originR.center().y());
|
|
orX = 0; orY = 0;
|
|
}
|
|
else if (pressed == SELECTIONRECT && posVX != 0)
|
|
{
|
|
selection = QRect(selection.x() - posVX, selection.y() - posVY, selection.width(), selection.height());
|
|
originR.moveCenter(QPoint(originR.center().x() - posVX, originR.center().y() - posVY));
|
|
origin = ToUVSpace(originR.center().x(), originR.center().y());
|
|
if (selectedV) UpdateVertex();
|
|
}
|
|
else if (pressed > NOSEL && pressed < selRect.size())
|
|
{
|
|
RotateComponent(degree);
|
|
UpdateVertexSelection();
|
|
UpdateSelectionAreaV(0,0);
|
|
degree = 0;
|
|
}
|
|
break;
|
|
case Select:
|
|
start = QPoint();
|
|
end = QPoint();
|
|
area = QRect();
|
|
switch (selectMode)
|
|
{
|
|
case Area:
|
|
if (selected)
|
|
{
|
|
selection = QRect(selStart, selEnd);
|
|
UpdateSelectionArea(0,0);
|
|
origin = ToUVSpace(selection.center().x(), selection.center().y());
|
|
originR = QRect(selection.center().x()-RADIUS/2, selection.center().y()-RADIUS/2, RADIUS, RADIUS);
|
|
this->ChangeMode(1);
|
|
this->update(selection);
|
|
this->ShowFaces();
|
|
emit UpdateModel();
|
|
}
|
|
break;
|
|
case Connected:
|
|
SelectConnectedComponent(e->pos());
|
|
if (selected)
|
|
{
|
|
selection = QRect(selStart, selEnd);
|
|
UpdateSelectionArea(0,0);
|
|
origin = ToUVSpace(selection.center().x(), selection.center().y());
|
|
originR = QRect(selection.center().x()-RADIUS/2, selection.center().y()-RADIUS/2, RADIUS, RADIUS);
|
|
this->ChangeMode(1);
|
|
this->update();
|
|
this->ShowFaces();
|
|
emit UpdateModel();
|
|
}
|
|
break;
|
|
case Vertex:
|
|
if (selectedV)
|
|
{
|
|
CountVertexes();
|
|
selection = QRect(QPoint(selStart.x() - RADIUS/2, selStart.y() - RADIUS/2), QPoint(selEnd.x() + RADIUS/2, selEnd.y() + RADIUS/2));
|
|
if (VCount > 1)
|
|
{
|
|
UpdateSelectionAreaV(0,0);
|
|
origin = ToUVSpace(selection.center().x(), selection.center().y());
|
|
originR = QRect(selection.center().x()-RADIUS/2, selection.center().y()-RADIUS/2, RADIUS, RADIUS);
|
|
}
|
|
this->ChangeMode(4);
|
|
this->update();
|
|
}
|
|
else this->update();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RenderArea::mouseMoveEvent(QMouseEvent *e)
|
|
{
|
|
if((e->buttons() & Qt::LeftButton))
|
|
{
|
|
int sx = (e->x() - oldX)/zoom, sy = (e->y() - oldY)/zoom;
|
|
switch(mode)
|
|
{
|
|
case View:
|
|
tb->Translate(Point3f(- oldX + e->x(), - oldY + e->y(), zoom));
|
|
viewport = Point2f(tmpX + sx, tmpY + sy);
|
|
this->update();
|
|
break;
|
|
case Edit:
|
|
if (pressed == SELECTIONRECT)
|
|
{
|
|
// Move the selection ara
|
|
panX = oldPX + tpanX - e->x();
|
|
panY = oldPY + tpanY - e->y();
|
|
posX = tpanX - e->x();
|
|
posY = tpanY - e->y();
|
|
if (posX != 0 || posY != 0)
|
|
{
|
|
selRect[0].moveCenter(QPoint(selection.topLeft().x() - posX, selection.topLeft().y() - posY));
|
|
selRect[1].moveCenter(QPoint(selection.topRight().x() - posX, selection.topRight().y() - posY));
|
|
selRect[2].moveCenter(QPoint(selection.bottomLeft().x() - posX, selection.bottomLeft().y() - posY));
|
|
selRect[3].moveCenter(QPoint(selection.bottomRight().x() - posX, selection.bottomRight().y() - posY));
|
|
}
|
|
this->update();
|
|
}
|
|
else if (pressed == ORIGINRECT)
|
|
{
|
|
// Move the origin rect inside the selection area
|
|
orX = tpanX - e->x();
|
|
/*int tx = originR.center().x() - orX;
|
|
if (tx < selection.x()) orX = - selection.x() + originR.center().x();
|
|
else if (tx > selection.x() + selection.width()) orX = originR.center().x() - (selection.x() + selection.width());
|
|
*/
|
|
orY = tpanY - e->y();
|
|
/*int ty = originR.y() - posY - orY;
|
|
if (ty < selection.y()) orY = - selection.y() + originR.center().y();
|
|
else if (ty > selection.y() + selection.height()) orY = originR.center().y() - (selection.y() + selection.height());
|
|
*/
|
|
this->update(originR);
|
|
}
|
|
else if (pressed > NOSEL && pressed < selRect.size())
|
|
{
|
|
if (editMode == Scale) HandleScale(e->pos());
|
|
else HandleRotate(e->pos());
|
|
}
|
|
break;
|
|
case EditVert:
|
|
if (pressed == SELECTIONRECT)
|
|
{
|
|
// Move the selection ara
|
|
posVX = tpanX - e->x();
|
|
posVY = tpanY - e->y();
|
|
if (posVX != 0 || posVY != 0)
|
|
{
|
|
selRect[0].moveBottomRight(QPoint(selection.topLeft().x() - posVX, selection.topLeft().y() - posVY));
|
|
selRect[1].moveBottomLeft(QPoint(selection.topRight().x() - posVX, selection.topRight().y() - posVY));
|
|
selRect[2].moveTopRight(QPoint(selection.bottomLeft().x() - posVX, selection.bottomLeft().y() - posVY));
|
|
selRect[3].moveTopLeft(QPoint(selection.bottomRight().x() - posVX, selection.bottomRight().y() - posVY));
|
|
}
|
|
}
|
|
else if (pressed > NOSEL && pressed < selRect.size())
|
|
{
|
|
HandleRotate(e->pos());
|
|
}
|
|
else if (pressed == ORIGINRECT)
|
|
{
|
|
orX = tpanX - e->x();
|
|
orY = tpanY - e->y();
|
|
this->update(originR);
|
|
}
|
|
this->update();
|
|
break;
|
|
case Select:
|
|
if (selectMode != Connected)
|
|
{
|
|
end = e->pos();
|
|
int x1, x2, y1, y2;
|
|
if (start.x() < end.x()) {x1 = start.x(); x2 = end.x();} else {x1 = end.x(); x2 = start.x();}
|
|
if (start.y() < end.y()) {y1 = start.y(); y2 = end.y();} else {y1 = end.y(); y2 = start.y();}
|
|
area = QRect(x1,y1,x2-x1,y2-y1);
|
|
if (selectMode == Area) SelectFaces();
|
|
else SelectVertexes();
|
|
this->update(area);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mode == Edit || mode == EditVert)
|
|
{
|
|
for (unsigned y = 0; y < selRect.size(); y++)
|
|
{
|
|
if (selRect[y].contains(e->pos()) && (mode == Edit || (mode == EditVert && VCount > 1)))
|
|
{
|
|
if (highlighted != y) this->update(selRect[y]);
|
|
highlighted = y;
|
|
return;
|
|
}
|
|
}
|
|
if (originR.contains(e->pos()) && ((mode == Edit && editMode == Rotate) || mode == EditVert))
|
|
{
|
|
if (highlighted != ORIGINRECT) this->update(originR);
|
|
highlighted = ORIGINRECT;
|
|
return;
|
|
}
|
|
if (selection.contains(e->pos()))
|
|
{
|
|
if (highlighted == ORIGINRECT) this->update(originR);
|
|
else if (highlighted < selRect.size()) this->update(selRect[highlighted]);
|
|
highlighted = SELECTIONRECT;
|
|
return;
|
|
}
|
|
if (highlighted != NOSEL)
|
|
{
|
|
if (highlighted == ORIGINRECT) this->update(originR);
|
|
else if (highlighted < selRect.size()) this->update(selRect[highlighted]);
|
|
}
|
|
highlighted = NOSEL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderArea::mouseDoubleClickEvent(QMouseEvent *e)
|
|
{
|
|
switch(mode)
|
|
{
|
|
case View: // Center the screen on the mouse click position
|
|
viewport = Point2f(viewport.X() - e->x()/zoom + (this->visibleRegion().boundingRect().width()/zoom)/2,
|
|
viewport.Y() - e->y()/zoom + (this->visibleRegion().boundingRect().height()/zoom)/2);
|
|
oldX = 0; oldY = 0;
|
|
tb->track.SetTranslate(Point3f(viewport.X(), viewport.Y(), 1));
|
|
tb->Scale(zoom);
|
|
this->update();
|
|
break;
|
|
case Edit: // Change edit mode
|
|
if (selection.contains(e->pos()))
|
|
{
|
|
if (editMode == Rotate) editMode = Scale;
|
|
else editMode = Rotate;
|
|
this->update();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RenderArea::wheelEvent(QWheelEvent*e)
|
|
{
|
|
// Handle the zoom for any mode
|
|
int cwx = viewport.X() - (this->visibleRegion().boundingRect().width()/zoom)/2;
|
|
int cwy = viewport.Y() - (this->visibleRegion().boundingRect().height()/zoom)/2;
|
|
bool scale = false;
|
|
if (e->delta() > 0)
|
|
{
|
|
if (zoom/0.75 < MAXZOOM) { zoom /= 0.75; scale = true; }
|
|
}
|
|
else if (zoom*0.75 > MINZOOM) { zoom *= 0.75; scale = true; }
|
|
if (scale)
|
|
{
|
|
// Change the viewport, putting the center of the screen on the mouseposition
|
|
cwx += (this->visibleRegion().boundingRect().width()/zoom)/2;
|
|
cwy += (this->visibleRegion().boundingRect().height()/zoom)/2;
|
|
viewport = Point2f(cwx, cwy);
|
|
ResetTrack(false);
|
|
tb->Scale(zoom);
|
|
if (selectedV)
|
|
{
|
|
UpdateVertexSelection();
|
|
UpdateSelectionAreaV(0,0);
|
|
}
|
|
else
|
|
{
|
|
RecalculateSelectionArea();
|
|
UpdateSelectionArea(0,0);
|
|
}
|
|
originR.moveCenter(ToScreenSpace(origin.x(), origin.y()));
|
|
initVX = viewport.X(); initVY = viewport.Y();
|
|
this->update();
|
|
}
|
|
}
|
|
|
|
void RenderArea::keyPressEvent(QKeyEvent *e)
|
|
{
|
|
if (e->key() == Qt::Key_H) ResetPosition();
|
|
else e->ignore();
|
|
}
|
|
|
|
void RenderArea::RemapClamp()
|
|
{
|
|
// Remap the uv coord out of border using clamp method
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
if (model->cm.face[i].WT(0).n() == textNum)
|
|
{
|
|
model->cm.face[i].ClearUserBit(selBit);
|
|
for (unsigned j = 0; j < 3; j++)
|
|
{
|
|
if (model->cm.face[i].WT(j).u() > 1) model->cm.face[i].WT(j).u() = 1;
|
|
else if (model->cm.face[i].WT(j).u() < 0) model->cm.face[i].WT(j).u() = 0;
|
|
if (model->cm.face[i].WT(j).v() > 1) model->cm.face[i].WT(j).v() = 1;
|
|
else if (model->cm.face[i].WT(j).v() < 0) model->cm.face[i].WT(j).v() = 0;
|
|
}
|
|
}
|
|
}
|
|
panX = 0; panY = 0; tpanX = 0; tpanY = 0; oldPX = 0; oldPY = 0;
|
|
ResetTrack(true);
|
|
this->update();
|
|
emit UpdateModel();
|
|
}
|
|
|
|
void RenderArea::RemapMod()
|
|
{
|
|
// Remap the uv coord out of border using mod function
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
if (model->cm.face[i].WT(0).n() == textNum)
|
|
{
|
|
model->cm.face[i].ClearUserBit(selBit);
|
|
for (unsigned j = 0; j < 3; j++)
|
|
{
|
|
float u = model->cm.face[i].WT(j).u();
|
|
float v = model->cm.face[i].WT(j).v();
|
|
if (u < 0) u = u + (int)u + 1;
|
|
else if (u > 1) u = u - (int)u;
|
|
if (v < 0) v = v + (int)v + 1;
|
|
else if (v > 1) v = v - (int)v;
|
|
model->cm.face[i].WT(j).u() = u;
|
|
model->cm.face[i].WT(j).v() = v;
|
|
}
|
|
}
|
|
}
|
|
panX = 0; panY = 0; tpanX = 0; tpanY = 0; oldPX = 0; oldPY = 0;
|
|
ResetTrack(true);
|
|
this->update();
|
|
emit UpdateModel();
|
|
}
|
|
|
|
void RenderArea::ChangeMode(int index)
|
|
{
|
|
// Change the selection mode
|
|
switch(index)
|
|
{
|
|
case 0:
|
|
if (mode != View)
|
|
{
|
|
mode = View;
|
|
this->setCursor(Qt::PointingHandCursor);
|
|
}
|
|
break;
|
|
case 1:
|
|
if (mode != Edit)
|
|
{
|
|
mode = Edit;
|
|
this->setCursor(Qt::SizeAllCursor);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (mode != Select)
|
|
{
|
|
if (selection != QRect())
|
|
{
|
|
if (selectMode == Vertex)
|
|
{
|
|
mode = EditVert;
|
|
selectedV = true;
|
|
selBit = CFaceO::NewBitFlag();
|
|
}
|
|
else
|
|
{
|
|
mode = Edit;
|
|
selected = true;
|
|
selVertBit = CVertexO::NewBitFlag();
|
|
}
|
|
this->setCursor(Qt::SizeAllCursor);
|
|
}
|
|
else
|
|
{
|
|
mode = Select;
|
|
selBit = CFaceO::NewBitFlag();
|
|
selVertBit = CVertexO::NewBitFlag();
|
|
this->setCursor(Qt::CrossCursor);
|
|
}
|
|
}
|
|
break;
|
|
case 3: // For internal use... reset the selction
|
|
mode = Select;
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++) model->cm.face[i].ClearUserBit(selBit);
|
|
selection = QRect();
|
|
this->setCursor(Qt::CrossCursor);
|
|
break;
|
|
case 4:
|
|
if (mode != EditVert)
|
|
{
|
|
if (selection != QRect())
|
|
{
|
|
mode = EditVert;
|
|
selectedV = true;
|
|
this->setCursor(QCursor(QBitmap(":/images/sel_move.png")));
|
|
}
|
|
else
|
|
{
|
|
mode = Select;
|
|
this->setCursor(Qt::CrossCursor);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
this->update();
|
|
}
|
|
|
|
void RenderArea::ChangeSelectMode(int index)
|
|
{
|
|
// Change the function of the mouse selection
|
|
switch(index)
|
|
{
|
|
case 0:
|
|
if (selectMode != Area && selectMode != Connected) selection = QRect();
|
|
selectMode = Area;
|
|
break;
|
|
case 1:
|
|
if (selectMode != Connected && selectMode != Area) selection = QRect();
|
|
selectMode = Connected;
|
|
break;
|
|
case 2:
|
|
if (selectMode != Vertex) selection = QRect();
|
|
selectMode = Vertex;
|
|
break;
|
|
default:
|
|
selectMode = Area;
|
|
break;
|
|
}
|
|
if (selectedV && selectMode != Vertex)
|
|
{
|
|
areaUV = QRectF();
|
|
selVertBit = CVertexO::NewBitFlag();
|
|
selectedV = false;
|
|
}
|
|
if (selected && selectMode == Vertex)
|
|
{
|
|
selected = false;
|
|
selBit = CFaceO::NewBitFlag();
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++) model->cm.face[i].ClearS();
|
|
emit UpdateModel();
|
|
}
|
|
}
|
|
|
|
void RenderArea::RotateComponent(float theta)
|
|
{
|
|
// Calcolate the new position of the vertex of the selected component after a rotation.
|
|
// The rotation is done around the selected point
|
|
if (origin != QPoint())
|
|
{
|
|
float sinv = sin(theta);
|
|
float cosv = cos(theta);
|
|
if (selected)
|
|
{
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
if (model->cm.face[i].WT(0).n() == textNum && (!selected || (selected && model->cm.face[i].IsUserBit(selBit))))
|
|
for (unsigned j = 0; j < 3; j++)
|
|
{
|
|
float u = origin.x() + (cosv * (model->cm.face[i].WT(j).u() - origin.x()) - sinv * (model->cm.face[i].WT(j).v() - origin.y()));
|
|
float v = origin.y() + (sinv * (model->cm.face[i].WT(j).u() - origin.x()) + cosv * (model->cm.face[i].WT(j).v() - origin.y()));
|
|
model->cm.face[i].WT(j).u() = u;
|
|
model->cm.face[i].WT(j).v() = v;
|
|
}
|
|
}
|
|
}
|
|
else if (selectedV)
|
|
{
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
for (unsigned j = 0; j < 3; j++)
|
|
{
|
|
if (areaUV.contains(QPointF(model->cm.face[i].WT(j).u(),model->cm.face[i].WT(j).v()))
|
|
&& model->cm.face[i].V(j)->IsUserBit(selVertBit))
|
|
{
|
|
float u = origin.x() + (cosv * (model->cm.face[i].WT(j).u() - origin.x()) - sinv * (model->cm.face[i].WT(j).v() - origin.y()));
|
|
float v = origin.y() + (sinv * (model->cm.face[i].WT(j).u() - origin.x()) + cosv * (model->cm.face[i].WT(j).v() - origin.y()));
|
|
model->cm.face[i].WT(j).u() = u;
|
|
model->cm.face[i].WT(j).v() = v;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this->update();
|
|
emit UpdateModel();
|
|
}
|
|
}
|
|
|
|
void RenderArea::ScaleComponent(float percX, float percY)
|
|
{
|
|
// Scale the selected component. The origin is set to the clicked point
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
if (model->cm.face[i].WT(0).n() == textNum && selected && model->cm.face[i].IsUserBit(selBit))
|
|
for (unsigned j = 0; j < 3; j++)
|
|
{
|
|
float x = oScale.x() + (model->cm.face[i].WT(j).u() - oScale.x()) * percX;
|
|
float y = oScale.y() + (model->cm.face[i].WT(j).v() - oScale.y()) * percY;
|
|
model->cm.face[i].WT(j).u() = x;
|
|
model->cm.face[i].WT(j).v() = y;
|
|
}
|
|
}
|
|
this->update();
|
|
emit UpdateModel();
|
|
}
|
|
|
|
void RenderArea::UpdateUV()
|
|
{
|
|
// After a move of component, re-calculate the new UV coordinates
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
if (model->cm.face[i].WT(0).n() == textNum && model->cm.face[i].IsUserBit(selBit))
|
|
{
|
|
for (unsigned j = 0; j < 3; j++)
|
|
{
|
|
model->cm.face[i].WT(j).u() = model->cm.face[i].WT(j).u() - (float)panX/(AREADIM*zoom);
|
|
model->cm.face[i].WT(j).v() = model->cm.face[i].WT(j).v() + (float)panY/(AREADIM*zoom);
|
|
}
|
|
}
|
|
}
|
|
panX = 0; panY = 0; tpanX = 0; tpanY = 0; oldPX = 0; oldPY = 0;
|
|
this->update();
|
|
emit UpdateModel();
|
|
}
|
|
|
|
void RenderArea::UpdateVertex()
|
|
{
|
|
// After a move of vertex, re-calculate the new UV coordinates
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
for (unsigned j = 0; j < 3; j++)
|
|
{
|
|
if (areaUV.contains(QPointF(model->cm.face[i].WT(j).u(),model->cm.face[i].WT(j).v()))
|
|
&& model->cm.face[i].V(j)->IsUserBit(selVertBit))
|
|
{
|
|
model->cm.face[i].WT(j).u() = model->cm.face[i].WT(j).u() - (float)posVX/(AREADIM*zoom);
|
|
model->cm.face[i].WT(j).v() = model->cm.face[i].WT(j).v() + (float)posVY/(AREADIM*zoom);
|
|
}
|
|
}
|
|
}
|
|
areaUV.moveCenter(QPointF(areaUV.center().x() - (float)posVX/(AREADIM*zoom), areaUV.center().y() + (float)posVY/(AREADIM*zoom)));
|
|
tpanX = 0; tpanY = 0; posVX = 0; posVY = 0;
|
|
this->update();
|
|
emit UpdateModel();
|
|
}
|
|
|
|
void RenderArea::ResetTrack(bool resetViewPort)
|
|
{
|
|
// Reset the viewport of the trackball
|
|
tb->center = Point3f(0, 0, 0);
|
|
tb->track.SetScale(1);
|
|
if (resetViewPort) viewport = Point2f(0,0);
|
|
oldX = 0; oldY = 0;
|
|
tb->track.SetTranslate(Point3f(viewport.X(), viewport.Y(), 1));
|
|
}
|
|
|
|
void RenderArea::SelectFaces()
|
|
{
|
|
// Check if a face is inside the rectangle of selection and mark it
|
|
selStart = QPoint(MAX,MAX);
|
|
selEnd = QPoint(-MAX,-MAX);
|
|
selected = false;
|
|
selection = QRect();
|
|
CMeshO::FaceIterator fi;
|
|
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
|
|
{
|
|
if ((*fi).WT(0).n() == textNum)
|
|
{
|
|
(*fi).ClearUserBit(selBit);
|
|
QVector<QPoint> t = QVector<QPoint>();
|
|
t.push_back(ToScreenSpace((*fi).WT(0).u(), (*fi).WT(0).v()));
|
|
t.push_back(ToScreenSpace((*fi).WT(1).u(), (*fi).WT(1).v()));
|
|
t.push_back(ToScreenSpace((*fi).WT(2).u(), (*fi).WT(2).v()));
|
|
QRegion r = QRegion(QPolygon(t));
|
|
if (r.intersects(area))
|
|
{
|
|
(*fi).SetUserBit(selBit);
|
|
UpdateBoundingArea(r.boundingRect().topLeft(), r.boundingRect().bottomRight());
|
|
if (!selected) selected = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderArea::SelectVertexes()
|
|
{
|
|
// Check if a vertex is inside the rectangle of selection
|
|
selStart = QPoint(MAX,MAX);
|
|
selEnd = QPoint(-MAX,-MAX);
|
|
selectedV = false;
|
|
selection = QRect();
|
|
QPointF a = ToUVSpace(area.x(), area.y());
|
|
QPointF b = ToUVSpace(area.bottomRight().x(),area.bottomRight().y());
|
|
areaUV = QRectF(a, QSizeF(b.x()-a.x(), b.y()-a.y()));
|
|
CMeshO::FaceIterator fi;
|
|
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
|
|
{
|
|
if ((*fi).WT(0).n() == textNum)
|
|
{
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
QPoint tmp = ToScreenSpace((*fi).WT(j).u(), (*fi).WT(j).v());
|
|
if (area.contains(tmp))
|
|
{
|
|
(*fi).V(j)->SetUserBit(selVertBit);
|
|
UpdateBoundingArea(tmp, tmp);
|
|
if (!selectedV) selectedV = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderArea::SelectConnectedComponent(QPoint e)
|
|
{
|
|
// Select a series of faces with the same UV coord on the edge
|
|
selStart = QPoint(MAX,MAX);
|
|
selEnd = QPoint(-MAX,-MAX);
|
|
selected = false;
|
|
selBit = CFaceO::NewBitFlag();
|
|
int index = 0;
|
|
vector<CFaceO*> Q = vector<CFaceO*>();
|
|
|
|
// Search the clicked face
|
|
for(unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
if (model->cm.face[i].WT(0).n() == textNum)
|
|
{
|
|
QVector<QPoint> t = QVector<QPoint>();
|
|
t.push_back(ToScreenSpace(model->cm.face[i].WT(0).u(), model->cm.face[i].WT(0).v()));
|
|
t.push_back(ToScreenSpace(model->cm.face[i].WT(1).u(), model->cm.face[i].WT(1).v()));
|
|
t.push_back(ToScreenSpace(model->cm.face[i].WT(2).u(), model->cm.face[i].WT(2).v()));
|
|
QRegion r = QRegion(QPolygon(t));
|
|
if (r.contains(e))
|
|
{
|
|
Q.push_back(&model->cm.face[i]);
|
|
model->cm.face[i].SetUserBit(selBit);
|
|
UpdateBoundingArea(r.boundingRect().topLeft(), r.boundingRect().bottomRight());
|
|
selected = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (index < Q.size())
|
|
{
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
CFaceO* p = Q[index]->FFp(j);
|
|
if (!p->IsUserBit(selBit) && (
|
|
(Q[index]->WT(0) == p->WT(0) || Q[index]->WT(0) == p->WT(1) || Q[index]->WT(0) == p->WT(2)) ||
|
|
(Q[index]->WT(1) == p->WT(0) || Q[index]->WT(1) == p->WT(1) || Q[index]->WT(1) == p->WT(2)) ||
|
|
(Q[index]->WT(2) == p->WT(0) || Q[index]->WT(2) == p->WT(1) || Q[index]->WT(2) == p->WT(2))))
|
|
{
|
|
p->SetUserBit(selBit);
|
|
Q.push_back(p);
|
|
QPoint tmp = ToScreenSpace(p->WT(j).u(), p->WT(j).v());
|
|
UpdateBoundingArea(tmp, tmp);
|
|
}
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
|
|
void RenderArea::ClearSelection()
|
|
{
|
|
// Clear every selection
|
|
selBit = CFaceO::NewBitFlag();
|
|
selVertBit = CVertexO::NewBitFlag();
|
|
selection = QRect();
|
|
}
|
|
|
|
void RenderArea::InvertSelection()
|
|
{
|
|
// Invert selected faces
|
|
if (selected)
|
|
{
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
if (model->cm.face[i].WT(0).n() == textNum)
|
|
{
|
|
if (model->cm.face[i].IsUserBit(selBit)) model->cm.face[i].ClearUserBit(selBit);
|
|
else model->cm.face[i].SetUserBit(selBit);
|
|
}
|
|
}
|
|
RecalculateSelectionArea();
|
|
originR.moveCenter(selection.center());
|
|
origin = ToUVSpace(originR.center().x(), originR.center().y());
|
|
this->update();
|
|
}
|
|
else if (selectedV)
|
|
{
|
|
for (unsigned i = 0; i < model->cm.vert.size(); i++)
|
|
{
|
|
if (model->cm.vert[i].IsUserBit(selVertBit)) model->cm.vert[i].ClearUserBit(selVertBit);
|
|
else model->cm.vert[i].SetUserBit(selVertBit);
|
|
}
|
|
UpdateVertexSelection();
|
|
this->update();
|
|
}
|
|
}
|
|
|
|
void RenderArea::Flip(bool mode)
|
|
{
|
|
if (selected)
|
|
{
|
|
QPointF mid = ToUVSpace(selection.center().x(), selection.center().y());
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
if (model->cm.face[i].WT(0).n() == textNum)
|
|
{
|
|
if (model->cm.face[i].IsUserBit(selBit))
|
|
{
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
if (mode) model->cm.face[i].WT(j).u() = 2.0f * mid.x() - model->cm.face[i].WT(j).u();
|
|
else model->cm.face[i].WT(j).v() = 2.0f * mid.y() - model->cm.face[i].WT(j).v();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
RecalculateSelectionArea();
|
|
this->update();
|
|
}
|
|
}
|
|
|
|
void RenderArea::UnifyCouple()
|
|
{
|
|
// Calculate the average coordinates and unify a couple of vertexes
|
|
if (VCount == 2)
|
|
{
|
|
float tu = (vc1.u() + vc2.u())/2.0;
|
|
float tv = (vc1.v() + vc2.v())/2.0;
|
|
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
for (unsigned j = 0; j < 3; j++)
|
|
{
|
|
if (model->cm.face[i].V(j) == collapse1 || model->cm.face[i].V(j) == collapse2)
|
|
{
|
|
model->cm.face[i].WT(j).u() = tu;
|
|
model->cm.face[i].WT(j).v() = tv;
|
|
}
|
|
}
|
|
}
|
|
selectedV = false;
|
|
selVertBit = CVertexO::NewBitFlag();
|
|
areaUV = QRectF();
|
|
selection = QRect();
|
|
this->ChangeMode(2);
|
|
this->update();
|
|
emit UpdateModel();
|
|
}
|
|
}
|
|
|
|
void RenderArea::UnifySet()
|
|
{
|
|
// Unify a set of vertexes
|
|
// <------
|
|
|
|
}
|
|
|
|
void RenderArea::HandleScale(QPoint e)
|
|
{
|
|
// Move the rectangle of scaling and resize the selction area
|
|
int tx = rectX - tpanX + e.x();
|
|
int ty = rectY - tpanY + e.y();
|
|
switch(highlighted)
|
|
{
|
|
case 0: // Top Left
|
|
if (tx > selection.x() + selection.width() - RECTDIM) tx = selection.x() + selection.width() - RECTDIM;
|
|
if (ty > selection.y() + selection.height() - RECTDIM) ty = selection.y() + selection.height() - RECTDIM;
|
|
selRect[0].moveCenter(QPoint(tx, ty));
|
|
//selRect[2].moveCenter(QPoint(tx, selRect[2].center().y())); // THERE IS A BUG IN QT: movecenter doesn't work
|
|
//selRect[1].moveCenter(QPoint(selRect[1].center().x(),ty)); if coords are negative.......
|
|
selRect[2] = QRect(tx - RECTDIM/2, selRect[2].y(), RECTDIM, RECTDIM);
|
|
selRect[1] = QRect(selRect[1].x(), ty - RECTDIM/2, RECTDIM, RECTDIM);
|
|
selection.setTopLeft(selRect[0].center());
|
|
selection.setBottomLeft(selRect[2].center());
|
|
selection.setTopRight(selRect[1].center());
|
|
this->update(selRect[1]);
|
|
break;
|
|
case 1: // Top Right
|
|
if (tx < selection.x() + RECTDIM) tx = selection.x() + RECTDIM;
|
|
if (ty > selection.y() + selection.height() - RECTDIM) ty = selection.y() + selection.height() - RECTDIM;
|
|
selRect[1].moveCenter(QPoint(tx, ty));
|
|
//selRect[3].moveCenter(QPoint(tx, selRect[3].center().y()));
|
|
//selRect[0].moveCenter(QPoint(selRect[0].center().x(), ty));
|
|
selRect[3] = QRect(tx - RECTDIM/2, selRect[3].y(), RECTDIM, RECTDIM);
|
|
selRect[0] = QRect(selRect[0].x(), ty - RECTDIM/2, RECTDIM, RECTDIM);
|
|
selection.setTopRight(selRect[1].center());
|
|
selection.setTopLeft(selRect[0].center());
|
|
selection.setBottomRight(selRect[3].center());
|
|
this->update(selRect[0]);
|
|
break;
|
|
case 2: // Bottom Left
|
|
if (tx > selection.x() + selection.width() - RECTDIM) tx = selection.x() + selection.width() - RECTDIM;
|
|
if (ty < selection.y() + RECTDIM) ty = selection.y() + RECTDIM;
|
|
selRect[2].moveCenter(QPoint(tx, ty));
|
|
//selRect[0].moveCenter(QPoint(tx, selRect[0].center().y()));
|
|
//selRect[3].moveCenter(QPoint(selRect[3].center().x(), ty));
|
|
selRect[0] = QRect(tx - RECTDIM/2, selRect[0].y(), RECTDIM, RECTDIM);
|
|
selRect[3] = QRect(selRect[3].x(), ty - RECTDIM/2, RECTDIM, RECTDIM);
|
|
selection.setTopLeft(selRect[0].center());
|
|
selection.setBottomLeft(selRect[2].center());
|
|
selection.setBottomRight(selRect[3].center());
|
|
this->update(selRect[3]);
|
|
break;
|
|
case 3: // Bottom Right
|
|
if (tx < selection.x() + RECTDIM) tx = selection.x() + RECTDIM;
|
|
if (ty < selection.y() + RECTDIM) ty = selection.y() + RECTDIM;
|
|
selRect[3].moveCenter(QPoint(tx, ty));
|
|
//selRect[1].moveCenter(QPoint(tx, selRect[1].center().y()));
|
|
//selRect[2].moveCenter(QPoint(selRect[2].center().x(), ty));
|
|
selRect[1] = QRect(tx - RECTDIM/2, selRect[1].y(), RECTDIM, RECTDIM);
|
|
selRect[2] = QRect(selRect[2].x(), ty - RECTDIM/2, RECTDIM, RECTDIM);
|
|
selection.setTopRight(selRect[1].center());
|
|
selection.setBottomLeft(selRect[2].center());
|
|
selection.setBottomRight(selRect[3].center());
|
|
this->update(selRect[2]);
|
|
break;
|
|
}
|
|
this->update(selRect[highlighted]);
|
|
this->update(selRect[(highlighted+2)%selRect.size()]);
|
|
originR.moveCenter(selection.center());
|
|
origin = ToUVSpace(originR.center().x(), originR.center().y());
|
|
// calculate scaling
|
|
scaleX = (float)selection.width() / oldSRX;
|
|
scaleY = (float)selection.height() / oldSRY;
|
|
|
|
this->update(selection);
|
|
}
|
|
|
|
void RenderArea::HandleRotate(QPoint e)
|
|
{
|
|
// Calculate the angle of rotazion
|
|
float A2 = (e.x() - originR.center().x())*(e.x() - originR.center().x()) + (e.y() - originR.center().y())*(e.y() - originR.center().y());
|
|
float C2 = (rectX - e.x())*(rectX - e.x()) + (rectY - e.y()) * (rectY -e.y());
|
|
degree = acos((C2 - A2 - B2) / (-2*sqrt(A2)*sqrt(B2)));
|
|
float ny = (float) Rm * e.x() + Rq;
|
|
switch(highlighted)
|
|
{
|
|
case 0:
|
|
if (ny > e.y()) degree = -degree;
|
|
break;
|
|
case 1:
|
|
if (ny < e.y())
|
|
degree = -degree;
|
|
break;
|
|
case 2:
|
|
if (ny > e.y()) degree = -degree;
|
|
break;
|
|
case 3:
|
|
if (ny < e.y()) degree = -degree;
|
|
break;
|
|
}
|
|
this->update();
|
|
}
|
|
|
|
void RenderArea::RecalculateSelectionArea()
|
|
{
|
|
// Find the new size of the selection rectangle after a rotation or a scale
|
|
selStart = QPoint(MAX,MAX);
|
|
selEnd = QPoint(-MAX,-MAX);
|
|
CMeshO::FaceIterator fi;
|
|
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
|
|
{
|
|
if ((*fi).IsUserBit(selBit))
|
|
{
|
|
QVector<QPoint> t = QVector<QPoint>();
|
|
t.push_back(ToScreenSpace((*fi).WT(0).u(), (*fi).WT(0).v()));
|
|
t.push_back(ToScreenSpace((*fi).WT(1).u(), (*fi).WT(1).v()));
|
|
t.push_back(ToScreenSpace((*fi).WT(2).u(), (*fi).WT(2).v()));
|
|
QRegion r = QRegion(QPolygon(t));
|
|
UpdateBoundingArea(r.boundingRect().topLeft(), r.boundingRect().bottomRight());
|
|
}
|
|
}
|
|
if (selected)
|
|
{
|
|
selection = QRect(selStart, selEnd);
|
|
UpdateSelectionArea(0,0);
|
|
}
|
|
}
|
|
|
|
void RenderArea::UpdateSelectionArea(int x, int y)
|
|
{
|
|
// Update the buttons of the selection area
|
|
selection.moveCenter(QPoint(selection.center().x() + x, selection.center().y() + y));
|
|
selRect[0].moveCenter(selection.topLeft());
|
|
selRect[1].moveCenter(selection.topRight());
|
|
selRect[2].moveCenter(selection.bottomLeft());
|
|
selRect[3].moveCenter(selection.bottomRight());
|
|
}
|
|
|
|
void RenderArea::UpdateSelectionAreaV(int x, int y)
|
|
{
|
|
// Update the buttons of the selection area for vertexes
|
|
selection.moveCenter(QPoint(selection.center().x() + x, selection.center().y() + y));
|
|
selRect[0].moveBottomRight(selection.topLeft());
|
|
selRect[1].moveBottomLeft(selection.topRight());
|
|
selRect[2].moveTopRight(selection.bottomLeft());
|
|
selRect[3].moveTopLeft(selection.bottomRight());
|
|
}
|
|
|
|
void RenderArea::UpdateVertexSelection()
|
|
{
|
|
// Recalcultate the rectangle for selection of vertexes
|
|
selStart = QPoint(MAX,MAX);
|
|
selEnd = QPoint(-MAX,-MAX);
|
|
selectedV = false;
|
|
selection = QRect();
|
|
CMeshO::FaceIterator fi;
|
|
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
|
|
{
|
|
if ((*fi).WT(0).n() == textNum)
|
|
{
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
QPoint tmp = ToScreenSpace((*fi).WT(j).u(), (*fi).WT(j).v());
|
|
if ((*fi).V(j)->IsUserBit(selVertBit))
|
|
{
|
|
UpdateBoundingArea(tmp,tmp);
|
|
if (!selectedV) selectedV = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
selection = QRect(QPoint(selStart.x() - VRADIUS, selStart.y() - VRADIUS), QPoint(selEnd.x() + VRADIUS, selEnd.y() + VRADIUS));
|
|
QPointF a = ToUVSpace(selection.x(), selection.y());
|
|
QPointF b = ToUVSpace(selection.bottomRight().x(),selection.bottomRight().y());
|
|
areaUV = QRectF(a, QSizeF(b.x()-a.x(), b.y()-a.y()));
|
|
}
|
|
|
|
QPointF RenderArea::ToUVSpace(int x, int y)
|
|
{
|
|
// Convert a point from screen-space to uv-space
|
|
return QPointF((float)(x - viewport.X()*zoom)/(AREADIM*zoom), (float)(AREADIM*zoom - y + viewport.Y()*zoom)/(AREADIM*zoom));
|
|
}
|
|
|
|
QPoint RenderArea::ToScreenSpace(float u, float v)
|
|
{
|
|
// Convert a point from uv-space to screen space
|
|
return QPoint(u * AREADIM*zoom + viewport.X()*zoom, AREADIM*zoom - (v * AREADIM*zoom) + viewport.Y()*zoom);
|
|
}
|
|
|
|
void RenderArea::DrawCircle(QPoint origin)
|
|
{
|
|
// Draw a circle
|
|
float DEG2RAD = 3.14159f/180.0f;
|
|
float r = (float)VRADIUS/zoom;
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
for (int i = 0; i < 360; i++)
|
|
{
|
|
float degInRad = i*DEG2RAD;
|
|
glVertex3f(origin.x() + cos(degInRad)*r,origin.y() + sin(degInRad)*r,2.0f);
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
void RenderArea::UpdateBoundingArea(QPoint topLeft, QPoint topRight)
|
|
{
|
|
// Update the bounding box (selection rectangle) of the selected faces/vertexes
|
|
if (topLeft.x() < selStart.x()) selStart.setX(topLeft.x());
|
|
if (topLeft.y() < selStart.y()) selStart.setY(topLeft.y());
|
|
if (topRight.x() > selEnd.x()) selEnd.setX(topRight.x());
|
|
if (topRight.y() > selEnd.y()) selEnd.setY(topRight.y());
|
|
}
|
|
|
|
void RenderArea::ImportSelection()
|
|
{
|
|
selBit = CFaceO::NewBitFlag();
|
|
selStart = QPoint(MAX,MAX);
|
|
selEnd = QPoint(-MAX,-MAX);
|
|
CMeshO::FaceIterator fi;
|
|
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
|
|
{
|
|
if ((*fi).IsS())
|
|
{
|
|
if (!selected) selected = true;
|
|
(*fi).SetUserBit(selBit);
|
|
QVector<QPoint> t = QVector<QPoint>();
|
|
t.push_back(ToScreenSpace((*fi).WT(0).u(), (*fi).WT(0).v()));
|
|
t.push_back(ToScreenSpace((*fi).WT(1).u(), (*fi).WT(1).v()));
|
|
t.push_back(ToScreenSpace((*fi).WT(2).u(), (*fi).WT(2).v()));
|
|
QRegion r = QRegion(QPolygon(t));
|
|
UpdateBoundingArea(r.boundingRect().topLeft(), r.boundingRect().bottomRight());
|
|
}
|
|
}
|
|
if (selected)
|
|
{
|
|
selection = QRect(selStart, selEnd);
|
|
UpdateSelectionArea(0,0);
|
|
originR.moveCenter(ToScreenSpace(origin.x(), origin.y()));
|
|
origin = ToUVSpace(originR.center().x(), originR.center().y());
|
|
}
|
|
ChangeMode(1);
|
|
this->update();
|
|
}
|
|
|
|
void RenderArea::CountVertexes()
|
|
{
|
|
// Count the number of selected UV vertexes (not so easy)
|
|
VCount = 0;
|
|
collapse1 = 0;
|
|
collapse2 = 0;
|
|
CMeshO::FaceIterator fi;
|
|
vector< TexCoord2<float> > tmpCoord = vector< TexCoord2<float> >();
|
|
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
|
|
{
|
|
if ((*fi).WT(0).n() == textNum)
|
|
{
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
if ((*fi).V(j)->IsUserBit(selVertBit))
|
|
{
|
|
if (!isInside(tmpCoord, (*fi).WT(j)) && areaUV.contains(QPointF((*fi).WT(j).u(), (*fi).WT(j).v())))
|
|
{
|
|
VCount++;
|
|
if (collapse1 == 0) {collapse1 = (*fi).V(j); vc1 = (*fi).WT(j); }
|
|
else if (collapse2 == 0) {collapse2 = (*fi).V(j); vc2 = (*fi).WT(j); }
|
|
tmpCoord.push_back((*fi).WT(j));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool RenderArea::isInside(vector<TexCoord2<float> > tmpCoord, TexCoord2<float> act)
|
|
{
|
|
// Support function for search in a vector
|
|
for (unsigned i = 0; i < tmpCoord.size(); i++)
|
|
{
|
|
if (tmpCoord[i] == act) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void RenderArea::ShowFaces()
|
|
{
|
|
// Set up model for display the selected faces
|
|
for (unsigned i = 0; i < model->cm.face.size(); i++)
|
|
{
|
|
if (model->cm.face[i].IsUserBit(selBit)) model->cm.face[i].SetS();
|
|
else model->cm.face[i].ClearS();
|
|
}
|
|
}
|
|
|
|
void RenderArea::ResetPosition()
|
|
{
|
|
// Reset the position of the viewport
|
|
zoom = 1;
|
|
ResetTrack(true);
|
|
if (selected) RecalculateSelectionArea();
|
|
else if (selectedV) UpdateVertexSelection();
|
|
this->update();
|
|
} |