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