meshlab/src/fgt/edit_texture/renderarea.cpp

414 lines
11 KiB
C++

#include <QtGui>
#include "renderarea.h"
#include "textureeditor.h"
#include <wrap/qt/trackball.h>
#include <math.h>
#include <stdlib.h>
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 = Point2f(0,0);
tb = new Trackball();
tb->center = Point3f(0, 0, 0);
tb->radius = 1;
panX = 0; panY = 0;
oldPX = 0; oldPY = 0;
brush = QBrush(Qt::green);
mode = View;
editMode = Move;
origin = QPoint();
this->setMouseTracking(true);
this->setCursor(Qt::PointingHandCursor);
this->setAttribute(Qt::WA_NoSystemBackground);
}
RenderArea::~RenderArea(){}
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)); // <--- customizzabile???
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 (image != QImage())
{
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_XOR);
glEnable(GL_DEPTH_TEST);
glColor3f(1,1,1);
glLineWidth(2);
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
// First draw the model in u,v space
if (model->cm.face[i].IsS() && 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--;
glBegin(GL_LINE_LOOP);
glVertex3f(model->cm.face[i].WT(0).u() * AREADIM - panX, AREADIM - (model->cm.face[i].WT(0).v() * AREADIM) - panY, 1);
glVertex3f(model->cm.face[i].WT(1).u() * AREADIM - panX, AREADIM - (model->cm.face[i].WT(1).v() * AREADIM) - panY, 1);
glVertex3f(model->cm.face[i].WT(2).u() * AREADIM - panX, AREADIM - (model->cm.face[i].WT(2).v() * AREADIM) - panY, 1);
glEnd();
}
}
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,AREADIM,AREADIM,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)
painter.drawLine(0,AREADIM,AREADIM,AREADIM);
painter.drawLine(0,AREADIM,0,0);
painter.drawText(TRANSLATE, AREADIM - TRANSLATE, QString("(%1,%2)").arg((float)-viewport.X()/AREADIM).arg((float)viewport.Y()/AREADIM));
painter.drawText(TRANSLATE, TRANSLATE*3, QString("(%1,%2)").arg((float)-viewport.X()/AREADIM).arg((float)viewport.Y()/AREADIM + 1));
painter.drawText(AREADIM - TRANSLATE*18, AREADIM - TRANSLATE, QString("(%1,%2)").arg((float)-(viewport.X()/AREADIM) + 1).arg((float)viewport.Y()/AREADIM));
painter.drawText(TRANSLATE, TRANSLATE*6, QString("V"));
painter.drawText(AREADIM - TRANSLATE*23, AREADIM - TRANSLATE, QString("U"));
// and the origin of the scale and rotation
if (origin != QPoint())
{
painter.setPen(QPen(QBrush(Qt::black),1));
painter.setBrush(QBrush(Qt::yellow));
painter.drawEllipse(originR);
}
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.drawRect(QRect(0, 0, width()-1, height()-1));
painter.end();
}
// Mouse Event:
void RenderArea::mousePressEvent(QMouseEvent *e)
{
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:
switch(editMode)
{
case Move:
tpanX = e->x();
tpanY = e->y();
break;
case Choose:
origin = QPointF((float)(e->x() - viewport.X())/AREADIM, (float)(AREADIM - e->y() + viewport.Y())/AREADIM);
originR = QRect(e->x()-RADIUS/2, e->y()-RADIUS/2, RADIUS, RADIUS);
this->update(originR);
break;
}
break;
}
}
void RenderArea::mouseReleaseEvent(QMouseEvent *e)
{
switch(mode)
{
case View:
tb->MouseUp(e->x(), AREADIM-e->y(), QT2VCG(e->button(), e->modifiers()));
this->update();
break;
case Edit:
oldPX = panX;
oldPY = panY;
UpdateUV();
break;
}
}
void RenderArea::mouseMoveEvent(QMouseEvent *e)
{
if((e->buttons() & Qt::LeftButton)) // <---- Se non ci sono facce selezionate -> non si fa nulla
{
switch(mode)
{
case View:
tb->track.SetTranslate(Point3f(tmpX + oldX - e->x(), tmpY + oldY - e->y(), 0));
viewport = Point2f(tmpX + oldX - e->x(), tmpY + oldY - e->y());
this->update();
break;
case Edit:
if (editMode == Move)
{
panX = oldPX + tpanX - e->x();
panY = oldPY + tpanY - e->y();
this->update();
}
break;
}
}
}
void RenderArea::mouseDoubleClickEvent(QMouseEvent *)
{
ResetTrack();
// <--- reset dello zoom
this->update();
}
void RenderArea::wheelEvent(QWheelEvent*e)
{
switch(mode)
{
case View:
// Zoom
float WHEEL_STEP = 120.0f;
float notch = (float)e->delta()/WHEEL_STEP;
tb->MouseWheel(notch, QTWheel2VCG(e->modifiers()));
tb->track.SetScale(notch); // <---- ???? parametro ????
this->update();
break;
}
}
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)
{
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();
this->update();
emit UpdateStat(0,0,0,0,0); // <--------
}
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)
{
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();
this->update();
emit UpdateStat(0,0,0,0,0); // <--------
}
void RenderArea::ChangeMode(int index)
{
// Change the selection mode
origin = QPoint();
switch(index)
{
case 0:
if (mode != View)
{
mode = View;
this->setCursor(Qt::PointingHandCursor);
}
break;
case 1:
if (mode != Edit)
{
mode = Edit;
this->setCursor(QCursor(QBitmap(":/images/sel_move.png")));
}
break;
case 2:
if (mode != Select)
{
mode = Select;
this->setCursor(Qt::CrossCursor);
}
break;
default:
this->setCursor(Qt::ArrowCursor);
break;
}
this->update();
}
void RenderArea::ChangeEditMode(int index)
{
// Change the function of the mouse press
if (index == 0) editMode = Move;
else editMode = Choose;
}
void RenderArea::RotateComponent(float alfa)
{
// 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 theta = alfa * 3.14159f / 180.0f; // Convert degree to radiant. PI is a finite number -> lost of precision
float sinv = sin(theta);
float cosv = cos(theta);
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
if (model->cm.face[i].WT(0).n() == textNum)
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;
}
}
this->update();
emit UpdateStat(0,0,0,0,0); // <--------
}
}
void RenderArea::ScaleComponent(int perc)
{
// Scale the selected component. The origin is set to the clicked point
if (origin != QPoint())
{
float p = (float) perc / 100.0f;
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
if (model->cm.face[i].WT(0).n() == textNum)
for (unsigned j = 0; j < 3; j++)
{
float x = origin.x() + (model->cm.face[i].WT(j).u() - origin.x()) * p;
float y = origin.y() + (model->cm.face[i].WT(j).v() - origin.y()) * p;
model->cm.face[i].WT(j).u() = x;
model->cm.face[i].WT(j).v() = y;
}
}
}
this->update();
emit UpdateStat(0,0,0,0,0);
}
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)
{
for (unsigned j = 0; j < 3; j++)
{
model->cm.face[i].WT(j).u() = model->cm.face[i].WT(j).u() - (float)panX/AREADIM;
model->cm.face[i].WT(j).v() = model->cm.face[i].WT(j).v() + (float)panY/AREADIM;
}
}
}
panX = 0; panY = 0; tpanX = 0; tpanY = 0; oldPX = 0; oldPY = 0;
this->update();
emit UpdateStat(0,0,0,0,0); // <--------
}
void RenderArea::ResetTrack()
{
// Reset the center of the trackball
tb->center = Point3f(0, 0, 0);
viewport = Point2f(0,0);
oldX = 0; oldY = 0;
tb->track.SetTranslate(Point3f(0,0,0));
}