diff options
Diffstat (limited to 'source/blender/freestyle/intern/application')
-rw-r--r-- | source/blender/freestyle/intern/application/AppCanvas.cpp | 218 | ||||
-rw-r--r-- | source/blender/freestyle/intern/application/AppCanvas.h | 101 | ||||
-rw-r--r-- | source/blender/freestyle/intern/application/AppConfig.cpp | 112 | ||||
-rw-r--r-- | source/blender/freestyle/intern/application/AppConfig.h | 112 | ||||
-rw-r--r-- | source/blender/freestyle/intern/application/AppView.cpp | 198 | ||||
-rw-r--r-- | source/blender/freestyle/intern/application/AppView.h | 245 | ||||
-rw-r--r-- | source/blender/freestyle/intern/application/Controller.cpp | 1073 | ||||
-rw-r--r-- | source/blender/freestyle/intern/application/Controller.h | 261 |
8 files changed, 2320 insertions, 0 deletions
diff --git a/source/blender/freestyle/intern/application/AppCanvas.cpp b/source/blender/freestyle/intern/application/AppCanvas.cpp new file mode 100644 index 00000000000..06391717bb9 --- /dev/null +++ b/source/blender/freestyle/intern/application/AppCanvas.cpp @@ -0,0 +1,218 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/freestyle/intern/application/AppCanvas.cpp + * \ingroup freestyle + */ + +#include "Controller.h" +#include "AppView.h" +#include "../image/Image.h" +#include "../system/TimeStamp.h" +#include "../stroke/StrokeRenderer.h" +#include "AppCanvas.h" +#include "AppConfig.h" +#include "../stroke/StyleModule.h" + +#include "../system/StringUtils.h" + +AppCanvas::AppCanvas() +:Canvas() +{ + _pViewer = 0; + _MapsPath = StringUtils::toAscii(Config::Path::getInstance()->getMapsDir()).c_str(); +} + +AppCanvas::AppCanvas(AppView* iViewer) +:Canvas() +{ + _pViewer = iViewer; +} + +AppCanvas::AppCanvas(const AppCanvas& iBrother) +:Canvas(iBrother) +{ + _pViewer = iBrother._pViewer; +} + +AppCanvas::~AppCanvas() +{ + _pViewer = 0; +} + +void AppCanvas::setViewer(AppView *iViewer) +{ + _pViewer = iViewer; +} + +int AppCanvas::width() const +{ + return _pViewer->width(); +} + +int AppCanvas::height() const +{ + return _pViewer->height(); +} + +BBox<Vec2i> AppCanvas::border() const +{ + return _pViewer->border(); +} + +float AppCanvas::thickness() const +{ + return _pViewer->thickness(); +} + +BBox<Vec3r> AppCanvas::scene3DBBox() const +{ + return _pViewer->scene3DBBox(); +} + +void AppCanvas::preDraw() +{ + Canvas::preDraw(); +} + +void AppCanvas::init() +{ +#if 0 + static bool firsttime = true; + if (firsttime) { + _Renderer = new BlenderStrokeRenderer; + if(!StrokeRenderer::loadTextures()) { + cerr << "unable to load stroke textures" << endl; + return; + } + } +#endif +} + +void AppCanvas::postDraw() +{ + for (unsigned int i = 0; i < _StyleModules.size(); i++) { + if(!_StyleModules[i]->getDisplayed() || !_Layers[i]) + continue; + _Layers[i]->ScaleThickness(thickness()); + } + Canvas::postDraw(); +} + +void AppCanvas::Erase() +{ + Canvas::Erase(); +} + +// Abstract + +void AppCanvas::readColorPixels(int x,int y,int w, int h, RGBImage& oImage) const +{ + float *rgb = new float[3*w*h]; + memset(rgb, 0, sizeof(float) * 3 * w * h); + int xsch = width(); + int ysch = height(); + if (_pass_diffuse.buf) { + int xmin = border().getMin().x(); + int ymin = border().getMin().y(); + int xmax = border().getMax().x(); + int ymax = border().getMax().y(); + int rectx = _pass_z.width; + int recty = _pass_z.height; + float xfac = ((float)rectx) / ((float)(xmax - xmin)); + float yfac = ((float)recty) / ((float)(ymax - ymin)); +#if 0 + if (G.debug & G_DEBUG_FREESTYLE) { + printf("readColorPixels %d x %d @ (%d, %d) in %d x %d [%d x %d] -- %d x %d @ %d%%\n", w, h, x, y, xsch, ysch, + xmax - xmin, ymax - ymin, rectx, recty, (int)(xfac * 100.0f)); + } +#endif + int ii, jj; + for (int j = 0; j < h; j++) { + jj = (int)((y - ymin + j) * yfac); + if (jj < 0 || jj >= recty) + continue; + for (int i = 0; i < w; i++) { + ii = (int)((x - xmin + i) * xfac); + if (ii < 0 || ii >= rectx) + continue; + memcpy(rgb + (w * j + i) * 3, _pass_diffuse.buf + (rectx * jj + ii) * 3, sizeof(float) * 3); + } + } + } + oImage.setArray(rgb, xsch, ysch, w, h, x, y, false); +} + +void AppCanvas::readDepthPixels(int x,int y,int w, int h, GrayImage& oImage) const +{ + float *z = new float[w*h]; + memset(z, 0, sizeof(float) * w * h); + int xsch = width(); + int ysch = height(); + if (_pass_z.buf) { + int xmin = border().getMin().x(); + int ymin = border().getMin().y(); + int xmax = border().getMax().x(); + int ymax = border().getMax().y(); + int rectx = _pass_z.width; + int recty = _pass_z.height; + float xfac = ((float)rectx) / ((float)(xmax - xmin)); + float yfac = ((float)recty) / ((float)(ymax - ymin)); +#if 0 + if (G.debug & G_DEBUG_FREESTYLE) { + printf("readDepthPixels %d x %d @ (%d, %d) in %d x %d [%d x %d] -- %d x %d @ %d%%\n", w, h, x, y, xsch, ysch, + xmax - xmin, ymax - ymin, rectx, recty, (int)(xfac * 100.0f)); + } +#endif + int ii, jj; + for (int j = 0; j < h; j++) { + jj = (int)((y - ymin + j) * yfac); + if (jj < 0 || jj >= recty) + continue; + for (int i = 0; i < w; i++) { + ii = (int)((x - xmin + i) * xfac); + if (ii < 0 || ii >= rectx) + continue; + z[w * j + i] = _pass_z.buf[rectx * jj + ii]; + } + } + } + oImage.setArray(z, xsch, ysch, w, h, x, y, false); +} + +void AppCanvas::RenderStroke(Stroke *iStroke) +{ + if(_basic) + iStroke->RenderBasic(_Renderer); + else + iStroke->Render(_Renderer); +} + + +void AppCanvas::update() +{ +} diff --git a/source/blender/freestyle/intern/application/AppCanvas.h b/source/blender/freestyle/intern/application/AppCanvas.h new file mode 100644 index 00000000000..3a65020463c --- /dev/null +++ b/source/blender/freestyle/intern/application/AppCanvas.h @@ -0,0 +1,101 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __APPCANVAS_H__ +#define __APPCANVAS_H__ + +/** \file blender/freestyle/intern/application/AppCanvas.h + * \ingroup freestyle + */ + +#include "../stroke/Canvas.h" +#include "AppView.h" + +class AppCanvas : public Canvas +{ +public: + AppCanvas(); + AppCanvas(AppView *iViewer); + AppCanvas(const AppCanvas& iBrother); + virtual ~AppCanvas(); + + /*! operations that need to be done before a draw */ + virtual void preDraw(); + + /*! operations that need to be done after a draw */ + virtual void postDraw(); + + /*! Erases the layers and clears the canvas */ + virtual void Erase(); + + /* init the canvas */ + virtual void init(); + + /*! Reads a pixel area from the canvas */ + virtual void readColorPixels(int x,int y,int w, int h, RGBImage& oImage) const; + /*! Reads a depth pixel area from the canvas */ + virtual void readDepthPixels(int x,int y,int w, int h, GrayImage& oImage) const; + + virtual BBox<Vec3r> scene3DBBox() const; + + /* abstract */ + virtual void RenderStroke(Stroke*); + virtual void update(); + + + /*! accessors */ + virtual int width() const; + virtual int height() const; + virtual BBox<Vec2i> border() const; + virtual float thickness() const; + + AppView *_pViewer; + inline const AppView * viewer() const {return _pViewer;} + + /*! modifiers */ + void setViewer(AppView *iViewer); + + /* soc */ + void setPassDiffuse(float *buf, int width, int height) { + _pass_diffuse.buf = buf; + _pass_diffuse.width = width; + _pass_diffuse.height = height; + } + void setPassZ(float *buf, int width, int height) { + _pass_z.buf = buf; + _pass_z.width = width; + _pass_z.height = height; + } + +private: + struct { + float *buf; + int width, height; + } _pass_diffuse, _pass_z; +}; + +#endif // __APPCANVAS_H__ diff --git a/source/blender/freestyle/intern/application/AppConfig.cpp b/source/blender/freestyle/intern/application/AppConfig.cpp new file mode 100644 index 00000000000..f687117c762 --- /dev/null +++ b/source/blender/freestyle/intern/application/AppConfig.cpp @@ -0,0 +1,112 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/freestyle/intern/application/AppConfig.cpp + * \ingroup freestyle + */ + +#include "AppConfig.h" +#include <iostream> + +#include "../system/StringUtils.h" + +using namespace std; + +extern "C" { +#include "BLI_path_util.h" +} + +namespace Config { + +Path* Path::_pInstance = 0; +Path::Path() +{ + // get the root directory + // soc + setRootDir(BLI_get_folder(BLENDER_SYSTEM_SCRIPTS, NULL)); + + _pInstance = this; +} + +void Path::setRootDir(const string& iRootDir) +{ + _ProjectDir = iRootDir + string(DIR_SEP.c_str()) + "freestyle"; + _ModelsPath = ""; + _PatternsPath = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "textures" + + string(DIR_SEP.c_str()) + "variation_patterns" + string(DIR_SEP.c_str()); + _BrushesPath = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "textures" + + string(DIR_SEP.c_str()) + "brushes" + string(DIR_SEP.c_str()); + _PythonPath = _ProjectDir + string(DIR_SEP.c_str()) + "style_modules" + string(DIR_SEP.c_str()); + if (getenv("PYTHONPATH")) { + _PythonPath += string(PATH_SEP.c_str()) + string(getenv("PYTHONPATH")); + } +#ifdef WIN32 + _BrowserCmd = "C:\\Program Files\\Internet Explorer\\iexplore.exe %s"; +#else + _BrowserCmd = "mozilla %s"; +#endif + _HelpIndexPath = _ProjectDir + string(DIR_SEP.c_str()) + "doc" + string(DIR_SEP.c_str()) + "html" + + string(DIR_SEP.c_str()) + "index.html"; + _EnvMapDir = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "env_map" + + string(DIR_SEP.c_str()); + _MapsDir = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "maps" + + string(DIR_SEP.c_str()); +} + +void Path::setHomeDir(const string& iHomeDir) +{ + _HomeDir = iHomeDir; +} + +Path::~Path() +{ + _pInstance = 0; +} + +Path* Path::getInstance() +{ + return _pInstance; +} + +string Path::getEnvVar(const string& iEnvVarName) +{ + string value; + if (!getenv(StringUtils::toAscii(iEnvVarName).c_str())) { + cerr << "Warning: You may want to set the $" + << StringUtils::toAscii(iEnvVarName) + << " environment variable to use Freestyle." << endl + << " Otherwise, the current directory will be used instead." + << endl; + value = "."; + } + else { + value = getenv(StringUtils::toAscii(iEnvVarName).c_str()); + } + return value; +} + +} // End of namepace Config diff --git a/source/blender/freestyle/intern/application/AppConfig.h b/source/blender/freestyle/intern/application/AppConfig.h new file mode 100644 index 00000000000..ebd6f85db70 --- /dev/null +++ b/source/blender/freestyle/intern/application/AppConfig.h @@ -0,0 +1,112 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __APP_CONFIG_H__ +#define __APP_CONFIG_H__ + +/** \file blender/freestyle/intern/application/AppConfig.h + * \ingroup freestyle + * \brief Configuration file + * \author Emmanuel Turquin + * \date 26/02/2003 + */ + +#include <string> +#include "../system/FreestyleConfig.h" +#include "../system/Precision.h" + +using namespace std; + +namespace Config { + +class Path{ +protected: + static Path * _pInstance; + string _ProjectDir; + string _ModelsPath; + string _PatternsPath; + string _BrushesPath; + string _PythonPath; + string _BrowserCmd; + string _HelpIndexPath; + string _EnvMapDir; + string _MapsDir; + string _HomeDir; + +public: + Path(); + virtual ~Path(); + static Path* getInstance(); + + void setRootDir(const string& iRootDir); + void setHomeDir(const string& iHomeDir); + + const string& getProjectDir() const {return _ProjectDir;} + const string& getModelsPath() const {return _ModelsPath;} + const string& getPatternsPath() const {return _PatternsPath;} + const string& getBrushesPath() const {return _BrushesPath;} + const string& getPythonPath() const {return _PythonPath;} + const string& getBrowserCmd() const {return _BrowserCmd;} + const string& getHelpIndexpath() const {return _HelpIndexPath;} + const string& getEnvMapDir() const {return _EnvMapDir;} + const string& getMapsDir() const {return _MapsDir;} + const string& getHomeDir() const {return _HomeDir;} + + static string getEnvVar(const string& iEnvVarName); +}; + +// +// Configuration, default values +// +////////////////////////////////////////////////////////////// + +// Application +static const string APPLICATION_NAME("APPNAME"); +static const string APPLICATION_VERSION("APPVERSION"); + +// ViewMap +static const string VIEWMAP_EXTENSION("vm"); +static const string VIEWMAP_MAGIC("ViewMap File"); +static const string VIEWMAP_VERSION("1.9"); + +// Style modules +static const string STYLE_MODULE_EXTENSION("py"); +static const string STYLE_MODULES_LIST_EXTENSION("sml"); + +// Options +static const string OPTIONS_DIR("." + APPLICATION_NAME); +static const string OPTIONS_FILE("options.xml"); +static const string OPTIONS_CURRENT_DIRS_FILE("current_dirs.xml"); +static const string OPTIONS_QGLVIEWER_FILE("qglviewer.xml"); + +// Default options +static const real DEFAULT_SPHERE_RADIUS = 1.0; +static const real DEFAULT_DKR_EPSILON = 0.0; + +} // End of namepace Config + +#endif // __APP_CONFIG_H__ diff --git a/source/blender/freestyle/intern/application/AppView.cpp b/source/blender/freestyle/intern/application/AppView.cpp new file mode 100644 index 00000000000..e09d958d564 --- /dev/null +++ b/source/blender/freestyle/intern/application/AppView.cpp @@ -0,0 +1,198 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/freestyle/intern/application/AppView.cpp + * \ingroup freestyle + */ + +/* This header file needs to be included first, in order to avoid a + compilation with MinGW (see the commit log of revision 28253) */ +extern "C" { +#include "BLI_jitter.h" +} + +#include <iostream> + +#include "Controller.h" +#include "AppConfig.h" +#include "AppView.h" +#include "../view_map/Silhouette.h" +#include "../view_map/ViewMap.h" +#include "../scene_graph/LineRep.h" +#include "../scene_graph/NodeLight.h" +#include "../scene_graph/NodeShape.h" +#include "../scene_graph/VertexRep.h" +#include "../stroke/Canvas.h" +#include "../system/StringUtils.h" + +extern "C" { +#include "BLI_blenlib.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#if 1 // FRS_antialiasing +# include "BKE_global.h" +# include "DNA_scene_types.h" +#endif + +#include "FRS_freestyle.h" +} + +AppView::AppView(const char *iName) +{ + _Fovy = DEG2RADF(30.0f); + _ModelRootNode = new NodeDrawingStyle; + _SilhouetteRootNode = new NodeDrawingStyle; + _DebugRootNode = new NodeDrawingStyle; + + _RootNode.AddChild(_ModelRootNode); + _SilhouetteRootNode->setStyle(DrawingStyle::LINES); + _SilhouetteRootNode->setLightingEnabled(false); + _SilhouetteRootNode->setLineWidth(2.0f); + _SilhouetteRootNode->setPointSize(3.0f); + + _RootNode.AddChild(_SilhouetteRootNode); + + _DebugRootNode->setStyle(DrawingStyle::LINES); + _DebugRootNode->setLightingEnabled(false); + _DebugRootNode->setLineWidth(1.0f); + + _RootNode.AddChild(_DebugRootNode); + + _minBBox = __min(__min(_ModelRootNode->bbox().getMin()[0], _ModelRootNode->bbox().getMin()[1]), + _ModelRootNode->bbox().getMin()[2]); + _maxBBox = __max(__max(_ModelRootNode->bbox().getMax()[0], _ModelRootNode->bbox().getMax()[1]), + _ModelRootNode->bbox().getMax()[2]); + + _maxAbs = __max(rabs(_minBBox), rabs(_maxBBox)); + _minAbs = __min(rabs(_minBBox), rabs(_maxBBox)); + + _p2DSelectionNode = new NodeDrawingStyle; + _p2DSelectionNode->setLightingEnabled(false); + _p2DSelectionNode->setStyle(DrawingStyle::LINES); + _p2DSelectionNode->setLineWidth(5.0f); + + _p2DNode.AddChild(_p2DSelectionNode); + + NodeLight *light = new NodeLight; + _Light.AddChild(light); +} + +AppView::~AppView() +{ + /*int ref =*/ /* UNUSED */ _RootNode.destroy(); + + _Light.destroy(); + /*ref =*/ /* UNUSED */ _p2DNode.destroy(); +} + +real AppView::distanceToSceneCenter() +{ + BBox<Vec3r> bbox = _ModelRootNode->bbox(); + + Vec3r v(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]); + v -= 0.5 * (bbox.getMin() + bbox.getMax()); + + return v.norm(); +} + +real AppView::znear() +{ + BBox<Vec3r> bbox = _ModelRootNode->bbox(); + Vec3r u = bbox.getMin(); + Vec3r v = bbox.getMax(); + Vec3r cameraCenter(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]); + + Vec3r w1(u[0], u[1], u[2]); + Vec3r w2(v[0], u[1], u[2]); + Vec3r w3(u[0], v[1], u[2]); + Vec3r w4(v[0], v[1], u[2]); + Vec3r w5(u[0], u[1], v[2]); + Vec3r w6(v[0], u[1], v[2]); + Vec3r w7(u[0], v[1], v[2]); + Vec3r w8(v[0], v[1], v[2]); + + real _znear = __min((w1 - cameraCenter).norm(), + __min((w2 - cameraCenter).norm(), + __min((w3 - cameraCenter).norm(), + __min((w4 - cameraCenter).norm(), + __min((w5 - cameraCenter).norm(), + __min((w6 - cameraCenter).norm(), + __min((w7 - cameraCenter).norm(), + (w8 - cameraCenter).norm() + ) + ) + ) + ) + ) + ) + ); + + return __max(_znear, 0.001); +} + +real AppView::zfar() +{ + BBox<Vec3r> bbox = _ModelRootNode->bbox(); + Vec3r u = bbox.getMin(); + Vec3r v = bbox.getMax(); + Vec3r cameraCenter(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]); + + Vec3r w1(u[0], u[1], u[2]); + Vec3r w2(v[0], u[1], u[2]); + Vec3r w3(u[0], v[1], u[2]); + Vec3r w4(v[0], v[1], u[2]); + Vec3r w5(u[0], u[1], v[2]); + Vec3r w6(v[0], u[1], v[2]); + Vec3r w7(u[0], v[1], v[2]); + Vec3r w8(v[0], v[1], v[2]); + + real _zfar = __max((w1 - cameraCenter).norm(), + __max((w2 - cameraCenter).norm(), + __max((w3 - cameraCenter).norm(), + __max((w4 - cameraCenter).norm(), + __max((w5 - cameraCenter).norm(), + __max((w6 - cameraCenter).norm(), + __max((w7 - cameraCenter).norm(), + (w8 - cameraCenter).norm() + ) + ) + ) + ) + ) + ) + ); + + return _zfar; +} + +real AppView::GetFocalLength() +{ + real Near = __max(0.1, (real)(-2.0f * _maxAbs + distanceToSceneCenter())); + return Near; +} diff --git a/source/blender/freestyle/intern/application/AppView.h b/source/blender/freestyle/intern/application/AppView.h new file mode 100644 index 00000000000..0763a33a212 --- /dev/null +++ b/source/blender/freestyle/intern/application/AppView.h @@ -0,0 +1,245 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __APPVIEW_H__ +#define __APPVIEW_H__ + +/** \file blender/freestyle/intern/application/AppView.h + * \ingroup freestyle + */ + +#if !defined(WIN32) || defined(__GNUC__) +# include <algorithm> +# define __min(x,y) (min(x,y)) +# define __max(x,y) (max(x,y)) + using namespace std; +#endif // WIN32 + +#include "AppConfig.h" +#include "../geometry/Geom.h" +#include "../geometry/BBox.h" +#include "../scene_graph/NodeDrawingStyle.h" +#include "../system/Precision.h" + +using namespace Geometry; + +class AppView +{ +public: + AppView(const char *iName = 0); + virtual ~AppView(); + +public: + //inherited + inline unsigned int width() {return _width;} + inline unsigned int height() {return _height;} + inline BBox<Vec2i> border() {return _border;} + inline float thickness() {return _thickness;} + inline void setWidth(unsigned int width) {_width = width;} + inline void setHeight(unsigned int height) {_height = height;} + inline void setBorder(int xmin, int ymin, int xmax, int ymax) { + _border = BBox<Vec2i>(Vec2i(xmin, ymin), Vec2i(xmax, ymax)); + } + inline void setThickness(float thickness) {_thickness = thickness;} + +protected: + unsigned int _width, _height; + BBox<Vec2i> _border; + float _thickness; + +public: + /*! Sets the model to draw in the viewer + * iModel + * The Root Node of the model + */ + inline void setModel(NodeGroup *iModel) + { + if (0 != _ModelRootNode->numberOfChildren()) { + _ModelRootNode->DetachChildren(); + _ModelRootNode->clearBBox(); + } + + AddModel(iModel); + } + + /*! Adds a model for displaying in the viewer */ + inline void AddModel(NodeGroup *iModel) + { + _ModelRootNode->AddChild(iModel); + _ModelRootNode->UpdateBBox(); + + _minBBox = __min(__min(_ModelRootNode->bbox().getMin()[0], _ModelRootNode->bbox().getMin()[1]), + _ModelRootNode->bbox().getMin()[2]); + _maxBBox = __max(__max(_ModelRootNode->bbox().getMax()[0], _ModelRootNode->bbox().getMax()[1]), + _ModelRootNode->bbox().getMax()[2]); + + _maxAbs = __max(rabs(_minBBox), rabs(_maxBBox)); + _minAbs = __min(rabs(_minBBox), rabs(_maxBBox)); + } + + inline void AddSilhouette(NodeGroup* iSilhouette) + { + _SilhouetteRootNode->AddChild(iSilhouette); + } + + inline void Add2DSilhouette(NodeGroup *iSilhouette) + { + //_pFENode->AddChild(iSilhouette); + } + + inline void Add2DVisibleSilhouette(NodeGroup *iVSilhouette) + { + //_pVisibleSilhouetteNode->AddChild(iVSilhouette); + } + + inline void setDebug(NodeGroup* iDebug) + { + if (0 != _DebugRootNode->numberOfChildren()) { + _DebugRootNode->DetachChildren(); + _DebugRootNode->clearBBox(); + } + + AddDebug(iDebug); + } + + inline void AddDebug(NodeGroup* iDebug) + { + _DebugRootNode->AddChild(iDebug); + } + + inline void DetachModel(Node *iModel) + { + _ModelRootNode->DetachChild(iModel); + _ModelRootNode->UpdateBBox(); + + _minBBox = __min(__min(_ModelRootNode->bbox().getMin()[0], _ModelRootNode->bbox().getMin()[1]), + _ModelRootNode->bbox().getMin()[2]); + _maxBBox = __max(__max(_ModelRootNode->bbox().getMax()[0], _ModelRootNode->bbox().getMax()[1]), + _ModelRootNode->bbox().getMax()[2]); + + _maxAbs = __max(rabs(_minBBox), rabs(_maxBBox)); + _minAbs = __min(rabs(_minBBox), rabs(_maxBBox)); + } + + inline void DetachModel() + { + _ModelRootNode->DetachChildren(); + _ModelRootNode->clearBBox(); + +#if 0 + // 2D Scene + _p2DNode.DetachChildren(); + _pFENode->DetachChildren(); + _pVisibleSilhouetteNode->DetachChildren(); +#endif + } + + inline void DetachSilhouette() + { + _SilhouetteRootNode->DetachChildren(); +#if 0 + _pFENode->DetachChildren(); + _pVisibleSilhouetteNode->DetachChildren(); +#endif + _p2DSelectionNode->destroy(); + } + + inline void DetachVisibleSilhouette() + { + //_pVisibleSilhouetteNode->DetachChildren(); + _p2DSelectionNode->destroy(); + } + + inline void DetachDebug() + { + _DebugRootNode->DetachChildren(); + } + + real distanceToSceneCenter(); + real GetFocalLength(); + + inline real GetAspect() const + { + return ((real)_width / (real)_height); + } + + void setHorizontalFov(float hfov) + { + _Fovy = 2.0 * atan (tan(hfov / 2.0) / GetAspect()); + } + + inline real GetFovyRadian() const + { + return _Fovy; + } + + inline real GetFovyDegrees() const + { + return _Fovy * 180.0 / M_PI; // TODO Use RAD2DEG here too? + } + + BBox<Vec3r> scene3DBBox() const {return _ModelRootNode->bbox();} + + real znear(); + real zfar(); + +public: + /*! Core scene drawing */ + void DrawScene(SceneVisitor *iRenderer); + + /*! 2D Scene Drawing */ + void Draw2DScene(SceneVisitor *iRenderer); + +protected: + /*! fabs or abs */ + inline int rabs(int x) {return abs(x);} + inline real rabs(real x) {return fabs(x);} + +protected: + float _Fovy; + + //The root node container + NodeGroup _RootNode; + NodeDrawingStyle *_ModelRootNode; + NodeDrawingStyle *_SilhouetteRootNode; + NodeDrawingStyle *_DebugRootNode; + + NodeGroup _Light; + + real _minBBox; + real _maxBBox; + real _maxAbs; + real _minAbs; + + // 2D Scene + bool _Draw2DScene; + bool _Draw3DScene; + NodeGroup _p2DNode; + NodeDrawingStyle *_p2DSelectionNode; +}; + +#endif // __APPVIEW_H__ diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp new file mode 100644 index 00000000000..662686c2524 --- /dev/null +++ b/source/blender/freestyle/intern/application/Controller.cpp @@ -0,0 +1,1073 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/freestyle/intern/application/Controller.cpp + * \ingroup freestyle + */ + +#include <string> +#include <fstream> +#include <float.h> + +#include "AppView.h" +#include "AppCanvas.h" +#include "AppConfig.h" +#include "Controller.h" + +#include "../image/Image.h" + +#include "../scene_graph/NodeDrawingStyle.h" +#include "../scene_graph/NodeShape.h" +#include "../scene_graph/NodeTransform.h" +#include "../scene_graph/ScenePrettyPrinter.h" +#include "../scene_graph/VertexRep.h" + +#include "../stroke/PSStrokeRenderer.h" +#include "../stroke/TextStrokeRenderer.h" +#include "../stroke/StrokeTesselator.h" +#include "../stroke/StyleModule.h" + +#include "../system/StringUtils.h" +#include "../system/PythonInterpreter.h" + +#include "../view_map/SteerableViewMap.h" +#include "../view_map/ViewMap.h" +#include "../view_map/ViewMapIO.h" +#include "../view_map/ViewMapTesselator.h" + +#include "../winged_edge/Curvature.h" +#include "../winged_edge/WEdge.h" +#include "../winged_edge/WingedEdgeBuilder.h" +#include "../winged_edge/WXEdgeBuilder.h" + +#include "../blender_interface/BlenderFileLoader.h" +#include "../blender_interface/BlenderStrokeRenderer.h" +#include "../blender_interface/BlenderStyleModule.h" + +#include "BKE_global.h" + +// XXX Not inside an "extern C" block??? +#include "DNA_freestyle_types.h" + +// XXX Are those "ifdef __cplusplus" useful here? +#ifdef __cplusplus +extern "C" { +#endif + +#include "FRS_freestyle.h" + +#ifdef __cplusplus +} +#endif + +Controller::Controller() +{ + const string sep(Config::DIR_SEP.c_str()); +#if 0 + const string filename = Config::Path::getInstance()->getHomeDir() + sep + Config::OPTIONS_DIR + sep + + Config::OPTIONS_CURRENT_DIRS_FILE; + _current_dirs = new ConfigIO(filename, Config::APPLICATION_NAME + "CurrentDirs", true); +#endif + + _RootNode = new NodeGroup; + _RootNode->addRef(); + + _SilhouetteNode = NULL; +#if 0 + _ProjectedSilhouette = NULL; + _VisibleProjectedSilhouette = NULL; +#endif + + _DebugNode = new NodeGroup; + _DebugNode->addRef(); + + _winged_edge = NULL; + + _pView = NULL; + _pRenderMonitor = NULL; + + _edgeTesselationNature = (Nature::SILHOUETTE | Nature::BORDER | Nature::CREASE); + + _ProgressBar = new ProgressBar; + _SceneNumFaces = 0; + _minEdgeSize = DBL_MAX; + _EPSILON = 1.0e-6; + _bboxDiag = 0; + + _ViewMap = 0; + + _Canvas = 0; + + _VisibilityAlgo = ViewMapBuilder::ray_casting_adaptive_traditional; + //_VisibilityAlgo = ViewMapBuilder::ray_casting; + + _Canvas = new AppCanvas; + + _inter = new PythonInterpreter(); + _EnableQI = true; + _EnableFaceSmoothness = false; + _ComputeRidges = true; + _ComputeSteerableViewMap = false; + _ComputeSuggestive = true; + _ComputeMaterialBoundaries = true; + _sphereRadius = 1.0; + _creaseAngle = 134.43; + + init_options(); +} + +Controller::~Controller() +{ + if (NULL != _RootNode) { + int ref = _RootNode->destroy(); + if (0 == ref) + delete _RootNode; + } + + if (NULL != _SilhouetteNode) { + int ref = _SilhouetteNode->destroy(); + if (0 == ref) + delete _SilhouetteNode; + } + + if (NULL != _DebugNode) { + int ref = _DebugNode->destroy(); + if (0 == ref) + delete _DebugNode; + } + + if (_winged_edge) { + delete _winged_edge; + _winged_edge = NULL; + } + + if (0 != _ViewMap) { + delete _ViewMap; + _ViewMap = 0; + } + + if (0 != _Canvas) { + delete _Canvas; + _Canvas = 0; + } + + if (_inter) { + delete _inter; + _inter = NULL; + } + + //delete _current_dirs; +} + +void Controller::setView(AppView *iView) +{ + if(NULL == iView) + return; + + _pView = iView; + _Canvas->setViewer(_pView); +} + +void Controller::setRenderMonitor(RenderMonitor *iRenderMonitor) +{ + _pRenderMonitor = iRenderMonitor; +} + +void Controller::setPassDiffuse(float *buf, int width, int height) +{ + AppCanvas *app_canvas = dynamic_cast<AppCanvas *>(_Canvas); + assert(app_canvas != 0); + app_canvas->setPassDiffuse(buf, width, height); +} + +void Controller::setPassZ(float *buf, int width, int height) +{ + AppCanvas *app_canvas = dynamic_cast<AppCanvas *>(_Canvas); + assert(app_canvas != 0); + app_canvas->setPassZ(buf, width, height); +} + +void Controller::setContext(bContext *C) +{ + PythonInterpreter* py_inter = dynamic_cast<PythonInterpreter*>(_inter); + assert(py_inter != 0); + py_inter->setContext(C); +} + +int Controller::LoadMesh(Render *re, SceneRenderLayer* srl) +{ + BlenderFileLoader loader(re, srl); + + loader.setRenderMonitor(_pRenderMonitor); + + _Chrono.start(); + + NodeGroup *blenderScene = loader.Load(); + + if (blenderScene == NULL) { + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "Cannot load scene" << endl; + } + return 1; + } + + if (blenderScene->numberOfChildren() < 1) { + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "Empty scene" << endl; + } + blenderScene->destroy(); + delete blenderScene; + return 1; + } + + real duration = _Chrono.stop(); + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "Scene loaded" << endl; + printf("Mesh cleaning : %lf\n", duration); + } + _SceneNumFaces += loader.numFacesRead(); + + if (loader.minEdgeSize() < _minEdgeSize) { + _minEdgeSize = loader.minEdgeSize(); + } + +#if 0 // DEBUG + ScenePrettyPrinter spp; + blenderScene->accept(spp); +#endif + + _RootNode->AddChild(blenderScene); + _RootNode->UpdateBBox(); // FIXME: Correct that by making a Renderer to compute the bbox + + _pView->setModel(_RootNode); + //_pView->FitBBox(); + + if (_pRenderMonitor->testBreak()) + return 0; + + _Chrono.start(); + + WXEdgeBuilder wx_builder; + wx_builder.setRenderMonitor(_pRenderMonitor); + blenderScene->accept(wx_builder); + _winged_edge = wx_builder.getWingedEdge(); + + duration = _Chrono.stop(); + if (G.debug & G_DEBUG_FREESTYLE) { + printf("WEdge building : %lf\n", duration); + } + +#if 0 + _pView->setDebug(_DebugNode); + + // delete stuff + if (0 != ws_builder) { + delete ws_builder; + ws_builder = 0; + } + + soc QFileInfo qfi(iFileName); + soc string basename((const char*)qfi.fileName().toAscii().data()); + char cleaned[FILE_MAX]; + BLI_strncpy(cleaned, iFileName, FILE_MAX); + BLI_cleanup_file(NULL, cleaned); + string basename = StringUtils::toAscii(string(cleaned)); +#endif + + _ListOfModels.push_back("Blender_models"); + + _bboxDiag = (_RootNode->bbox().getMax()-_RootNode->bbox().getMin()).norm(); + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "Triangles nb : " << _SceneNumFaces << endl; + cout << "Bounding Box : " << _bboxDiag << endl; + } + + ClearRootNode(); + + return 0; +} + +void Controller::CloseFile() +{ + WShape::setCurrentId(0); + _ListOfModels.clear(); + + // We deallocate the memory: + ClearRootNode(); + DeleteWingedEdge(); + DeleteViewMap(); + + // clears the canvas + _Canvas->Clear(); + + // soc: reset passes + setPassDiffuse(NULL, 0, 0); + setPassZ(NULL, 0, 0); +} + +void Controller::ClearRootNode() +{ + _pView->DetachModel(); + if (NULL != _RootNode) { + int ref = _RootNode->destroy(); + if (0 == ref) + _RootNode->addRef(); + _RootNode->clearBBox(); + } +} + +void Controller::DeleteWingedEdge() +{ + if (_winged_edge) { + delete _winged_edge; + _winged_edge = NULL; + } + + // clears the grid + _Grid.clear(); + _SceneNumFaces = 0; + _minEdgeSize = DBL_MAX; +} + +void Controller::DeleteViewMap() +{ + _pView->DetachSilhouette(); + if (NULL != _SilhouetteNode) { + int ref = _SilhouetteNode->destroy(); + if (0 == ref) { + delete _SilhouetteNode; + _SilhouetteNode = NULL; + } + } + +#if 0 + if (NULL != _ProjectedSilhouette) { + int ref = _ProjectedSilhouette->destroy(); + if (0 == ref) { + delete _ProjectedSilhouette; + _ProjectedSilhouette = NULL; + } + } + if (NULL != _VisibleProjectedSilhouette) { + int ref = _VisibleProjectedSilhouette->destroy(); + if (0 == ref) { + delete _VisibleProjectedSilhouette; + _VisibleProjectedSilhouette = NULL; + } + } +#endif + + _pView->DetachDebug(); + if (NULL != _DebugNode) { + int ref = _DebugNode->destroy(); + if (0 == ref) + _DebugNode->addRef(); + } + + if (NULL != _ViewMap) { + delete _ViewMap; + _ViewMap = NULL; + } +} + +void Controller::ComputeViewMap() +{ + if (!_ListOfModels.size()) + return; + + if (NULL != _ViewMap) { + delete _ViewMap; + _ViewMap = NULL; + } + + _pView->DetachDebug(); + if (NULL != _DebugNode) { + int ref = _DebugNode->destroy(); + if (0 == ref) + _DebugNode->addRef(); + } + + _pView->DetachSilhouette(); + if (NULL != _SilhouetteNode) { + int ref = _SilhouetteNode->destroy(); + if (0 == ref) + delete _SilhouetteNode; + } + +#if 0 + if (NULL != _ProjectedSilhouette) { + int ref = _ProjectedSilhouette->destroy(); + if (0 == ref) + delete _ProjectedSilhouette; + } + + if (NULL != _VisibleProjectedSilhouette) { + int ref = _VisibleProjectedSilhouette->destroy(); + if (0 == ref) { + delete _VisibleProjectedSilhouette; + _VisibleProjectedSilhouette = NULL; + } + } +#endif + + // retrieve the 3D viewpoint and transformations information + //---------------------------------------------------------- + // Save the viewpoint context at the view level in order + // to be able to restore it later: + + // Restore the context of view: + // we need to perform all these operations while the + // 3D context is on. + Vec3r vp(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]); + +#if 0 + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "mv" << endl; + } +#endif + real mv[4][4]; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + mv[i][j] = freestyle_mv[i][j]; +#if 0 + if (G.debug & G_DEBUG_FREESTYLE) { + cout << mv[i][j] << " "; + } +#endif + } +#if 0 + if (G.debug & G_DEBUG_FREESTYLE) { + cout << endl; + } +#endif + } + +#if 0 + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "\nproj" << endl; + } +#endif + real proj[4][4]; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + proj[i][j] = freestyle_proj[i][j]; +#if 0 + if (G.debug & G_DEBUG_FREESTYLE) { + cout << proj[i][j] << " "; + } +#endif + } +#if 0 + if (G.debug & G_DEBUG_FREESTYLE) { + cout << endl; + } +#endif + } + + int viewport[4]; + for (int i = 0; i < 4; i++) + viewport[i] = freestyle_viewport[i]; + +#if 0 + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "\nfocal:" << _pView->GetFocalLength() << endl << endl; + } +#endif + + // Flag the WXEdge structure for silhouette edge detection: + //---------------------------------------------------------- + + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "\n=== Detecting silhouette edges ===" << endl; + } + _Chrono.start(); + + edgeDetector.setViewpoint(Vec3r(vp)); + edgeDetector.enableOrthographicProjection(proj[3][3] != 0.0); + edgeDetector.enableRidgesAndValleysFlag(_ComputeRidges); + edgeDetector.enableSuggestiveContours(_ComputeSuggestive); + edgeDetector.enableMaterialBoundaries(_ComputeMaterialBoundaries); + edgeDetector.enableFaceSmoothness(_EnableFaceSmoothness); + edgeDetector.setCreaseAngle(_creaseAngle); + edgeDetector.setSphereRadius(_sphereRadius); + edgeDetector.setSuggestiveContourKrDerivativeEpsilon(_suggestiveContourKrDerivativeEpsilon); + edgeDetector.setRenderMonitor(_pRenderMonitor); + edgeDetector.processShapes(*_winged_edge); + + real duration = _Chrono.stop(); + if (G.debug & G_DEBUG_FREESTYLE) { + printf("Feature lines : %lf\n", duration); + } + + if (_pRenderMonitor->testBreak()) + return; + + // Builds the view map structure from the flagged WSEdge structure: + //---------------------------------------------------------- + ViewMapBuilder vmBuilder; + vmBuilder.setEnableQI(_EnableQI); + vmBuilder.setViewpoint(Vec3r(vp)); + vmBuilder.setTransform( mv, proj,viewport, _pView->GetFocalLength(), _pView->GetAspect(), _pView->GetFovyRadian()); + vmBuilder.setFrustum(_pView->znear(), _pView->zfar()); + vmBuilder.setGrid(&_Grid); + vmBuilder.setRenderMonitor(_pRenderMonitor); + + // Builds a tesselated form of the silhouette for display purpose: + //--------------------------------------------------------------- + ViewMapTesselator3D sTesselator3d; +#if 0 + ViewMapTesselator2D sTesselator2d; + sTesselator2d.setNature(_edgeTesselationNature); +#endif + sTesselator3d.setNature(_edgeTesselationNature); + + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "\n=== Building the view map ===" << endl; + } + _Chrono.start(); + // Build View Map + _ViewMap = vmBuilder.BuildViewMap(*_winged_edge, _VisibilityAlgo, _EPSILON, _RootNode->bbox(), _SceneNumFaces); + _ViewMap->setScene3dBBox(_RootNode->bbox()); + + if (G.debug & G_DEBUG_FREESTYLE) { + printf("ViewMap edge count : %i\n", _ViewMap->viewedges_size()); + } + + // Tesselate the 3D edges: + _SilhouetteNode = sTesselator3d.Tesselate(_ViewMap); + _SilhouetteNode->addRef(); + + // Tesselate 2D edges +#if 0 + _ProjectedSilhouette = sTesselator2d.Tesselate(_ViewMap); + _ProjectedSilhouette->addRef(); +#endif + + duration = _Chrono.stop(); + if (G.debug & G_DEBUG_FREESTYLE) { + printf("ViewMap building : %lf\n", duration); + } + + _pView->AddSilhouette(_SilhouetteNode); +#if 0 + _pView->AddSilhouette(_WRoot); + _pView->Add2DSilhouette(_ProjectedSilhouette); + _pView->Add2DVisibleSilhouette(_VisibleProjectedSilhouette); +#endif + _pView->AddDebug(_DebugNode); + + // Draw the steerable density map: + //-------------------------------- + if (_ComputeSteerableViewMap) { + ComputeSteerableViewMap(); + } + // Reset Style modules modification flags + resetModified(true); + + DeleteWingedEdge(); +} + +void Controller::ComputeSteerableViewMap() +{ +#if 0 //soc + if ((!_Canvas) || (!_ViewMap)) + return; + + // Build 4 nodes containing the edges in the 4 directions + NodeGroup *ng[Canvas::NB_STEERABLE_VIEWMAP]; + unsigned i; + real c = 32.0f/255.0f; // see SteerableViewMap::readSteerableViewMapPixel() for information about this 32. + for (i = 0; i < Canvas::NB_STEERABLE_VIEWMAP; ++i) { + ng[i] = new NodeGroup; + } + NodeShape *completeNS = new NodeShape; + completeNS->material().setDiffuse(c,c,c,1); + ng[Canvas::NB_STEERABLE_VIEWMAP-1]->AddChild(completeNS); + SteerableViewMap * svm = _Canvas->getSteerableViewMap(); + svm->Reset(); + + ViewMap::fedges_container& fedges = _ViewMap->FEdges(); + LineRep * fRep; + NodeShape *ns; + for (ViewMap::fedges_container::iterator f = fedges.begin(), fend = fedges.end(); + f != fend; + ++f) + { + if ((*f)->viewedge()->qi() != 0) + continue; + fRep = new LineRep((*f)->vertexA()->point2d(), (*f)->vertexB()->point2d()); + completeNS->AddRep(fRep); // add to the complete map anyway + double *oweights = svm->AddFEdge(*f); + for (i = 0; i < (Canvas::NB_STEERABLE_VIEWMAP - 1); ++i) { + ns = new NodeShape; + double wc = oweights[i]*c; + if (oweights[i] == 0) + continue; + ns->material().setDiffuse(wc, wc, wc, 1); + ns->AddRep(fRep); + ng[i]->AddChild(ns); + } + } + + GrayImage *img[Canvas::NB_STEERABLE_VIEWMAP]; + //#ifdef WIN32 + QGLBasicWidget offscreenBuffer(_pView, "SteerableViewMap", _pView->width(), _pView->height()); + QPixmap pm; + QImage qimg; + for (i = 0; i < Canvas::NB_STEERABLE_VIEWMAP; ++i) { + offscreenBuffer.AddNode(ng[i]); +#if 0 + img[i] = new GrayImage(_pView->width(), _pView->height()); + offscreenBuffer.readPixels(0,0,_pView->width(), _pView->height(), img[i]->getArray()); +#endif + pm = offscreenBuffer.renderPixmap(_pView->width(), _pView->height()); + + if (pm.isNull()) { + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "BuildViewMap Warning: couldn't render the steerable ViewMap" << endl; + } + } + //pm.save(QString("steerable") + QString::number(i) + QString(".bmp"), "BMP"); + // FIXME!! Lost of time ! + qimg = pm.toImage(); + // FIXME !! again! + img[i] = new GrayImage(_pView->width(), _pView->height()); + for (unsigned int y = 0; y < img[i]->height(); ++y) { + for(unsigned int x = 0; x < img[i]->width(); ++x) { + //img[i]->setPixel(x, y, (float)qGray(qimg.pixel(x, y)) / 255.0f); + img[i]->setPixel(x, y, (float)qGray(qimg.pixel(x, y))); + //float c = qGray(qimg.pixel(x, y)); + //img[i]->setPixel(x, y, qGray(qimg.pixel(x, y))); + } + } + offscreenBuffer.DetachNode(ng[i]); + ng[i]->destroy(); + delete ng[i]; + // check +#if 0 + qimg = QImage(_pView->width(), _pView->height(), 32); + for (unsigned int y = 0; y < img[i]->height(); ++y) { + for(unsigned int x = 0; x < img[i]->width(); ++x) { + float v = img[i]->pixel(x, y); + qimg.setPixel(x, y, qRgb(v, v, v)); + } + } + qimg.save(QString("newsteerable") + QString::number(i) + QString(".bmp"), "BMP"); +#endif + } + + + svm->buildImagesPyramids(img, false, 0, 1.0f); +#endif +} + +void Controller::saveSteerableViewMapImages() +{ + SteerableViewMap * svm = _Canvas->getSteerableViewMap(); + if (!svm) { + cerr << "the Steerable ViewMap has not been computed yet" << endl; + return; + } + svm->saveSteerableViewMap(); +} + +void Controller::toggleVisibilityAlgo() +{ + if (_VisibilityAlgo == ViewMapBuilder::ray_casting) { + _VisibilityAlgo = ViewMapBuilder::ray_casting_fast; + } + else if (_VisibilityAlgo == ViewMapBuilder::ray_casting_fast) { + _VisibilityAlgo = ViewMapBuilder::ray_casting_very_fast; + } + else { + _VisibilityAlgo = ViewMapBuilder::ray_casting; + } +} + +void Controller::setVisibilityAlgo(int algo) +{ + switch (algo) { + case FREESTYLE_ALGO_REGULAR: + _VisibilityAlgo = ViewMapBuilder::ray_casting; + break; + case FREESTYLE_ALGO_FAST: + _VisibilityAlgo = ViewMapBuilder::ray_casting_fast; + break; + case FREESTYLE_ALGO_VERYFAST: + _VisibilityAlgo = ViewMapBuilder::ray_casting_very_fast; + break; + case FREESTYLE_ALGO_CULLED_ADAPTIVE_TRADITIONAL: + _VisibilityAlgo = ViewMapBuilder::ray_casting_culled_adaptive_traditional; + break; + case FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL: + _VisibilityAlgo = ViewMapBuilder::ray_casting_adaptive_traditional; + break; + case FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE: + _VisibilityAlgo = ViewMapBuilder::ray_casting_culled_adaptive_cumulative; + break; + case FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE: + _VisibilityAlgo = ViewMapBuilder::ray_casting_adaptive_cumulative; + break; + } +} + +int Controller::getVisibilityAlgo() +{ + switch (_VisibilityAlgo) { + case ViewMapBuilder::ray_casting: + return FREESTYLE_ALGO_REGULAR; + case ViewMapBuilder::ray_casting_fast: + return FREESTYLE_ALGO_FAST; + case ViewMapBuilder::ray_casting_very_fast: + return FREESTYLE_ALGO_VERYFAST; + case ViewMapBuilder::ray_casting_culled_adaptive_traditional: + return FREESTYLE_ALGO_CULLED_ADAPTIVE_TRADITIONAL; + case ViewMapBuilder::ray_casting_adaptive_traditional: + return FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL; + case ViewMapBuilder::ray_casting_culled_adaptive_cumulative: + return FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE; + case ViewMapBuilder::ray_casting_adaptive_cumulative: + return FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE; + } + + // ray_casting_adaptive_traditional is the most exact replacement + // for legacy code + return FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL; +} + +void Controller::setQuantitativeInvisibility(bool iBool) +{ + _EnableQI = iBool; +} + +bool Controller::getQuantitativeInvisibility() const +{ + return _EnableQI; +} + +void Controller::setFaceSmoothness(bool iBool) +{ + _EnableFaceSmoothness = iBool; +} + +bool Controller::getFaceSmoothness() const +{ + return _EnableFaceSmoothness; +} + +void Controller::setComputeRidgesAndValleysFlag(bool iBool) +{ + _ComputeRidges = iBool; +} + +bool Controller::getComputeRidgesAndValleysFlag() const +{ + return _ComputeRidges; +} + +void Controller::setComputeSuggestiveContoursFlag(bool b) +{ + _ComputeSuggestive = b; +} + +bool Controller::getComputeSuggestiveContoursFlag() const +{ + return _ComputeSuggestive; +} + +void Controller::setComputeMaterialBoundariesFlag(bool b) +{ + _ComputeMaterialBoundaries = b; +} + +bool Controller::getComputeMaterialBoundariesFlag() const +{ + return _ComputeMaterialBoundaries; +} + +void Controller::setComputeSteerableViewMapFlag(bool iBool) +{ + _ComputeSteerableViewMap = iBool; +} + +bool Controller::getComputeSteerableViewMapFlag() const +{ + return _ComputeSteerableViewMap; +} + +void Controller::DrawStrokes() +{ + if (_ViewMap == 0) + return; + + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "\n=== Stroke drawing ===" << endl; + } + _Chrono.start(); + _Canvas->Draw(); + real d = _Chrono.stop(); + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "Strokes generation : " << d << endl; + cout << "Stroke count : " << _Canvas->stroke_count << endl; + } + resetModified(); + DeleteViewMap(); +} + +void Controller::ResetRenderCount() +{ + _render_count = 0; +} + +Render* Controller::RenderStrokes(Render *re) +{ + _Chrono.start(); + BlenderStrokeRenderer* blenderRenderer = new BlenderStrokeRenderer(re, ++_render_count); + _Canvas->Render(blenderRenderer); + real d = _Chrono.stop(); + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "Temporary scene generation: " << d << endl; + } + _Chrono.start(); + Render* freestyle_render = blenderRenderer->RenderScene(re); + d = _Chrono.stop(); + if (G.debug & G_DEBUG_FREESTYLE) { + cout << "Stroke rendering : " << d << endl; + } + delete blenderRenderer; + + return freestyle_render; +} + +void Controller::InsertStyleModule(unsigned index, const char *iFileName) +{ + if (!BLI_testextensie(iFileName, ".py")) { + cerr << "Error: Cannot load \"" << StringUtils::toAscii(string(iFileName)) + << "\", unknown extension" << endl; + return; + } + + StyleModule* sm = new StyleModule(iFileName, _inter); + _Canvas->InsertStyleModule(index, sm); +} + +void Controller::InsertStyleModule(unsigned index, const char *iName, struct Text *iText) +{ + StyleModule* sm = new BlenderStyleModule(iText, iName, _inter); + _Canvas->InsertStyleModule(index, sm); +} + +void Controller::AddStyleModule(const char *iFileName) +{ + //_pStyleWindow->Add(iFileName); +} + +void Controller::RemoveStyleModule(unsigned index) +{ + _Canvas->RemoveStyleModule(index); +} + +void Controller::Clear() +{ + _Canvas->Clear(); +} + +void Controller::ReloadStyleModule(unsigned index, const char * iFileName) +{ + StyleModule* sm = new StyleModule(iFileName, _inter); + _Canvas->ReplaceStyleModule(index, sm); +} + +void Controller::SwapStyleModules(unsigned i1, unsigned i2) +{ + _Canvas->SwapStyleModules(i1, i2); +} + +void Controller::toggleLayer(unsigned index, bool iDisplay) +{ + _Canvas->setVisible(index, iDisplay); +} + +void Controller::setModified(unsigned index, bool iMod) +{ + //_pStyleWindow->setModified(index, iMod); + _Canvas->setModified(index, iMod); + updateCausalStyleModules(index + 1); +} + +void Controller::updateCausalStyleModules(unsigned index) +{ + vector<unsigned> vec; + _Canvas->causalStyleModules(vec, index); + for (vector<unsigned>::const_iterator it = vec.begin(); it != vec.end(); it++) { + //_pStyleWindow->setModified(*it, true); + _Canvas->setModified(*it, true); + } +} + +void Controller::resetModified(bool iMod) +{ + //_pStyleWindow->resetModified(iMod); + _Canvas->resetModified(iMod); +} + +NodeGroup * Controller::BuildRep(vector<ViewEdge*>::iterator vedges_begin, vector<ViewEdge*>::iterator vedges_end) +{ + ViewMapTesselator2D tesselator2D; + FrsMaterial mat; + mat.setDiffuse(1, 1, 0.3, 1); + tesselator2D.setFrsMaterial(mat); + + return (tesselator2D.Tesselate(vedges_begin, vedges_end)); +} + +void Controller::toggleEdgeTesselationNature(Nature::EdgeNature iNature) +{ + _edgeTesselationNature ^= (iNature); + ComputeViewMap(); +} + +void Controller::setModelsDir(const string& dir) +{ + //_current_dirs->setValue("models/dir", dir); +} + +string Controller::getModelsDir() const +{ + string dir = "."; + //_current_dirs->getValue("models/dir", dir); + return dir; +} + +void Controller::setModulesDir(const string& dir) +{ + //_current_dirs->setValue("modules/dir", dir); +} + +string Controller::getModulesDir() const +{ + string dir = "."; + //_current_dirs->getValue("modules/dir", dir); + return dir; +} + +void Controller::setHelpIndex(const string& index) +{ + _help_index = index; +} + +string Controller::getHelpIndex() const +{ + return _help_index; +} + +void Controller::setBrowserCmd(const string& cmd) +{ + _browser_cmd = cmd; +} + +string Controller::getBrowserCmd() const +{ + return _browser_cmd; +} + +void Controller::resetInterpreter() +{ + if (_inter) + _inter->reset(); +} + + +void Controller::displayDensityCurves(int x, int y) +{ + SteerableViewMap * svm = _Canvas->getSteerableViewMap(); + if (!svm) + return; + + unsigned int i, j; + typedef vector<Vec3r> densityCurve; + vector<densityCurve> curves(svm->getNumberOfOrientations() + 1); + vector<densityCurve> curvesDirection(svm->getNumberOfPyramidLevels()); + + // collect the curves values + unsigned nbCurves = svm->getNumberOfOrientations() + 1; + unsigned nbPoints = svm->getNumberOfPyramidLevels(); + if (!nbPoints) + return; + + // build the density/nbLevels curves for each orientation + for (i = 0; i < nbCurves; ++i) { + for (j = 0; j < nbPoints; ++j) { + curves[i].push_back(Vec3r(j, svm->readSteerableViewMapPixel(i, j, x, y), 0)); + } + } + // build the density/nbOrientations curves for each level + for (i = 0; i < nbPoints; ++i) { + for (j = 0; j < nbCurves; ++j) { + curvesDirection[i].push_back(Vec3r(j, svm->readSteerableViewMapPixel(j, i, x, y), 0)); + } + } + + // display the curves +#if 0 + for (i = 0; i < nbCurves; ++i) + _pDensityCurvesWindow->setOrientationCurve(i, Vec2d(0, 0), Vec2d(nbPoints, 1), curves[i], "scale", "density"); + for (i = 1; i <= 8; ++i) + _pDensityCurvesWindow->setLevelCurve(i, Vec2d(0, 0), Vec2d(nbCurves, 1), curvesDirection[i], + "orientation", "density"); + _pDensityCurvesWindow->show(); +#endif +} + +void Controller::init_options() +{ + // from AppOptionsWindow.cpp + // Default init options + + Config::Path * cpath = Config::Path::getInstance(); + + // Directories + ViewMapIO::Options::setModelsPath(StringUtils::toAscii(cpath->getModelsPath())); + PythonInterpreter::Options::setPythonPath(StringUtils::toAscii(cpath->getPythonPath())); + TextureManager::Options::setPatternsPath(StringUtils::toAscii(cpath->getPatternsPath())); + TextureManager::Options::setBrushesPath(StringUtils::toAscii(cpath->getModelsPath())); + + // ViewMap Format + ViewMapIO::Options::rmFlags(ViewMapIO::Options::FLOAT_VECTORS); + ViewMapIO::Options::rmFlags(ViewMapIO::Options::NO_OCCLUDERS); + setComputeSteerableViewMapFlag(false); + + // Visibility + setQuantitativeInvisibility(true); + + // soc: initialize canvas + _Canvas->init(); + + // soc: initialize passes + setPassDiffuse(NULL, 0, 0); + setPassZ(NULL, 0, 0); +} diff --git a/source/blender/freestyle/intern/application/Controller.h b/source/blender/freestyle/intern/application/Controller.h new file mode 100644 index 00000000000..475d9c6efd3 --- /dev/null +++ b/source/blender/freestyle/intern/application/Controller.h @@ -0,0 +1,261 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __CONTROLLER_H__ +#define __CONTROLLER_H__ + +/** \file blender/freestyle/intern/application/Controller.h + * \ingroup freestyle + * \brief The spinal tap of the system. + * \author Stephane Grabli + * \date 01/07/2002 + */ + +#include <string> + +//#include "ConfigIO.h" +#include "../geometry/FastGrid.h" +#include "../system/Interpreter.h" +#include "../system/ProgressBar.h" +#include "../system/Precision.h" +#include "../system/RenderMonitor.h" +#include "../system/TimeUtils.h" +#include "../view_map/FEdgeXDetector.h" +#include "../view_map/ViewMapBuilder.h" + +class AppView; +class NodeGroup; +class WShape; +class SShape; +class ViewMap; +class ViewEdge; +class AppCanvas; +class InteractiveShader; +class Shader; +class StrokeRenderer; + +// XXX Are those "ifdef __cplusplus" useful here? +#ifdef __cplusplus +extern "C" { +#endif + +#include "render_types.h" +#include "DNA_scene_types.h" + +#ifdef __cplusplus +} +#endif + +class Controller +{ +public: + Controller(); + ~Controller(); + + void setView(AppView *iView); + void setRenderMonitor(RenderMonitor *iRenderMonitor); + void setPassDiffuse(float *buf, int width, int height); + void setPassZ(float *buf, int width, int height); + void setContext(bContext *C); + + //soc + void init_options(); + + int LoadMesh(Render *re, SceneRenderLayer *srl); + int Load3DSFile(const char *iFileName); + void CloseFile(); + void ComputeViewMap(); + void ComputeSteerableViewMap(); + void saveSteerableViewMapImages(); + void toggleEdgeTesselationNature(Nature::EdgeNature iNature); + void DrawStrokes(); + void ResetRenderCount(); + Render *RenderStrokes(Render *re); + void SwapStyleModules(unsigned i1, unsigned i2); + void InsertStyleModule(unsigned index, const char *iFileName); + void InsertStyleModule(unsigned index, const char *iName, struct Text *iText); + void AddStyleModule(const char *iFileName); + void RemoveStyleModule(unsigned index); + void ReloadStyleModule(unsigned index, const char * iFileName); + void Clear(); + void ClearRootNode(); + void DeleteWingedEdge(); + void DeleteViewMap(); + void toggleLayer(unsigned index, bool iDisplay); + void setModified(unsigned index, bool iMod); + void resetModified(bool iMod=false); + void updateCausalStyleModules(unsigned index); + void displayDensityCurves(int x, int y); + + ViewEdge *SelectViewEdge(real x, real y); + FEdge *SelectFEdge(real x, real y); + NodeGroup *BuildRep(vector<ViewEdge*>::iterator vedges_begin, vector<ViewEdge*>::iterator vedges_end) ; + +#if 0 + NodeGroup *debugNode() {return _DebugNode;} + AppView *view() {return _pView;} + NodeGroup *debugScene() {return _DebugNode;} + Grid& grid() {return _Grid;} +#endif + + void toggleVisibilityAlgo(); + void setVisibilityAlgo(int algo); + int getVisibilityAlgo(); + + void setQuantitativeInvisibility(bool iBool); // if true, we compute quantitativeInvisibility + bool getQuantitativeInvisibility() const; + void setFaceSmoothness(bool iBool); + bool getFaceSmoothness() const; + + void setComputeRidgesAndValleysFlag(bool b); + bool getComputeRidgesAndValleysFlag() const; + void setComputeSuggestiveContoursFlag(bool b); + bool getComputeSuggestiveContoursFlag() const; + void setComputeMaterialBoundariesFlag(bool b); + bool getComputeMaterialBoundariesFlag() const; + + void setComputeSteerableViewMapFlag(bool iBool); + bool getComputeSteerableViewMapFlag() const; + void setCreaseAngle(real angle) {_creaseAngle = angle;} + real getCreaseAngle() const {return _creaseAngle;} + void setSphereRadius(real s) {_sphereRadius = s;} + real getSphereRadius() const {return _sphereRadius;} + void setSuggestiveContourKrDerivativeEpsilon(real dkr) {_suggestiveContourKrDerivativeEpsilon = dkr;} + real getSuggestiveContourKrDerivativeEpsilon() const {return _suggestiveContourKrDerivativeEpsilon;} + + void setModelsDir(const string& dir); + string getModelsDir() const; + void setModulesDir(const string& dir); + string getModulesDir() const; + void setHelpIndex(const string& dir); + string getHelpIndex() const; + void setBrowserCmd(const string& cmd); + string getBrowserCmd() const; + + void resetInterpreter(); + +public: + // Viewmap data structure + ViewMap *_ViewMap; + + // Canvas + AppCanvas *_Canvas; + +private: + // Main Window: + //AppMainWindow *_pMainWindow; + + // List of models currently loaded + vector<string> _ListOfModels; + + // Current directories + //ConfigIO* _current_dirs; + + //View + // 3D + AppView *_pView; + + // 2D +#if 0 + Viewer2DWindow *_pView2DWindow; + Viewer2D *_pView2D; +#endif + + RenderMonitor *_pRenderMonitor; + + //Model + // Drawing Structure + NodeGroup *_RootNode; + + // Winged-Edge structure + WingedEdge *_winged_edge; + + // Silhouette structure: +#if 0 + std::vector<SShape*> _SShapes; + NodeGroup *_SRoot; +#endif + + // Silhouette + NodeGroup *_SilhouetteNode; + NodeGroup *_ProjectedSilhouette; + NodeGroup *_VisibleProjectedSilhouette; + + // more Debug info + NodeGroup *_DebugNode; + + // debug + //NodeUser<ViewMap> *_ViewMapNode; // FIXME + + // Chronometer: + Chronometer _Chrono; + + // Progress Bar + ProgressBar *_ProgressBar; + + // edges tesselation nature + int _edgeTesselationNature; + + FastGrid _Grid; + //HashGrid _Grid; + + unsigned int _SceneNumFaces; + real _minEdgeSize; + real _EPSILON; + real _bboxDiag; + + int _render_count; + + //AppStyleWindow *_pStyleWindow; + //AppOptionsWindow *_pOptionsWindow; + //AppDensityCurvesWindow *_pDensityCurvesWindow; + + ViewMapBuilder::visibility_algo _VisibilityAlgo; + + // Script Interpreter + Interpreter *_inter; + + string _help_index; + string _browser_cmd; + + bool _EnableQI; + bool _EnableFaceSmoothness; + bool _ComputeRidges; + bool _ComputeSuggestive; + bool _ComputeMaterialBoundaries; + real _creaseAngle; + real _sphereRadius; + real _suggestiveContourKrDerivativeEpsilon; + + bool _ComputeSteerableViewMap; + + FEdgeXDetector edgeDetector; +}; + +extern Controller *g_pController; + +#endif // __CONTROLLER_H__ |