1 /****************************************************************************
2 * MeshLab o o *
3 * An extendible mesh processor o o *
4 * _ O _ *
5 * Copyright(C) 2005, 2009 \/)\/ *
6 * Visual Computing Lab /\/| *
7 * ISTI - Italian National Research Council | *
8 * \ *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20 * for more details. *
21 * *
22 ****************************************************************************/
23
24 #include <common/interfaces.h>
25 #include <meshlab/glarea.h>
26 #include "edittexture.h"
27 #include "renderarea.h"
28 #include <wrap/gl/pick.h>
29 #include <wrap/gl/picking.h>
30
31 #include <vcg/complex/algorithms/clean.h>
32 #include <QDockWidget>
33
34 using namespace vcg;
35
EditTexturePlugin()36 EditTexturePlugin::EditTexturePlugin()
37 {
38 isDragging = false;
39 widget = 0;
40 qFont.setFamily("Helvetica");
41 qFont.setPixelSize(14);
42 }
43
~EditTexturePlugin()44 EditTexturePlugin::~EditTexturePlugin()
45 {
46 // Delete the tool widget
47 if (widget != 0)
48 {
49 delete widget;
50 widget = 0;
51 }
52 }
53
Info()54 const QString EditTexturePlugin::Info()
55 {
56 return tr("Edit texture coordinates of the selected area");
57 }
58
mousePressEvent(QMouseEvent * event,MeshModel & m,GLArea * gla)59 void EditTexturePlugin::mousePressEvent(QMouseEvent * event, MeshModel &m, GLArea * gla)
60 {
61 isDragging = true;
62
63 if(event->modifiers() == Qt::ControlModifier) selMode = SMAdd;
64 else if(event->modifiers() == Qt::ShiftModifier) selMode = SMSub;
65 else selMode = SMClear;
66 // Change the appearance of the cursor
67 switch(selMode)
68 {
69 case SMAdd: // CTRL + Mouse
70 gla->setCursor(QCursor(QPixmap(":/images/sel_rect_plus.png"),1,1));
71 break;
72 case SMSub: // SHIFT + Mouse
73 gla->setCursor(QCursor(QPixmap(":/images/sel_rect_minus.png"),1,1));
74 break;
75 case SMClear: // Mouse
76 gla->setCursor(QCursor(QPixmap(":/images/sel_rect.png"),1,1));
77 for (unsigned i = 0; i < FaceSel.size(); i++) FaceSel[i]->ClearS();
78 FaceSel.clear();
79 break;
80 }
81 if(event->modifiers() == Qt::ControlModifier || event->modifiers() == Qt::ShiftModifier )
82 {
83 CMeshO::FaceIterator fi;
84 for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)
85 if(!(*fi).IsD() && (*fi).IsS()) FaceSel.push_back(&*fi);
86 }
87
88 start = event->pos();
89 cur = start;
90 gla->update();
91 return;
92 }
93
mouseMoveEvent(QMouseEvent * event,MeshModel &,GLArea * gla)94 void EditTexturePlugin::mouseMoveEvent(QMouseEvent * event, MeshModel &/*m*/, GLArea * gla)
95 {
96 prev = cur;
97 cur = event->pos();
98 /*int curT;
99 static int lastRendering;
100 if (isDragging)
101 {
102 // The user is selecting an area: management of the update
103 lastRendering = clock();
104 curT = clock();
105 if(gla->lastRenderingTime() < 50 || (curT - lastRendering) > 1000 )
106 {
107 lastRendering = curT;
108 gla->update();
109 }
110 else
111 {
112 gla->makeCurrent();
113 glDrawBuffer(GL_FRONT);
114 DrawXORRect(gla);
115 glDrawBuffer(GL_BACK);
116 glFlush();
117 }
118 }*/
119 if(gla->lastRenderingTime() < 200 )
120 {
121 gla->update();
122 }
123 else
124 {
125 gla->makeCurrent();
126 glDrawBuffer(GL_FRONT);
127 DrawXORRect(gla);
128 glDrawBuffer(GL_BACK);
129 glFlush();
130 }
131 }
132
mouseReleaseEvent(QMouseEvent * event,MeshModel &,GLArea * gla)133 void EditTexturePlugin::mouseReleaseEvent(QMouseEvent * event, MeshModel &/*m*/, GLArea * gla)
134 {
135 prev = cur;
136 cur = event->pos();
137 gla->setCursor(QCursor(QPixmap(":/images/sel_rect.png"),1,1));
138 if (isDragging)
139 {
140 widget->SelectFromModel();
141 isDragging = false;
142 }
143 gla->update();
144 }
145
Decorate(MeshModel & m,GLArea * gla)146 void EditTexturePlugin::Decorate(MeshModel &m, GLArea *gla)
147 {
148 if (isDragging)
149 {
150 QPoint mid, wid;
151 vector<CMeshO::FacePointer> NewFaceSel;
152 vector<CMeshO::FacePointer>::iterator fpi;
153 CMeshO::FaceIterator fi;
154
155 DrawXORRect(gla);
156 mid = (start + cur)/2;
157 mid.setY(gla->height() - mid.y());
158 wid = (start - cur);
159 if(wid.x()<0) wid.setX(-wid.x());
160 if(wid.y()<0) wid.setY(-wid.y());
161
162 for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)
163 if(!(*fi).IsD()) (*fi).ClearS();
164
165 glPushMatrix();
166 glMultMatrix(m.cm.Tr);
167 GLPickTri<CMeshO>::PickFace(mid.x(), mid.y(), m.cm, NewFaceSel, wid.x(), wid.y());
168 glPopMatrix();
169
170 switch(selMode)
171 {
172 case SMSub:
173 for(fpi = FaceSel.begin(); fpi != FaceSel.end(); ++fpi)
174 (*fpi)->SetS();
175 for(fpi = NewFaceSel.begin(); fpi != NewFaceSel.end(); ++fpi)
176 (*fpi)->ClearS();
177 break;
178 case SMAdd:
179 for(fpi = FaceSel.begin(); fpi != FaceSel.end(); ++fpi)
180 (*fpi)->SetS();
181 case SMClear:
182 for(fpi = NewFaceSel.begin(); fpi != NewFaceSel.end(); ++fpi)
183 (*fpi)->SetS();
184 break;
185 }
186 }
187 }
188
StartEdit(MeshModel & m,GLArea * gla)189 bool EditTexturePlugin::StartEdit(MeshModel &m, GLArea *gla )
190 {
191 // Set up the model
192 //m.cm.face.EnableFFAdjacency();
193 m.updateDataMask(MeshModel::MM_FACEFACETOPO);
194
195 if (m.cm.textures.size() == 0)
196 {
197 QMessageBox::warning(gla->window(), "Texture Parametrization Tool",
198 "Sorry, this mesh has no texture.",
199 QMessageBox::Ok, QMessageBox::Ok);
200 return false;
201 }
202
203 if (vcg::tri::HasPerWedgeTexCoord(m.cm))
204 {
205 vcg::tri::UpdateTopology<CMeshO>::FaceFaceFromTexCoord(m.cm);
206 if(vcg::tri::Clean<CMeshO>::HasConsistentPerWedgeTexCoord(m.cm) && !HasCollapsedTextCoords(m)) degenerate = false;
207 else
208 {
209 this->Log(GLLogStream::WARNING,"This mesh has a degenerated texture parametrization!");
210 degenerate = true;
211 }
212 }
213
214 FaceSel.clear();
215 CMeshO::FaceIterator ff;
216 for(ff = m.cm.face.begin(); ff != m.cm.face.end(); ++ff)
217 if(!(*ff).IsD() && (*ff).IsS()) FaceSel.push_back(&*ff);
218
219 CMeshO::FaceIterator fi;
220 for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) (*fi).ClearS();
221
222 gla->setCursor(QCursor(QPixmap(":/images/sel_rect.png"),1,1));
223
224 connect(this, SIGNAL(setSelectionRendering(bool)),gla,SLOT(setSelectionRendering(bool)));
225 setSelectionRendering(true);
226
227 // Create an instance of the interface
228 if (widget == 0)
229 {
230 widget = new TextureEditor(gla->window(), &m, gla, degenerate);
231 dock = new QDockWidget(gla->window());
232 dock->setAllowedAreas(Qt::NoDockWidgetArea);
233 dock->setWidget(widget);
234 QPoint p = gla->window()->mapToGlobal(QPoint(0,0));
235 dock->setGeometry(-5+p.x()+gla->window()->width()-widget->width(),p.y(),widget->width(),widget->height());
236 dock->setFloating(true);
237 }
238 dock->setVisible(true);
239 dock->layout()->update();
240
241 // Initialize the texture using the intere model
242 InitTexture(m);
243
244 gla->update();
245 return true;
246 }
247
EndEdit(MeshModel & m,GLArea *)248 void EditTexturePlugin::EndEdit(MeshModel &m , GLArea * )
249 {
250 // Delete the widget
251 for (unsigned i = 0; i < m.cm.face.size(); i++) m.cm.face[i].ClearS();
252 if (widget != 0)
253 {
254 delete widget;
255 delete dock;
256 widget = 0;
257 dock = 0;
258 }
259 }
260
DrawXORRect(GLArea * gla)261 void EditTexturePlugin::DrawXORRect(GLArea *gla)
262 {
263 // Draw the rectangle of the selection area
264 glMatrixMode(GL_PROJECTION);
265 glPushMatrix();
266 glLoadIdentity();
267 glOrtho(0, gla->width(), gla->height(),0,-1,1);
268 glMatrixMode(GL_MODELVIEW);
269 glPushMatrix();
270 glLoadIdentity();
271 glPushAttrib(GL_ENABLE_BIT);
272 glDisable(GL_DEPTH_TEST);
273 glDisable(GL_LIGHTING);
274 glDisable(GL_TEXTURE_2D);
275 glEnable(GL_COLOR_LOGIC_OP);
276 glLogicOp(GL_XOR);
277 glColor3f(1,1,1);
278
279 glBegin(GL_LINE_LOOP);
280 glVertex2f(start.x(),start.y());
281 glVertex2f(cur.x(),start.y());
282 glVertex2f(cur.x(),cur.y());
283 glVertex2f(start.x(),cur.y());
284 glEnd();
285
286 glDisable(GL_LOGIC_OP);
287 glPopAttrib();
288 glPopMatrix();
289 glMatrixMode(GL_PROJECTION);
290 glPopMatrix();
291 glMatrixMode(GL_MODELVIEW);
292 }
293
InitTexture(MeshModel & m)294 void EditTexturePlugin::InitTexture(MeshModel &m)
295 {
296 // Get the textures name and add the tab
297 if (m.cm.textures.size() > 0)
298 {
299 for(unsigned i = 0; i < m.cm.textures.size(); i++)
300 widget->AddRenderArea(m.cm.textures[i].c_str(), &m, i);
301 }
302 else widget->AddEmptyRenderArea();
303 }
304
305
306 // DA METTERE IN Clean.h
307 /**
308 Check if the parametrization is valid
309 */
HasCollapsedTextCoords(MeshModel & m)310 bool EditTexturePlugin::HasCollapsedTextCoords(MeshModel &m)
311 {
312 if(!HasPerWedgeTexCoord(m.cm)) return true;
313 for (CMeshO::FaceIterator fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)
314 {
315 if(!(*fi).IsD())
316 {
317 if( (*fi).WT(0).P() == (*fi).WT(1).P() || (*fi).WT(0).P() == (*fi).WT(2).P() || (*fi).WT(1).P() == (*fi).WT(2).P())
318 return true;
319 }
320 }
321 return false;
322 }
323