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
24 #include <math.h>
25 #include <limits>
26 #include <stdlib.h>
27 #include "decorate_background.h"
28 #include <wrap/gl/addons.h>
29
30 #include <meshlab/glarea.h>
31 #include <common/GLExtensionsManager.h>
32 #include <common/pluginmanager.h>
33
34
35 using namespace vcg;
36
decorationName(FilterIDType id) const37 QString DecorateBackgroundPlugin::decorationName(FilterIDType id) const
38 {
39 switch (id)
40 {
41 case DP_SHOW_CUBEMAPPED_ENV: return tr("Cube mapped background");
42 case DP_SHOW_GRID: return tr("Background Grid");
43 }
44 assert(0);
45 return QString();
46 }
47
decorationInfo(FilterIDType id) const48 QString DecorateBackgroundPlugin::decorationInfo(FilterIDType id) const
49 {
50 switch(id)
51 {
52 case DP_SHOW_CUBEMAPPED_ENV : return tr("Draws a customizable cube mapped background that is sync with trackball rotation");
53 case DP_SHOW_GRID : return tr("Draws a gridded background that can be used as a reference.");
54 }
55 assert(0);
56 return QString();
57 }
58
initGlobalParameterSet(QAction * action,RichParameterSet & parset)59 void DecorateBackgroundPlugin::initGlobalParameterSet(QAction *action, RichParameterSet &parset)
60 {
61 switch(ID(action))
62 {
63 case DP_SHOW_CUBEMAPPED_ENV :
64 if(!parset.hasParameter(CubeMapPathParam()))
65 {
66 QString cubemapDirPath = PluginManager::getBaseDirPath() + QString("/textures/cubemaps/uffizi.jpg");
67 //parset.addParam(new RichString(CubeMapPathParam(), cubemapDirPath,"",""));
68 }
69 break;
70 case DP_SHOW_GRID :
71 parset.addParam(new RichFloat(BoxRatioParam(),1.2f,"Box Ratio","The size of the grid around the object w.r.t. the bbox of the object"));
72 parset.addParam(new RichFloat(GridMajorParam(),10.0f,"Major Spacing",""));
73 parset.addParam(new RichFloat(GridMinorParam(),1.0f,"Minor Spacing",""));
74 parset.addParam(new RichBool(GridBackParam(),true,"Front grid culling",""));
75 parset.addParam(new RichBool(ShowShadowParam(),false,"Show silhouette",""));
76 parset.addParam(new RichColor(GridColorBackParam(), QColor(163,116,35,255), "Back Grid Color", ""));
77 parset.addParam(new RichColor(GridColorFrontParam(),QColor(22,139,119,255),"Front grid Color",""));
78 break;
79 }
80 }
81
startDecorate(QAction * action,MeshDocument &,RichParameterSet * parset,GLArea * gla)82 bool DecorateBackgroundPlugin::startDecorate( QAction * action, MeshDocument &/*m*/, RichParameterSet * parset, GLArea * gla)
83 {
84 if (!GLExtensionsManager::initializeGLextensions_notThrowing()) {
85 return false;
86 }
87 switch(ID(action))
88 {
89 case DP_SHOW_CUBEMAPPED_ENV :
90 if(parset->findParameter(CubeMapPathParam())== NULL) qDebug("CubeMapPath was not set!!!");
91 cubemapFileName = parset->getString(CubeMapPathParam());
92 break;
93 case DP_SHOW_GRID:
94 /*QMetaObject::Connection aaa =*/ connect(gla, SIGNAL(transmitShot(QString, Shotm)), this, SLOT(setValue(QString, Shotm)));
95 /*QMetaObject::Connection bbb =*/ connect(this, SIGNAL(askViewerShot(QString)), gla, SLOT(sendViewerShot(QString)));
96 break;
97 }
98 return true;
99 }
100
decorateDoc(QAction * a,MeshDocument & m,RichParameterSet * parset,GLArea * gla,QPainter *,GLLogStream &)101 void DecorateBackgroundPlugin::decorateDoc(QAction *a, MeshDocument &m, RichParameterSet * parset,GLArea * gla, QPainter *, GLLogStream &)
102 {
103 static QString lastname("uninitialized");
104 switch(ID(a))
105 {
106 case DP_SHOW_CUBEMAPPED_ENV :
107 {
108 if(!cm.IsValid() || (lastname != cubemapFileName ) )
109 {
110 qDebug( "Current CubeMapPath Dir: %s ",qUtf8Printable(cubemapFileName));
111 GLExtensionsManager::initializeGLextensions();
112 bool ret = cm.Load(qUtf8Printable(cubemapFileName));
113 lastname=cubemapFileName;
114 if(! ret ) return;
115 //QMessageBox::warning(gla,"Cubemapped background decoration","Warning unable to load cube map images: " + cubemapFileName );
116 cm.radius=10;
117 }
118 if(!cm.IsValid()) return;
119
120 Matrix44f tr;
121 glGetv(GL_MODELVIEW_MATRIX,tr);
122 // Remove the translation from the current matrix by simply padding the last column of the matrix
123 tr.SetColumn(3,Point4f(0,0,0,1.0));
124 //Remove the scaling from the the current matrix by adding an inverse scaling matrix
125 float scale = 1.0/pow(tr.Determinant(),1.0f/3.0f);
126 Matrix44f Scale;
127 Scale.SetDiagonal(scale);
128 tr=tr*Scale;
129
130 glMatrixMode(GL_PROJECTION);
131 glPushMatrix();
132 glMatrixMode(GL_MODELVIEW);
133 glPushMatrix();
134 cm.DrawEnvCube(tr);
135 glPopMatrix();
136 glMatrixMode(GL_PROJECTION);
137 glPopMatrix();
138 glMatrixMode(GL_MODELVIEW);
139 }
140 break;
141 case DP_SHOW_GRID :
142 {
143 emit this->askViewerShot("backGrid");
144
145 float scaleBB = parset->getFloat(BoxRatioParam());
146 float majorTick = fabs(parset->getFloat(GridMajorParam()));
147 float minorTick = fabs(parset->getFloat(GridMinorParam()));
148 bool backFlag = parset->getBool(GridBackParam());
149 bool shadowFlag = parset->getBool(ShowShadowParam());
150 Color4b backColor = parset->getColor4b(GridColorBackParam());
151 Color4b frontColor = parset->getColor4b(GridColorFrontParam());
152 Box3m bb = m.bbox();
153 float scalefactor = std::max(0.1, (scaleBB - 1.0));
154 bb.Offset((bb.max - bb.min)*(scalefactor/2.0));
155
156 // minortick should never be more than majortick
157 if (minorTick > majorTick)
158 minorTick = majorTick;
159
160 // check if user asked for a grid that is too dense
161 // if more than 100-200k ticks, the rendering will slow down too much and crash on some drivers
162 int ticks = ((bb.Dim()[0] + bb.Dim()[1] + bb.Dim()[2]) / minorTick) + ((bb.Dim()[0] + bb.Dim()[1] + bb.Dim()[2]) / majorTick);
163 if (ticks > 200000)
164 {
165 if (log10(bb.Diag()) > 0.0)
166 majorTick = pow(10, floor(log10(bb.Diag()) -1));
167 else
168 majorTick = pow(10, floor(log10(bb.Diag()) + 1));
169 minorTick = majorTick / 2.0;
170 }
171
172 MLSceneGLSharedDataContext* shared = NULL;
173 QGLContext* cont = NULL;
174 if ((gla != NULL) && (gla->mvc() != NULL))
175 {
176 cont = gla->context();
177 shared = gla->mvc()->sharedDataContext();
178 }
179
180 DrawGriddedCube(shared,cont,*m.mm(), bb, majorTick, minorTick, backFlag, shadowFlag, backColor, frontColor);
181 }
182 break;
183 }
184 }
185
186
187 // Note minG/maxG is wider than minP/maxP.
DrawGridPlane(int axis,int side,Point3m minP,Point3m maxP,Point3m minG,Point3m maxG,float majorTick,float minorTick,Color4b lineColor)188 void DrawGridPlane(int axis,
189 int side, // 0 is min 1 is max
190 Point3m minP, Point3m maxP,
191 Point3m minG, Point3m maxG, // the box with vertex positions snapped to the grid (enlarging it).
192 float majorTick, float minorTick,
193 Color4b lineColor)
194 {
195 int xAxis = (1+axis)%3;
196 int yAxis = (2+axis)%3;
197 int zAxis = (0+axis)%3; // the axis perpendicular to the plane we want to draw (e.g. if i want to draw plane xy I write '2')
198
199 Color4b majorColor=lineColor;
200 Color4b minorColor;
201 Color4b axisColor;
202 minorColor[0] = std::min(255.0, lineColor[0] * 2.0); // minorcolor is 2 times brighter and half solid w.r.t. majorcolor
203 minorColor[1] = std::min(255.0, lineColor[1] * 2.0);
204 minorColor[2] = std::min(255.0, lineColor[2] * 2.0);
205 minorColor[3] = std::min(127.0, lineColor[3] / 2.0);
206 axisColor[0] = lineColor[0] * 0.66; // axiscolor is 2/3 darker w.r.t. majorcolor
207 axisColor[1] = lineColor[1] * 0.66;
208 axisColor[2] = lineColor[2] * 0.66;
209 axisColor[3] = 255;
210
211 // We draw orizontal and vertical lines onto the XY plane snapped with the major ticks
212 Point3m p1,p2,p3,p4;
213 p1[zAxis] = p2[zAxis] = p3[zAxis] = p4[zAxis] = side ? maxG[zAxis] : minG[zAxis];
214
215 float aMin,aMax,bMin,bMax;
216
217 p1[yAxis] = minG[yAxis];
218 p2[yAxis] = maxG[yAxis];
219 p3[xAxis] = minG[xAxis];
220 p4[xAxis] = maxG[xAxis];
221 aMin = minG[xAxis];
222 aMax = maxG[xAxis];
223 bMin = minG[yAxis];
224 bMax = maxG[yAxis];
225
226 glLineWidth(0.5f);
227 glColor(minorColor);
228 glBegin(GL_LINES);
229 for (float alpha = aMin; alpha <= aMax; alpha += minorTick)
230 {
231 p1[xAxis] = p2[xAxis] = alpha;
232 glVertex(p1); glVertex(p2);
233 }
234 for (float alpha = bMin; alpha <= bMax; alpha += minorTick)
235 {
236 p3[yAxis] = p4[yAxis] = alpha;
237 glVertex(p3); glVertex(p4);
238 }
239 glEnd();
240
241 glLineWidth(1.0f);
242 glColor(majorColor);
243 glBegin(GL_LINES);
244 for (float alpha = aMin; alpha <= aMax; alpha += majorTick)
245 {
246 p1[xAxis] = p2[xAxis] = alpha;
247 glVertex(p1); glVertex(p2);
248 }
249 for (float alpha = bMin; alpha <= bMax; alpha += majorTick)
250 {
251 p3[yAxis] = p4[yAxis] = alpha;
252 glVertex(p3); glVertex(p4);
253 }
254 glEnd();
255
256 // Draw the axis
257 glColor(axisColor);
258 glLineWidth(1.5f);
259 glBegin(GL_LINES);
260 if(minP[xAxis]*maxP[xAxis] <0 )
261 {
262 p1[yAxis]=minG[yAxis];
263 p2[yAxis]=maxG[yAxis];
264 p1[xAxis]=p2[xAxis]=0;
265 glVertex(p1);
266 glVertex(p2);
267 }
268 if(minP[yAxis]*maxP[yAxis] <0 )
269 {
270 p1[xAxis]=minG[xAxis];
271 p2[xAxis]=maxG[xAxis];
272 p1[yAxis]=p2[yAxis]=0;
273 glVertex(p1);
274 glVertex(p2);
275 }
276 glEnd();
277 }
278
279 /* return true if the side of a box is front facing with respet of the give viewpoint.
280 side 0, axis i == min on than i-th axis
281 side 1, axis i == min on than i-th axis
282 questo capita se il prodotto scalare tra il vettore normale entro della faccia
283 */
FrontFacing(Point3m viewPos,int axis,int side,Point3m minP,Point3m maxP)284 bool FrontFacing(Point3m viewPos,
285 int axis,
286 int side,
287 Point3m minP,
288 Point3m maxP)
289 {
290 assert (side==0 || side ==1);
291 assert (axis>=0 && axis < 3);
292 Point3m N(0,0,0);
293 Point3m C = (minP+maxP)/2.0;
294
295 if(side == 1) {
296 C[axis] = maxP[axis];
297 N[axis]=-1;
298 }
299
300 if(side == 0) {
301 C[axis] = minP[axis];
302 N[axis]=1;
303 }
304 Point3m vpc = viewPos-C;
305 // qDebug("FaceCenter %f %f %f - %f %f %f",C[0],C[1],C[2],N[0],N[1],N[2]);
306 // qDebug("VPC %f %f %f",vpc[0],vpc[1],vpc[2]);
307 return vpc*N > 0;
308 }
309
DrawFlatMesh(MLSceneGLSharedDataContext * shared,QGLContext * cont,MeshModel & m,int axis,int side,Point3m minG,Point3m maxG)310 void DrawFlatMesh(MLSceneGLSharedDataContext* shared,QGLContext* cont,MeshModel &m, int axis, int side, Point3m minG, Point3m maxG)
311 {
312 if ((shared == NULL) || (cont == NULL))
313 return;
314 glPushAttrib(GL_ALL_ATTRIB_BITS);
315 glDisable(GL_LIGHTING);
316 glPushMatrix();
317 Point3m trans = side?maxG:minG;
318 Point3m scale(1.0f,1.0f,1.0);
319 trans[(axis+1)%3]=0;
320 trans[(axis+2)%3]=0;
321 scale[axis]=0;
322 glTranslate(trans);
323 glScale(scale);
324 shared->draw(m.id(),cont);
325 // m.render(GLW::DMFlat,GLW::CMNone,GLW::TMNone);
326 glPopMatrix();
327 glPopAttrib();
328 }
329
DrawGriddedCube(MLSceneGLSharedDataContext * shared,QGLContext * cont,MeshModel & m,const Box3m & bb,Scalarm majorTick,Scalarm minorTick,bool backCullFlag,bool shadowFlag,Color4b frontColor,Color4b backColor)330 void DecorateBackgroundPlugin::DrawGriddedCube(MLSceneGLSharedDataContext* shared,QGLContext* cont,MeshModel &m, const Box3m &bb, Scalarm majorTick, Scalarm minorTick, bool backCullFlag, bool shadowFlag, Color4b frontColor, Color4b backColor)
331 {
332 glPushAttrib(GL_ALL_ATTRIB_BITS);
333 Point3m minP,maxP, minG,maxG;
334 minP=bb.min;maxP=bb.max;
335
336 // Make the box well rounded wrt to major tick (only increase)
337 for(int i=0;i<3;++i) // foreach axis
338 {
339 if (minP[i] == 0)
340 minG[i] = -majorTick;
341 else
342 minG[i] = minP[i] + fmod(fabs(minP[i]), majorTick) - majorTick;
343
344 if (maxP[i] == 0)
345 maxG[i] = majorTick;
346 else
347 maxG[i] = maxP[i] - fmod(fabs(maxP[i]), majorTick) + majorTick;
348 }
349
350 glDisable(GL_LIGHTING);
351 glDisable(GL_COLOR_MATERIAL);
352 glColor3f(0.8f,0.8f,0.8f);
353 glEnable(GL_LINE_SMOOTH);
354 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
355 glEnable(GL_BLEND);
356 glDepthMask(GL_FALSE);
357 Point3m viewPos = Point3m::Construct(this->curShot.GetViewPoint());
358 // qDebug("BG Grid MajorTick %4.2f MinorTick %4.2f ## camera pos %7.3f %7.3f %7.3f", majorTick, minorTick, viewPos[0],viewPos[1],viewPos[2]);
359 // qDebug("BG Grid boxF %7.3f %7.3f %7.3f # %7.3f %7.3f %7.3f",minP[0],minP[1],minP[2],maxP[0],maxP[1],maxP[2]);
360 // qDebug("BG Grid boxG %7.3f %7.3f %7.3f # %7.3f %7.3f %7.3f",minG[0],minG[1],minG[2],maxG[0],maxG[1],maxG[2]);
361 for (int ii=0;ii<3;++ii)
362 {
363 for(int jj=0;jj<2;++jj)
364 {
365 bool front = FrontFacing(viewPos,ii,jj,minP,maxP);
366 if( front || !backCullFlag)
367 {
368 DrawGridPlane(ii,jj,minP,maxP,minG,maxG,majorTick,minorTick,front?frontColor:backColor);
369 if(shadowFlag)
370 {
371 glPushAttrib(GL_COLOR_BUFFER_BIT);
372 glBlendColor(1.0f,1.0f,1.0f,0.4f);
373 glBlendFunc(GL_CONSTANT_COLOR, GL_ONE);
374 DrawFlatMesh(shared,cont,m,ii,jj,minG,maxG);
375 glPopAttrib();
376 }
377 }
378 }
379 }
380 glDisable(GL_BLEND);
381 glPopAttrib();
382 }
383
setValue(QString,Shotm val)384 void DecorateBackgroundPlugin::setValue(QString, Shotm val)
385 {
386 curShot=val;
387 }
388
389 MESHLAB_PLUGIN_NAME_EXPORTER(DecorateBackgroundPlugin)
390