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