1 /****************************************************************************
2  * MeshLab                                                           o o     *
3  * A versatile mesh processing toolbox                             o     o   *
4  *                                                                _   O  _   *
5  * Copyright(C) 2005                                                \/)\/    *
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 #include "edit_paint.h"
24 
25 #include <meshlab/glarea.h>
26 #include <vcg/math/perlin_noise.h>
27 
28 using namespace std;
29 using namespace vcg;
30 
EditPaintPlugin()31 EditPaintPlugin::EditPaintPlugin()
32 {
33 	zbuffer = NULL;
34 	color_buffer = NULL;
35 	clone_zbuffer = NULL;
36 	generateCircle(circle);
37 	generateCircle(dense_circle, 64);
38 	generateSquare(square);
39 	generateSquare(dense_square, 16);
40 }
41 
~EditPaintPlugin()42 EditPaintPlugin::~EditPaintPlugin() {}
43 
Info()44 const QString EditPaintPlugin::Info() {
45 	return tr("Improved Painting");
46 }
47 
StartEdit(MeshModel & m,GLArea * parent)48 bool EditPaintPlugin::StartEdit(MeshModel& m, GLArea * parent)
49 {
50 	dock = new QDockWidget(parent->window());
51 	paintbox = new Paintbox(dock);
52 	dock->setAllowedAreas(Qt::NoDockWidgetArea);
53 	dock->setWidget(paintbox);
54 	QPoint p=parent->mapToGlobal(QPoint(0,0));
55 	dock->setGeometry(5 + p.x(), p.y() + 5 , paintbox->width(), parent->height() - 10);
56 	dock->setFloating(true);
57 	dock->setVisible(true);
58 
59 	tri::UpdateBounding<CMeshO>::Box(m.cm);
60 
61 	m.updateDataMask(MeshModel::MM_VERTFACETOPO | MeshModel::MM_FACEMARK|MeshModel::MM_VERTMARK);
62 
63 	if (!m.hasDataMask(MeshModel::MM_VERTCOLOR))
64 	{
65 		m.updateDataMask(MeshModel::MM_VERTCOLOR);
66 		tri::UpdateColor<CMeshO>::VertexConstant(m.cm,Color4b(150, 150, 150, 255));
67 	}
68   tri::InitFaceIMark(m.cm);
69   tri::InitVertexIMark(m.cm);
70 
71 	parent->getCurrentRenderMode().colorMode=vcg::GLW::CMPerVert;
72 
73 	QObject::connect(paintbox, SIGNAL(undo()), this, SLOT(update()));
74 	QObject::connect(paintbox, SIGNAL(redo()), this, SLOT(update()));
75 	QObject::connect(paintbox, SIGNAL(typeChange(ToolType)), this, SLOT(setToolType(ToolType)));
76 
77 	parent->update();
78 
79 	selection = new vector<CMeshO::FacePointer>();
80 	latest_event.pressure = 0.0;
81 
82 	setToolType(COLOR_PAINT);
83 
84 	glarea = parent;
85 	buffer_width = glarea->curSiz.width();
86 	buffer_height = glarea->curSiz.height();
87 	glarea->setMouseTracking(true);
88 
89 	connect(this, SIGNAL(setSelectionRendering(bool)),glarea,SLOT(setSelectFaceRendering(bool)) );
90 
91 	parent->setCursor(QCursor(QPixmap(":/images/cursor_paint.png"),1,1));
92 
93   // initialize once and for all the radius (will remain the same all the time)
94   current_brush.radius = (paintbox->getRadius() * m.cm.bbox.Diag() * 0.5);
95 
96 	return true;
97 }
98 
EndEdit(MeshModel &,GLArea *)99 void EditPaintPlugin::EndEdit(MeshModel &/*m*/, GLArea * /*parent*/)
100 {
101 	QObject::disconnect(paintbox, SIGNAL(undo()), this, SLOT(update()));
102 	QObject::disconnect(paintbox, SIGNAL(redo()), this, SLOT(update()));
103 	glarea->setMouseTracking(false);
104 	if (zbuffer != NULL) delete zbuffer; zbuffer = NULL;
105 	delete paintbox;
106 	delete selection;
107 	delete dock;
108 }
109 
mousePressEvent(QMouseEvent * event,MeshModel &,GLArea * gla)110 void EditPaintPlugin::mousePressEvent(QMouseEvent * event, MeshModel &, GLArea * gla)
111 {
112   // start a new stroke: init zbuffer and update brush
113 	if (zbuffer != NULL) delete zbuffer; zbuffer = NULL;
114 
115   current_brush.size = paintbox->getSize();
116 	current_brush.opacity = paintbox->getOpacity();
117 	current_brush.hardness = paintbox->getHardness();
118 
119 	pushInputEvent(event->type(), event->pos(), event->modifiers(), 1, event->button(), gla);
120 	gla->update();
121 }
122 
mouseMoveEvent(QMouseEvent * event,MeshModel &,GLArea * gla)123 void EditPaintPlugin::mouseMoveEvent(QMouseEvent* event, MeshModel & , GLArea * gla)
124 {
125 	pushInputEvent(event->type(), event->pos(), event->modifiers(), latest_event.pressure, latest_event.button, gla);
126 	gla->update();
127 }
128 
mouseReleaseEvent(QMouseEvent * event,MeshModel &,GLArea * gla)129 void EditPaintPlugin::mouseReleaseEvent(QMouseEvent * event, MeshModel &, GLArea * gla)
130 {
131 	pushInputEvent(event->type(), event->pos(), event->modifiers(), 0, event->button(), gla);
132 	gla->update();
133 }
134 
tabletEvent(QTabletEvent * event,MeshModel &,GLArea * gla)135 void EditPaintPlugin::tabletEvent(QTabletEvent * event, MeshModel & , GLArea * gla)
136 {
137   if(!(paintbox->getPressureFrameEnabled()))
138     paintbox->enablePressureFrame();
139 
140 	event->accept();
141 
142   // if event is down, start a new stroke: clean zbuff
143   if(event->type() == QEvent::TabletPress)
144   {
145   	if (zbuffer != NULL) delete zbuffer; zbuffer = NULL;
146     current_brush.size = paintbox->getSize();
147 	  current_brush.opacity = paintbox->getOpacity();
148 	  current_brush.hardness = paintbox->getHardness();
149   }
150 
151   pushInputEvent(event->type(), event->pos(), event->modifiers(), event->pressure(), (event->pointerType() == QTabletEvent::Eraser)? Qt::RightButton : Qt::LeftButton, gla);
152 	gla->update();
153 }
154 
setToolType(ToolType t)155 void EditPaintPlugin::setToolType(ToolType t)
156 {
157 	current_type = t;
158 
159 	switch(current_type)
160 	{
161 		case MESH_SELECT :
162 			current_options = EPP_PICK_FACES | EPP_DRAW_CURSOR;
163 			emit setSelectionRendering(true);
164 			break;
165 
166 		case COLOR_PAINT:
167 		case COLOR_NOISE:
168 		case COLOR_CLONE:
169 		case COLOR_SMOOTH :
170 		case MESH_SMOOTH :
171 			current_options = EPP_PICK_VERTICES | EPP_DRAW_CURSOR;
172 			break;
173 
174 		case MESH_PULL:
175 		case MESH_PUSH:
176 			current_options = EPP_PICK_VERTICES | EPP_AVG_NORMAL | EPP_DRAW_CURSOR;
177 			break;
178 
179 		case COLOR_FILL:
180 		case COLOR_GRADIENT:
181 		case COLOR_PICK :
182 		default:
183 			current_options = EPP_NONE;
184 	}
185 }
186 
setBrushSettings(int size,int opacity,int hardness)187 void EditPaintPlugin::setBrushSettings(int size, int opacity, int hardness)
188 {
189 	current_brush.size = size;
190 	current_brush.opacity = opacity;
191 	current_brush.hardness = hardness;
192 }
193 
194 /**
195  * Since only on a Decorate call it is possible to obtain correct values
196  * from OpenGL, all operations are performed during the execution of this
197  * method and not where mouse events are processed.
198  *
199  */
Decorate(MeshModel & m,GLArea * gla)200 void EditPaintPlugin::Decorate(MeshModel &m, GLArea * gla)
201 {
202 	glarea = gla;
203 
204 	if (!latest_event.valid || latest_event.processed) return;
205 
206 	latest_event.processed = true;
207 
208 	glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix);
209 	glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix);
210 
211 	viewport[0] = viewport[1] = 0;
212 	viewport[2] = gla->curSiz.width(); viewport[3] = gla->curSiz.height();
213 
214 	if (zbuffer == NULL)
215 	{
216 		zbuffer = new GLfloat[gla->curSiz.width()*gla->curSiz.height()];
217 		glReadPixels(0,0,gla->curSiz.width(), gla->curSiz.height(), GL_DEPTH_COMPONENT, GL_FLOAT, zbuffer);
218 	}
219 
220 	if (current_options & EPP_DRAW_CURSOR)
221 	{
222 
223     current_brush.radius = (paintbox->getRadius() * m.cm.bbox.Diag() * 0.5);
224     if((paintbox->getPressureFrameEnabled()))
225     {
226       if(paintbox->getPressureSize())
227 		    current_brush.size = paintbox->getSize() * latest_event.pressure;
228 
229       if(paintbox->getPressureOpacity())
230 		    current_brush.opacity = paintbox->getOpacity() * latest_event.pressure;
231 
232       if(paintbox->getPressureHardness())
233 		    current_brush.hardness = paintbox->getHardness() * latest_event.pressure;
234     }
235 
236 		if (paintbox->getSizeUnit() == 0)
237 			drawSimplePolyLine(gla, latest_event.position, paintbox->getSize(),
238 					(paintbox->getBrush() == CIRCLE) ? & circle : & square);
239 		else
240 			drawPercentualPolyLine(glarea, latest_event.gl_position, m, zbuffer, modelview_matrix, projection_matrix, viewport, current_brush.radius,
241 					(paintbox->getBrush() == CIRCLE) ? & dense_circle : & dense_square );
242 	}
243 
244 	if (latest_event.pressure > 0)
245 	{
246 		if (current_options & EPP_PICK_VERTICES)
247 		{
248 			vertices.clear();
249 			updateSelection(m, & vertices);
250 		}else if (current_options & EPP_PICK_FACES) updateSelection(m);
251 
252 		if (previous_event.pressure == 0)
253 		{
254 			/*************************
255 			 *     ON BRUSH DOWN     *
256 			 *************************/
257 
258 			paintbox->setUndoStack(glarea);
259 
260 			switch (current_type)
261 			{
262 				case COLOR_PAINT:
263 					{
264 						painted_vertices.clear();
265 						QColor newcol;
266 
267             if(latest_event.button == Qt::LeftButton)
268               newcol = paintbox->getForegroundColor();
269             else
270 							newcol = paintbox->getBackgroundColor();
271 						color[0] = newcol.red(); color[1] = newcol.green();
272 						color[2] = newcol.blue(); color[3] = newcol.alpha();
273 						paintbox->getUndoStack()->beginMacro("Color Paint");
274 						paint(& vertices);
275 					}
276 					break;
277 
278 				case COLOR_CLONE :
279 
280 					//Clone Source Acquisition
281 					if (latest_event.modifiers & Qt::ControlModifier ||
282 							latest_event.button == Qt::RightButton)
283 					{
284 						if (color_buffer != NULL) delete color_buffer;
285 						if (clone_zbuffer != NULL) delete clone_zbuffer;
286 						color_buffer = NULL, clone_zbuffer = NULL;
287 						glarea->getCurrentRenderMode().lighting = false;
288 						current_options &= ~EPP_DRAW_CURSOR;
289 						glarea->update();
290 					}
291 
292 					//Clone Painting
293 					else {
294 						//There's a new image to get
295 						if (paintbox->isNewPixmapAvailable())
296 						{
297 							paintbox->getPixmapBuffer(color_buffer, clone_zbuffer, buffer_width, buffer_height);
298 					//		source_delta.setX(buffer_width/2);
299 					//		source_delta.setY(buffer_height/2);
300 							source_delta = paintbox->getPixmapDelta();
301 							paintbox->setPixmapOffset(0, 0);
302 							apply_start = latest_event.position;
303 							painted_vertices.clear();
304 							paintbox->getUndoStack()->beginMacro("Color Clone");
305 
306 							paint( & vertices);
307 						}else if (color_buffer != NULL)
308 						//There's still something in the buffer
309 						{
310 							painted_vertices.clear();
311 							source_delta = paintbox->getPixmapDelta();
312 							paintbox->setPixmapOffset(0, 0);
313 							apply_start = latest_event.position;
314 							paintbox->getUndoStack()->beginMacro("Color Clone");
315 							paint( & vertices);
316 						}
317 					}
318 					break;
319 
320 				case COLOR_NOISE :
321 					painted_vertices.clear();
322 					noise_scale = paintbox->getNoiseSize() * 10 / m.cm.bbox.Diag();
323 					paintbox->getUndoStack()->beginMacro("Color Noise");
324 					break;
325 
326 				case COLOR_GRADIENT:
327 					gradient_start = latest_event.position;
328 					break;
329 
330 				case MESH_PULL:
331 				case MESH_PUSH :
332 					displaced_vertices.clear();
333 					paintbox->getUndoStack()->beginMacro("Mesh Sculpting");
334 					sculpt(m, & vertices);
335 					break;
336 
337 				case COLOR_SMOOTH:
338 					paintbox->getUndoStack()->beginMacro("Color Smooth");
339 					smoothed_vertices.clear();
340           tri::UnMarkAll(m.cm);
341 					break;
342 				case MESH_SMOOTH:
343 					paintbox->getUndoStack()->beginMacro("Mesh Smooth");
344 					smoothed_vertices.clear();
345           tri::UnMarkAll(m.cm);
346 					break;
347 
348 				default :
349 					break;
350 			}
351 		}else
352 		{
353 			/*************************
354 			 *     ON BRUSH MOVE     *
355 			 *************************/
356 
357 			switch (current_type)
358 			{
359 
360 				case COLOR_CLONE :
361 					paintbox->setPixmapOffset(latest_event.position.x() - apply_start.x(), latest_event.position.y() - apply_start.y());
362 					if (color_buffer != NULL) paint( & vertices);
363 					break;
364 
365 				case COLOR_PAINT:
366 				case COLOR_NOISE :
367 					paint(& vertices);
368 					break;
369 
370 				case COLOR_GRADIENT:
371 					drawLine(glarea, gradient_start, latest_event.position);
372 					break;
373 
374 				case MESH_SELECT:
375 					for(vector<CMeshO::FacePointer>::iterator fpi = selection->begin(); fpi != selection->end(); ++fpi)
376 					{
377 						if (latest_event.button == Qt::LeftButton)(*fpi)->SetS();
378 						else (*fpi)->ClearS();
379 					}
380 					break;
381 
382 				case MESH_PUSH:
383 				case MESH_PULL:
384 					sculpt(m, & vertices);
385 					break;
386 
387 				case COLOR_SMOOTH:
388 				case MESH_SMOOTH:
389 					smooth(& vertices);
390 					break;
391 
392 				default :
393 					break;
394 			}
395 		}
396 
397 	}else
398 	{
399 		if (previous_event.pressure > 0)
400 		{
401 			/*************************
402 			 *      ON BRUSH UP      *
403 			 *************************/
404 
405 			switch (current_type)
406 			{
407 				case COLOR_FILL:
408 					CFaceO * face;
409 					if(GLPickTri<CMeshO>::PickNearestFace(latest_event.gl_position.x(), latest_event.gl_position.y(), m.cm, face, 2, 2))
410 					{
411 						fill(m, face);
412 						glarea->update();
413 					}
414 					break;
415 
416 
417 				case COLOR_PICK :
418 					{
419 						QColor color;
420 						CVertexO * temp_vert = NULL;
421 						if (paintbox->getPickMode() == 0) {
422 							if (getVertexAtMouse(m,temp_vert, latest_event.gl_position, modelview_matrix, projection_matrix, viewport))
423 							{
424 								color.setRgb(temp_vert->C()[0], temp_vert->C()[1], temp_vert->C()[2], 255);
425 								(latest_event.button == Qt::LeftButton) ? paintbox->setForegroundColor(color) : paintbox->setBackgroundColor(color);
426 							}
427 						} else
428 						{
429 							GLubyte pixel[3];
430 							glReadPixels( latest_event.gl_position.x(), latest_event.gl_position.y(), 1, 1, GL_RGB, GL_UNSIGNED_BYTE,(void *)pixel);
431 							color.setRgb(pixel[0], pixel[1], pixel[2], 255);
432 							(latest_event.button == Qt::LeftButton) ? paintbox->setForegroundColor(color) : paintbox->setBackgroundColor(color);
433 						}
434 						paintbox->restorePreviousType();
435 					}
436 					break;
437 
438 				case COLOR_GRADIENT:
439 					gradient(m, gla);
440 					gla->update();
441 					break;
442 
443 				case COLOR_CLONE:
444 					if (latest_event.modifiers & Qt::ControlModifier ||
445 						latest_event.button == Qt::RightButton) {capture(); break;}
446 					else
447 						paintbox->movePixmapDelta(-latest_event.position.x() + apply_start.x(), -latest_event.position.y() + apply_start.y());
448 				case COLOR_SMOOTH :
449 				case COLOR_NOISE :
450 				case COLOR_PAINT:
451 				case MESH_SMOOTH :
452 				case MESH_PUSH:
453 				case MESH_PULL:
454 					paintbox->getUndoStack()->endMacro();
455 				default :
456 					break;
457 			}
458 		}
459 	}
460 }
461 
462 
smooth(vector<pair<CVertexO *,PickingData>> * vertices)463 inline void EditPaintPlugin::smooth(vector< pair<CVertexO *, PickingData> > * vertices)
464 {
465 	QHash <CVertexO *, pair<Point3f, Color4b> > originals;
466 
467 	Color4b newcol, destCol;
468 	int opac = paintbox->getOpacity();
469 	int decrease_pos = paintbox->getSmoothPercentual();
470 	int c_r, c_g, c_b;
471 	float p_x, p_y, p_z;
472 	float newpos[3];
473 
474   if(paintbox->getPressureDisplacement())
475     decrease_pos *= latest_event.pressure;
476 
477 	for (unsigned int k = 0; k < vertices->size(); k++) //forach selected vertices
478 	{
479 		pair<CVertexO *, PickingData> data = vertices->at(k);
480 
481 		CVertexO * v = data.first;
482 		PickingData * vd = & data.second;
483 
484 		pair<Point3f, Color4b> pc_data; //save its color and position
485 
486 		for (int k = 0; k < 4; k++) pc_data.second[k] = v->C()[k];
487 		for (int k = 0; k < 3; k++) pc_data.first[k] = v->P()[k];
488 
489 		if (!smoothed_vertices.contains(v))
490 		{
491 			if (paintbox->getCurrentType() == COLOR_SMOOTH) paintbox->getUndoStack()->push(new SingleColorUndo(v, v->C()));
492 			else paintbox->getUndoStack()->push(new SinglePositionUndo(v, v->P(), v->N()));
493 			smoothed_vertices.insert(v,v);
494 		}
495 
496 		if (!originals.contains(v)) originals.insert(v, pc_data); //save original color/position data
497 
498 		CFaceO * one_face = v->VFp(); //one of the faces adjacent to the vertex
499 		int pos = v->VFi();  //index of vertex v on face one_face
500 		c_r = c_g = c_b = 0;
501 		p_x = p_y = p_z = 0;
502 		int count_me = 0;
503 		CFaceO * f  = one_face;
504 
505 		do
506 		{ /// calc the sum of the surrounding vertexes pos or and vertexes color
507 			CFaceO * temp = one_face->VFp(pos); //next face in VF list
508 			if (one_face != 0 && !one_face->IsD())
509 			{
510 				for (int k = 0; k < 3; k++)
511 				{
512 					if (pos != k)
513 					{
514 						CVertexO * v = one_face->V(k);
515 						Color4b tco = v->C();
516 						if (originals.contains(v))
517 						{
518 							pair<Point3f, Color4b> pc_data_k = originals[v];
519 
520 							tco = pc_data_k.second;
521 
522 							p_x += pc_data_k.first[0]; p_y += pc_data_k.first[1]; p_z += pc_data_k.first[2];
523 						}else if (paintbox->getCurrentType() == MESH_SMOOTH)
524 						{
525 							p_x += v->P()[0]; p_y += v->P()[1]; p_z += v->P()[2];
526 						}
527 						c_r += tco[0]; c_g += tco[1]; c_b += tco[2];
528 					}
529 				}
530 
531 				pos=one_face->VFi(pos);
532 				count_me+=2;
533 			}
534 			one_face = temp;
535 		} while (one_face != f && one_face != 0);
536 
537 		if (count_me > 0) /// calc the new color or pos
538 		{
539 			float op = brush(paintbox->getBrush(), vd->distance, vd->rel_position.x(), vd->rel_position.y(), decrease_pos);
540 
541 			if (paintbox->getCurrentType() == COLOR_SMOOTH)
542 			{
543 				newcol[0] = c_r/count_me;
544 				newcol[1] = c_g/count_me;
545 				newcol[2] = c_b/count_me;
546 
547 				mergeColors((float)(op*opac)/100.0, newcol, v->C(), &destCol);
548 
549 				v->C()[0] = destCol[0];
550 				v->C()[1] = destCol[1];
551 				v->C()[2] = destCol[2];
552 			} else
553 			{
554 				newpos[0] = p_x/(float)count_me;
555 				newpos[1] = p_y/(float)count_me;
556 				newpos[2] = p_z/(float)count_me;
557 				float po[3]; for (int lauf=0; lauf<3; lauf++) po[lauf]=v->P()[lauf];
558 				mergePositions((float)(op*opac)/100.0,newpos,po,newpos);
559 
560 				for (int lauf=0; lauf<3; lauf++) v->P()[lauf]=newpos[lauf];
561 			}
562 		}
563 
564 		if (paintbox->getCurrentType() == MESH_SMOOTH)
565 		{
566 			updateNormal(v);
567 		}
568 	}
569 }
570 
sculpt(MeshModel & m,vector<pair<CVertexO *,PickingData>> * vertices)571 inline void EditPaintPlugin::sculpt(MeshModel & m, vector< pair<CVertexO *, PickingData> > * vertices)
572 {
573 //	int opac = 1.0;
574 	float decrease_pos = paintbox->getHardness() / 100.0;
575 	float strength = m.cm.bbox.Diag() * paintbox->getDisplacement() / 1000.0;
576 
577   if(paintbox->getPressureDisplacement())
578     strength *= latest_event.pressure;
579 
580 	if (latest_event.button == Qt::RightButton) strength = - strength;
581 
582 	if (normal[0] == normal[1] && normal[1] == normal[2] && normal[2] == 0) {
583 		return;
584 	}
585 
586 	for (unsigned int k = 0; k < vertices->size(); k++)
587 	{
588 		pair<CVertexO *, PickingData> data = vertices->at(k);
589 
590 		float op = brush(paintbox->getBrush(), data.second.distance, data.second.rel_position.x(), data.second.rel_position.y(), decrease_pos * 100);
591 
592 		//TODO Precalculate this monster!
593 		float gauss = (strength * exp(-(op - 1.0)*(op - 1.0) * 8.0 ));
594 
595 		if (!displaced_vertices.contains(data.first))
596 		{
597 			displaced_vertices.insert(data.first, pair<Point3f, float>(
598 				Point3f(data.first->P()[0], data.first->P()[1], data.first->P()[2]),
599 				gauss) );
600 
601 			paintbox->getUndoStack()->push(new SinglePositionUndo(data.first, data.first->P(), data.first->N()));
602 			displaceAlongVector(data.first, normal, gauss);
603 			updateNormal(data.first);
604 
605 		} else if ((latest_event.button == Qt::RightButton)
606 				? displaced_vertices[data.first].second > gauss
607 				: displaced_vertices[data.first].second < gauss)
608 		{
609 			displaced_vertices[data.first].second = gauss;
610 			Point3f temp = displaced_vertices[data.first].first;
611 			data.first->P()[0]=temp[0]; data.first->P()[1]=temp[1]; data.first->P()[2]=temp[2];
612 			displaceAlongVector(data.first, normal, gauss);
613 			updateNormal(data.first);
614 
615 		}
616 
617 		delete zbuffer; zbuffer = NULL;
618 	}
619 }
620 
capture()621 inline void EditPaintPlugin::capture()
622 {
623 	color_buffer = new GLubyte[glarea->curSiz.width()*glarea->curSiz.height()*4];
624 	clone_zbuffer = new GLfloat[glarea->curSiz.width()*glarea->curSiz.height()];
625 	glReadPixels(0,0,glarea->curSiz.width(), glarea->curSiz.height(), GL_RGBA, GL_UNSIGNED_BYTE, color_buffer);
626 	glReadPixels(0,0,glarea->curSiz.width(), glarea->curSiz.height(), GL_DEPTH_COMPONENT, GL_FLOAT, clone_zbuffer);
627 	buffer_height = glarea->curSiz.height();
628 	buffer_width = glarea->curSiz.width();
629 
630 	source_delta = latest_event.position;
631 
632 	QImage image(glarea->width(), glarea->height(), QImage::Format_ARGB32);
633 	for (int x = 0; x < glarea->width(); x++){
634 		for (int y = 0; y < glarea->height(); y++){
635 			int index = (y * glarea->width() + x)*4;
636 			image.setPixel(x, glarea->height() - y -1, qRgba((int)color_buffer[index], (int)color_buffer[index + 1], (int)color_buffer[index + 2], (int)color_buffer[index + 3]));
637 		}
638 	}
639 	glarea->getCurrentRenderMode().lighting = true;
640 	current_options |= EPP_DRAW_CURSOR;
641 	paintbox->setClonePixmap(image);
642 	paintbox->setPixmapDelta(source_delta.x(), source_delta.y());
643 
644 //	paintbox->setPixmapCenter(-source_delta.x(), -source_delta.y());
645 	glarea->update();
646 }
647 
accessCloneBuffer(int vertex_x,int vertex_y,vcg::Color4b & color)648 inline bool EditPaintPlugin::accessCloneBuffer(int vertex_x, int vertex_y, vcg::Color4b & color)
649 {
650 	int y =  buffer_height - source_delta.y() +	(vertex_y + apply_start.y() - glarea->curSiz.height());
651 	int x =  source_delta.x() +	(vertex_x - apply_start.x());
652 
653 	int index = y * buffer_width + x;
654 
655 	if (x < buffer_width && y < buffer_height && x >= 0 && y >= 0)
656 	{
657 		if (clone_zbuffer[index] < 1.0)
658 		{
659 			index *= 4;
660 			color[0] = color_buffer[index]; color[1] = color_buffer[index + 1]; color[2] = color_buffer[index + 2], color[3] = color_buffer[index + 3];
661 			return true;
662 		}
663 	}
664 	return false;
665 }
666 
667 /**
668  * Painting, Cloning and Noise!
669  */
paint(vector<pair<CVertexO *,PickingData>> * vertices)670 inline void EditPaintPlugin::paint(vector< pair<CVertexO *, PickingData> > * vertices)
671 {
672 	int opac = current_brush.opacity; //TODO legacy assignment
673 	int decrease_pos = current_brush.hardness; //TODO legacy assignment
674 
675 	for (unsigned int k = 0; k < vertices->size(); k++)
676 	{
677 		pair<CVertexO *, PickingData> data = vertices->at(k);
678 
679 		float op = brush(paintbox->getBrush(), data.second.distance, data.second.rel_position.x(), data.second.rel_position.y(), decrease_pos);
680 
681 		if (!painted_vertices.contains(data.first))
682 		{
683 			if (paintbox->getCurrentType() == COLOR_CLONE)
684 				if (!accessCloneBuffer(data.second.position.x(), data.second.position.y(), color)) return;
685 
686 			if (paintbox->getCurrentType() == COLOR_NOISE)
687 				computeNoiseColor(data.first, color);
688 
689 			painted_vertices.insert(data.first, pair<Color4b, int>(
690 				Color4b(data.first->C()[0], data.first->C()[1], data.first->C()[2], data.first->C()[3]),
691 				(int)(op*opac)) );
692 
693 			paintbox->getUndoStack()->push(new SingleColorUndo(data.first, data.first->C()));
694 
695 			applyColor(data.first, color, (int)(op * opac  ));
696 
697 		} else if (painted_vertices[data.first].second < (int)(op * opac))
698 		{
699 			painted_vertices[data.first].second = (int)(op * opac);
700 			Color4b temp = painted_vertices[data.first].first;
701 			data.first->C()[0]=temp[0]; data.first->C()[1]=temp[1]; data.first->C()[2]=temp[2];
702 
703 			if (paintbox->getCurrentType() == COLOR_CLONE)
704 				if (!accessCloneBuffer(data.second.position.x(), data.second.position.y(), color)) return;
705 
706 			if (paintbox->getCurrentType() == COLOR_NOISE)
707 				computeNoiseColor(data.first, color);
708 
709 			paintbox->getUndoStack()->push(new SingleColorUndo(data.first, data.first->C()));
710 
711 			applyColor(data.first, color, (int)(op * opac) );
712 		}
713 	}
714 }
715 
computeNoiseColor(CVertexO * vert,vcg::Color4b & col)716 inline void EditPaintPlugin::computeNoiseColor(CVertexO * vert, vcg::Color4b & col)
717 {
718 	float scaler = noise_scale; //parameter TODO to be cahced
719 
720 	double noise;
721 	//if "veins on"
722 //	noise = vcg::math::Abs(vcg::math::Perlin::Noise(vert->P()[0] * scaler, vert->P()[1] * scaler, vert->P()[2] * scaler));
723 	//else
724 	noise = (vcg::math::Perlin::Noise(vert->P()[0] * scaler, vert->P()[1] * scaler, vert->P()[2] * scaler)+ 1) /2;
725 
726 	Color4b forecolor(paintbox->getForegroundColor().red(), paintbox->getForegroundColor().green(), paintbox->getForegroundColor().blue(), paintbox->getForegroundColor().alpha());
727 
728 	//TODO test code to be refactored
729 	if (paintbox->getGradientType() == 0)
730 	{
731 		Color4b backcolor(paintbox->getBackgroundColor().red(), paintbox->getBackgroundColor().green(), paintbox->getBackgroundColor().blue(), paintbox->getBackgroundColor().alpha());
732 		for (int i = 0; i < 4; i ++)
733 			col[i] = forecolor[i] * noise + backcolor[i] * (1.0 - noise);
734 	}else
735 	{
736 		for (int i = 0; i < 4; i ++)
737 			col[i] = forecolor[i] * noise + vert->C()[i] * (1.0 - noise);
738 	}
739 }
740 
741 /**
742  * fills the mesh starting from face.
743  * If face is selected, it will fill only the selected area,
744  * otherwise only the non selected area
745  */
fill(MeshModel &,CFaceO * face)746 inline void EditPaintPlugin::fill(MeshModel & ,CFaceO * face)
747 {
748 	QHash <CFaceO *,CFaceO *> visited;
749 	QHash <CVertexO *,CVertexO *> temp;
750 	vector <CFaceO *>temp_po;
751 	bool who = face->IsS();
752 	temp_po.push_back(face);
753 	visited.insert(face,face);
754 	int opac=paintbox->getOpacity();
755 	QColor newcol = (latest_event.button == Qt::LeftButton) ? paintbox->getForegroundColor() : paintbox->getBackgroundColor();
756 
757 	Color4b color(newcol.red(), newcol.green(), newcol.blue(), newcol.alpha());
758 
759 	paintbox->getUndoStack()->beginMacro("Fill Color");
760 
761 	for (unsigned int lauf2 = 0; lauf2 < temp_po.size(); lauf2++) {
762 		CFaceO * fac=temp_po.at(lauf2);
763 		if (who == fac->IsS()) {
764 			for (int lauf=0; lauf<3; lauf++) {
765 				if (!temp.contains(fac->V(lauf))) {
766 					temp.insert(fac->V(lauf),fac->V(lauf));
767 
768 					paintbox->getUndoStack()->push(new SingleColorUndo(fac->V(lauf), fac->V(lauf)->C()));
769 
770 					applyColor(fac->V(lauf), color , opac);
771 				}
772 			}
773 
774 			vector <CFaceO *> surround;
775 			for (int lauf=0; lauf<3; lauf++) getSurroundingFacesVF(fac,lauf,&surround);
776 
777 			for (unsigned int lauf3 = 0; lauf3 < surround.size(); lauf3++) {
778 				if (!visited.contains(surround[lauf3])) {
779 					temp_po.push_back(surround[lauf3]);
780 					visited.insert(surround[lauf3],surround[lauf3]);
781 				}
782 			}
783 		}
784 	}
785 
786 	paintbox->getUndoStack()->endMacro();
787 }
788 
gradient(MeshModel & m,GLArea * gla)789 inline void EditPaintPlugin::gradient(MeshModel & m,GLArea * gla) {
790 
791 	QPoint p = gradient_start - latest_event.position;
792 
793 	QHash <CVertexO *,CVertexO *> temp;
794 
795 	int opac = paintbox->getOpacity();
796 	QColor qc1 = paintbox->getForegroundColor();
797 	QColor qc2 = paintbox->getBackgroundColor();
798 
799 	Color4b c1(qc1.red(), qc1.green(), qc1.blue(), qc1.alpha());
800 	Color4b c2(qc2.red(), qc2.green(), qc2.blue(), qc2.alpha());
801 
802 	QPointF p1(gradient_start.x(),gla->curSiz.height() - gradient_start.y());
803 	QPointF p0(latest_event.gl_position);
804 
805 	float x2=(p1.x()-p0.x());
806 	float y2=(p1.y()-p0.y());
807 
808 	float l_square=x2*x2+y2*y2;
809 
810 	CVertexO * vertex;
811 	CMeshO::FaceIterator fi;
812 	double dx,dy,dz;
813 	Color4b merger;
814 	bool tutti = !hasSelected(m);
815 	float radius=sqrt((float)(p.x()*p.x()+p.y()*p.y()));
816 
817 	paintbox->getUndoStack()->beginMacro("Gradient");
818 
819 	int gradient_type=paintbox->getGradientType();
820 	int gradient_form=paintbox->getGradientForm();
821 	for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi)
822 		if (!(*fi).IsD() && (tutti || (*fi).IsS()))
823 		for (int lauf=0; lauf<3; lauf++) {
824 			if (!temp.contains((*fi).V(lauf))) {
825 				vertex=(*fi).V(lauf);
826 				temp.insert(vertex,vertex);
827 				gluProject(vertex->P()[0],vertex->P()[1],vertex->P()[2],modelview_matrix, projection_matrix, viewport,&dx,&dy,&dz);
828 
829 				paintbox->getUndoStack()->push(new SingleColorUndo(vertex, vertex->C()));
830 
831 				if (gradient_form==0) {
832 					double r=(dx-p0.x())*(p1.x()-p0.x())+(dy-p0.y())*(p1.y()-p0.y());
833 					r=r/l_square;
834 
835 					float px=p0.x()+r*(p1.x()-p0.x());
836 					float py=p0.y()+r*(p1.y()-p0.y());
837 
838 					px=px-dx;
839 					py=py-dy;
840 
841 					if (gradient_type==0) {
842 						if (r>=0 && r<=1) {
843 							mergeColors(r,c1,c2,&merger);
844 							applyColor(vertex,merger,opac);
845 						} else if (r>1) {
846 							applyColor(vertex,c1,opac);
847 						} else if (r<0) {
848 							applyColor(vertex,c2,opac);
849 						}
850 					} else {
851 						if (r>=0 && r<=1) {
852 							applyColor(vertex,c1,(int)((opac * 0.01) * r * 100.0));
853 						} else if (r>1) {
854 							applyColor(vertex,c1,opac);
855 						}
856 					}
857 				} else {
858 					float x0=(dx-p1.x());
859 					float y0=(dy-p1.y());
860 					float bla0=x0*x0+y0*y0;
861 					if (bla0<radius*radius && radius>0) {
862 						float r=1.0-sqrt(bla0)/sqrt(radius*radius);
863 						if (gradient_type==0) {
864 							mergeColors(r,c1,c2,&merger);
865 							applyColor(vertex,merger,opac);
866 						} else {
867 							applyColor(vertex,c1,(int)((opac * 0.01) * r * 100.0));
868 						}
869 					}
870 				}
871 			}
872 		}
873 	paintbox->getUndoStack()->endMacro();
874 }
875 
876 
877 /**
878  * Updates currently selected faces by using one of the
879  * two methods. Just a new version of computeBrushedFaces
880  *
881  * It's inlined because it's only called once, inside Decorate.
882  * Should it be called in other places, the inlining must be removed!
883  */
updateSelection(MeshModel & m,vector<pair<CVertexO *,PickingData>> * vertex_result)884 inline void EditPaintPlugin::updateSelection(MeshModel &m, vector< pair<CVertexO *, PickingData> > * vertex_result)
885 {
886 	vector<CMeshO::FacePointer>::iterator fpi;
887 	vector<CMeshO::FacePointer> temp; //TODO maybe temp can be placed inside the class for better performance
888 
889 	vector <CFaceO *> surround; /*< surrounding faces of a given face*/
890 	surround.reserve(6);
891 
892 	if (current_options & EPP_AVG_NORMAL ) normal = Point3f(0.0, 0.0, 0.0);
893 
894   tri::UnMarkAll(m.cm);
895 
896 	if (selection->size() == 0) {
897 		CMeshO::FaceIterator fi;
898 		temp.reserve(m.cm.fn); //avoid unnecessary expansions
899         for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi){
900         	if(!(*fi).IsD()) {
901         		temp.push_back((&*fi));
902         	}
903         }
904 	} else
905 	{
906 		temp.reserve(selection->size()); //avoid unnecessary expansions
907 		vertex_result->reserve(selection->size());
908 		for(fpi = selection->begin();fpi != selection->end(); ++fpi)
909 		{
910 			temp.push_back(*fpi);
911 		}
912 	}
913 
914 	selection->clear();
915 
916 	QPointF gl_cursorf = QPointF(latest_event.gl_position);
917 	QPointF gl_prev_cursorf = QPointF(previous_event.gl_position);
918 
919 	QPointF p[3],z[3]; //p stores vertex coordinates in screen space, z the corresponding depth value
920 	double tx,ty,tz;
921 
922 	bool backface = paintbox->getPaintBackFace();
923 	bool invisible = paintbox->getPaintInvisible();
924 	bool percentual = paintbox->getSizeUnit() == 1;
925 
926 	double EPSILON = 0.003;
927 
928 	double scale_fac = 1.0;
929 	float fov = 1.0;
930 	double distance[3];
931 
932 	if (percentual)
933 	{
934 		double dX, dY, dZ;
935 
936 		fastMultiply(0,0,0,modelview_matrix,&dX,&dY,&dZ);
937 		fastMultiply(0,1,0,modelview_matrix,&tx,&ty,&tz);
938 
939 		scale_fac=sqrt((ty-dY)*(ty-dY)+(tx-dX)*(tx-dX)+(tz-dZ)*(tz-dZ));
940 
941 		/** to get the correct radius depending on distance but on fov too */
942 		float fo = glarea->getFov()*0.5;
943 		fov = 1.0/tan(fo*M_PI/180.0)*0.5;
944 	}
945 
946 	for (unsigned int k = 0; k < temp.size(); k++) //for each face
947 	{
948 		CFaceO * fac = temp.at(k);
949 		bool intern = false;
950 		int checkable = 0; /*< counts how many valid vertices there are in this face*/
951 
952 		for (int i = 0; i < 3; i++) //for each vertex defining the face
953 		{
954 			if (gluProject((fac)->V(i)->P()[0], (fac)->V(i)->P()[1], (fac)->V(i)->P()[2],
955 					modelview_matrix, projection_matrix, viewport, &tx, &ty, &tz) == GL_TRUE) checkable++; //if gluProjection works
956 
957 			if (tz < 0 || tz > 1) checkable--; //but if outside depth bounds
958 
959 			p[i].setX(tx); p[i].setY(ty); //store the position of the vertex on the screen
960 
961 			//if the vertex is projected within the screen (i.e. it's visible)
962 			if (tx>=0 && tx<viewport[2] && ty>=0 && ty<viewport[3])
963 			{
964 				z[i].setX(tz); //the screen depth of the point
965 				z[i].setY((float)zbuffer[(int)(((int)ty)*viewport[2]+(int)tx)]); //the screen depth of the closest point at the same coors
966 			}else
967 			{
968 				z[i].setX(1); //far
969 				z[i].setY(0); //near
970 			}
971 
972 			if (percentual){
973 				double dx,dy,dz; // distance
974 				fastMultiply((fac)->V(i)->P()[0],(fac)->V(i)->P()[1],(fac)->V(i)->P()[2], modelview_matrix, &dx, &dy, &dz);
975 				distance[i]=dz;
976 			}
977 		}
978 
979 		if (backface || isFront(p[0],p[1],p[2]))
980 		{
981 			for (int j=0; j<3; j++) if (invisible || (z[j].x() <= z[j].y() + EPSILON))
982 			{
983 				PickingData vd; //TODO make it a pointer
984 
985 				float radius = percentual ? vcg::math::Abs(current_brush.radius * scale_fac * viewport[3] * fov / distance[j]) : current_brush.size;
986 
987 				if (isIn(gl_cursorf, gl_prev_cursorf, p[j].x(), p[j].y(), radius , & vd.distance, vd.rel_position))
988 				{
989 					intern = true;
990 					if (vertex_result == NULL) continue;
991           else if (!tri::IsMarked(m.cm,fac->V(j)))
992 					{
993 						vd.position.setX((int)p[j].x()); vd.position.setY((int)p[j].y());
994 						pair<CVertexO *, PickingData> data(fac->V(j), vd);
995 						vertex_result->push_back(data);
996 
997 						if (current_options & EPP_AVG_NORMAL ) normal += fac->V(j)->N();
998 
999             tri::Mark(m.cm,fac->V(j));
1000 					}
1001 				}
1002 
1003 				if (vertex_result == NULL && !intern && lineHitsCircle(p[j],p[(j+1)%3], gl_cursorf, radius))
1004 				{
1005 					intern = true;
1006 					continue;
1007 				}
1008 			}
1009 
1010 			if (checkable==3 && !intern && (pointInTriangle(gl_cursorf,p[0],p[1],p[2]) || pointInTriangle(gl_prev_cursorf,p[0],p[1],p[2])))
1011 			{
1012 				intern = true;
1013 			}
1014 		}
1015 
1016     if (intern && !tri::IsMarked(m.cm,fac))
1017 		{
1018       tri::Mark(m.cm,fac);
1019 			selection->push_back(fac);
1020 			surround.clear();
1021 			for (int lauf=0; lauf<3; lauf++) getSurroundingFacesVF(fac,lauf,&surround);
1022 
1023 			for (unsigned int lauf3=0; lauf3<surround.size(); lauf3++)
1024 			{
1025         if (!tri::IsMarked(m.cm,surround[lauf3]))
1026 				{
1027 						temp.push_back(surround[lauf3]);
1028 				}
1029 			}
1030 		}
1031 	} //end of for each face loop
1032 
1033 	if (current_options & EPP_AVG_NORMAL ) normal /= vertex_result->size();
1034 }
1035 
1036 /**
1037  * Request an async repainting of the glarea
1038  *
1039  * This slot is connected to undo and redo
1040  */
update()1041 void EditPaintPlugin::update()
1042 {
1043 	glarea->update();
1044 }
1045 
1046 
1047 /*********OpenGL Drawing Routines************/
1048 
1049 
1050 /**
1051  * draws the xor-line
1052  */
drawLine(GLArea * gla,QPoint & start,QPoint & cur)1053 void drawLine(GLArea * gla, QPoint & start, QPoint & cur) {
1054 	glMatrixMode(GL_PROJECTION);
1055 	glPushMatrix();
1056 	glLoadIdentity();
1057 	glOrtho(0,gla->curSiz.width(),gla->curSiz.height(),0,-1,1);
1058 	glMatrixMode(GL_MODELVIEW);
1059 	glPushMatrix();
1060 	glLoadIdentity();
1061 	glPushAttrib(GL_ENABLE_BIT);
1062 	glDisable(GL_DEPTH_TEST);
1063 	glDisable(GL_LIGHTING);
1064 	glDisable(GL_TEXTURE_2D);
1065 	glEnable(GL_COLOR_LOGIC_OP);
1066 	float wi;
1067 	glGetFloatv(GL_LINE_WIDTH,&wi);
1068 	glLineWidth(4);
1069 	glLogicOp(GL_XOR);
1070 	glColor3f(1,1,1);
1071 	glBegin(GL_LINES);
1072 		glVertex2f(start.x(),start.y());
1073 		glVertex2f(cur.x(),cur.y());
1074 	glEnd();
1075 	glPopAttrib();
1076 	glPopMatrix(); // restore modelview
1077 	glLineWidth(wi);
1078 	glMatrixMode(GL_PROJECTION);
1079 	glPopMatrix();
1080 	glMatrixMode(GL_MODELVIEW);
1081 }
1082 
drawSimplePolyLine(GLArea * gla,QPoint & cur,float scale,vector<QPointF> * points)1083 void drawSimplePolyLine(GLArea * gla, QPoint & cur, float scale, vector<QPointF> * points)
1084 {
1085 	glMatrixMode(GL_PROJECTION);
1086 	glPushMatrix();
1087 	glLoadIdentity();
1088 	glOrtho(0,gla->curSiz.width(),gla->curSiz.height(),0,-1,1);
1089 	glMatrixMode(GL_MODELVIEW);
1090 	glPushMatrix();
1091 	glLoadIdentity();
1092 	glPushAttrib(GL_ENABLE_BIT);
1093 	glDisable(GL_DEPTH_TEST);
1094 	glDisable(GL_LIGHTING);
1095 	glDisable(GL_TEXTURE_2D);
1096 	glEnable(GL_COLOR_LOGIC_OP);
1097 	glLogicOp(GL_XOR);
1098 	glColor3f(1,1,1);
1099 
1100 	glBegin(GL_LINE_LOOP);
1101 
1102 	for (unsigned int k = 0; k < points->size(); k++)
1103 	{
1104 		glVertex2f(cur.x() + ( points->at(k).x() * scale ), cur.y() + ( points->at(k).y() * scale ));
1105 	}
1106 
1107 	glEnd();
1108 
1109 	glDisable(GL_LOGIC_OP);
1110 	glPopAttrib();
1111 	glPopMatrix(); // restore modelview
1112 	glMatrixMode(GL_PROJECTION);
1113 	glPopMatrix();
1114 	glMatrixMode(GL_MODELVIEW);
1115 }
1116 
drawPercentualPolyLine(GLArea * gla,QPoint & mid,MeshModel & m,GLfloat * pixels,double * modelview_matrix,double * projection_matrix,GLint * viewport,float scale,vector<QPointF> * points)1117 void drawPercentualPolyLine(GLArea * gla, QPoint &mid, MeshModel &m, GLfloat* pixels,
1118 		double* modelview_matrix, double* projection_matrix, GLint* viewport, float scale, vector<QPointF> * points)
1119 {
1120 	double dX, dY, dZ; //near
1121 	double dX2, dY2, dZ2; //far
1122 
1123 	gluUnProject ((double) mid.x(), mid.y(), 0.0, modelview_matrix, projection_matrix, viewport, &dX, &dY, &dZ);
1124 	gluUnProject ((double) mid.x(), mid.y(), 1.0, modelview_matrix, projection_matrix, viewport, &dX2, &dY2, &dZ2);
1125 
1126 	glPushMatrix();
1127 	glLoadIdentity();
1128 	gluLookAt(dX,dY,dZ, dX2,dY2,dZ2, 1,0,0);
1129 
1130 	double mvmatrix2[16];
1131 	glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix2);
1132 	glPopMatrix();
1133 
1134 	double tx,ty,tz;
1135 	double tx2,ty2,tz2;
1136 
1137 	double inv_mvmatrix[16];
1138 
1139 	Matrix44d temp(mvmatrix2);
1140 	Invert(temp);
1141 
1142 	for (int k=0; k<16; k++)
1143 		inv_mvmatrix[k]=temp[k/4][k%4];
1144 
1145 	double a,b,c;
1146 	double a2,b2,c2;
1147 
1148 	int STEPS = 30;
1149 	int DSCALER = -7;
1150 
1151 	float diag = m.cm.bbox.Diag() * DSCALER;
1152 
1153 	float radius = scale; //TODO leftover
1154 
1155   QVector<QPointF> proj_points(points->size());
1156 
1157 	for (unsigned int i = 0; i < points->size(); i++)
1158 	{
1159 		/** calcs the far point of the line */
1160 		fastMultiply(points->at(i).x() * radius, points->at(i).y() * radius, diag, inv_mvmatrix, &tx, &ty, &tz);
1161 
1162 		gluProject(tx,ty,tz,modelview_matrix, projection_matrix, viewport, &a,&b,&c);
1163 
1164 		/** calcs the near point of the line */
1165 		fastMultiply(points->at(i).x() * radius, points->at(i).y() * radius, 0, inv_mvmatrix, &tx2, &ty2, &tz2);
1166 
1167 		gluProject(tx2,ty2,tz2,modelview_matrix, projection_matrix, viewport, &a2,&b2,&c2);
1168 		double da=(a-a2);// /(double)STEPS;
1169 		double db=(b-b2);// /(double)STEPS;
1170 		double dc=(c-c2);// /(double)STEPS;
1171 		double pix_x=a2;
1172 		double pix_y=b2;
1173 		double pix_z=c2;
1174 
1175 		/** to search with quicksearch the nearset zbuffer value in the line */
1176 		for (int k = 0; k < STEPS; k++)
1177 		{
1178 			double inv_yy = gla->curSiz.height()-pix_y;
1179 			double zz=999;
1180 
1181 			if ((int)pix_x>=0 && (int)pix_x<gla->curSiz.width() && (int)pix_y>=0 && (int)pix_y<gla->curSiz.height())
1182 				zz=(GLfloat)pixels[(int)(((int)pix_y)*gla->curSiz.width()+(int)pix_x)];
1183 			da=da/2.0;
1184 			db=db/2.0;
1185 			dc=dc/2.0;
1186 			if (fabsf(zz-pix_z)<0.001)
1187 			{
1188 				proj_points[i] = QPointF(pix_x, inv_yy);
1189 				break;
1190 			} else if (zz>pix_z)
1191 			{
1192 				pix_x+=da;
1193 				pix_y+=db;
1194 				pix_z+=dc;
1195 			} else
1196 			{
1197 				pix_x-=da;
1198 				pix_y-=db;
1199 				pix_z-=dc;
1200 			}
1201 
1202 			if (k == STEPS-1)
1203 			{
1204 				proj_points[i] = QPointF(pix_x,inv_yy);
1205 				break;
1206 			}
1207 		}
1208 	}
1209 
1210 	glMatrixMode(GL_PROJECTION);
1211 	glPushMatrix();
1212 	glLoadIdentity();
1213 	glOrtho(0,gla->curSiz.width(),gla->curSiz.height(),0,-1,1);
1214 	glMatrixMode(GL_MODELVIEW);
1215 	glPushMatrix();
1216 	glLoadIdentity();
1217 	glPushAttrib(GL_ENABLE_BIT);
1218 	glDisable(GL_DEPTH_TEST);
1219 	glDisable(GL_LIGHTING);
1220 	glDisable(GL_TEXTURE_2D);
1221 	glEnable(GL_COLOR_LOGIC_OP);
1222 	glLogicOp(GL_XOR);
1223 	glColor3f(1,1,1);
1224 
1225 	/** draws the circle */
1226 	glBegin(GL_LINE_LOOP);
1227 
1228 	for (unsigned int i = 0; i < points->size(); i++)
1229 	{
1230 		glVertex2f(proj_points[i].x(), proj_points[i].y());
1231 	}
1232 
1233 	glEnd();
1234 
1235 	glDisable(GL_COLOR_LOGIC_OP);
1236 	glPopAttrib();
1237 	glPopMatrix(); // restore modelview
1238 	glMatrixMode(GL_PROJECTION);
1239 	glPopMatrix();
1240 	glMatrixMode(GL_MODELVIEW);
1241 
1242 }
1243 
1244 //each side is divided in given segments
generatePolygon(std::vector<QPointF> & vertices,int sides,int segments)1245 void generatePolygon(std::vector<QPointF> & vertices, int sides, int segments)
1246 {
1247 	float step = sides / 2.0;
1248 
1249 	float start_angle = M_PI / sides;
1250 
1251 	for (int k = 0; k < sides; k++)
1252 	{
1253 		vertices.push_back(QPointF(sin((M_PI * (float)k / step) + start_angle), cos((M_PI * (float)k / step) + start_angle)));
1254 	}
1255 
1256 	if (segments > 1)
1257 	{
1258 		int sk;
1259 		for (int k = 0; k < sides; k++  )
1260 		{
1261 			sk = (k + 1) % sides;
1262 			QPointF kv = vertices.at(k);
1263 			QPointF skv =vertices.at(sk);
1264 			QPointF d = (skv - kv)/segments;
1265 			vertices.push_back(kv);
1266 			for (int j = 1; j < segments; j++)
1267 			{
1268 				vertices.push_back(kv + d * j);
1269 			}
1270 		}
1271 		vertices.erase(vertices.begin(), vertices.begin() + sides);
1272 	}
1273 }
1274 
1275 //TODO This should be done statically
1276 
1277 /**
1278  * Generates the same circle points that Gfrei's algorithm does
1279  */
generateCircle(std::vector<QPointF> & vertices,int segments)1280 void generateCircle(std::vector<QPointF> & vertices, int segments)
1281 {
1282 	return generatePolygon(vertices, segments, 1);
1283 }
1284 
generateSquare(std::vector<QPointF> & vertices,int segments)1285 void generateSquare(std::vector<QPointF> & vertices, int segments)
1286 {
1287 	return generatePolygon(vertices, 4, segments);
1288 }
1289 
1290