diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py index d9bfd89e6b5..6abd6f448f5 100644 --- a/release/scripts/startup/bl_ui/properties_freestyle.py +++ b/release/scripts/startup/bl_ui/properties_freestyle.py @@ -122,7 +122,9 @@ class RENDERLAYER_PT_freestyle(RenderLayerFreestyleButtonsPanel, Panel): layout.active = rl.use_freestyle + row = layout.row() layout.prop(freestyle, "mode", text="Control mode") + layout.prop(freestyle, "use_view_map_cache", text="View Map Cache") layout.label(text="Edge Detection Options:") split = layout.split() diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt index c94a5ac9f92..bfd1c17df7d 100644 --- a/source/blender/freestyle/CMakeLists.txt +++ b/source/blender/freestyle/CMakeLists.txt @@ -412,6 +412,8 @@ set(SRC intern/scene_graph/OrientedLineRep.h intern/scene_graph/Rep.cpp intern/scene_graph/Rep.h + intern/scene_graph/SceneHash.cpp + intern/scene_graph/SceneHash.h intern/scene_graph/ScenePrettyPrinter.cpp intern/scene_graph/ScenePrettyPrinter.h intern/scene_graph/SceneVisitor.cpp diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h index fc9fc35e410..1815883bf0d 100644 --- a/source/blender/freestyle/FRS_freestyle.h +++ b/source/blender/freestyle/FRS_freestyle.h @@ -48,6 +48,7 @@ int FRS_is_freestyle_enabled(struct SceneRenderLayer *srl); void FRS_init_stroke_rendering(struct Render *re); struct Render *FRS_do_stroke_rendering(struct Render *re, struct SceneRenderLayer *srl, int render); void FRS_finish_stroke_rendering(struct Render *re); +void FRS_free_view_map_cache(); void FRS_composite_result(struct Render *re, struct SceneRenderLayer *srl, struct Render *freestyle_render); void FRS_exit(void); diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp index 176199600ac..a7f936ff171 100644 --- a/source/blender/freestyle/intern/application/Controller.cpp +++ b/source/blender/freestyle/intern/application/Controller.cpp @@ -118,6 +118,7 @@ Controller::Controller() _Canvas = new AppCanvas; _inter = new PythonInterpreter(); + _EnableViewMapCache = false; _EnableQI = true; _EnableFaceSmoothness = false; _ComputeRidges = true; @@ -212,6 +213,19 @@ void Controller::setContext(bContext *C) py_inter->setContext(C); } +bool Controller::hitViewMapCache() +{ + if (!_EnableViewMapCache) { + return false; + } + real hashCode = sceneHashFunc.getValue(); + if (prevSceneHash == hashCode) { + return (NULL != _ViewMap); + } + prevSceneHash = hashCode; + return false; +} + int Controller::LoadMesh(Render *re, SceneRenderLayer *srl) { BlenderFileLoader loader(re, srl); @@ -242,6 +256,7 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl) if (G.debug & G_DEBUG_FREESTYLE) { cout << "Scene loaded" << endl; printf("Mesh cleaning : %lf\n", duration); + printf("View map cache : %s\n", _EnableViewMapCache ? "enabled" : "disabled"); } _SceneNumFaces += loader.numFacesRead(); @@ -263,6 +278,22 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl) if (_pRenderMonitor->testBreak()) return 0; + if (_EnableViewMapCache) { + sceneHashFunc.reset(); + blenderScene->accept(sceneHashFunc); + if (G.debug & G_DEBUG_FREESTYLE) { + printf("Scene hash : %.16e\n", sceneHashFunc.getValue()); + } + if (hitViewMapCache()) { + ClearRootNode(); + return 0; + } + else { + delete _ViewMap; + _ViewMap = NULL; + } + } + _Chrono.start(); WXEdgeBuilder wx_builder; @@ -357,7 +388,7 @@ void Controller::DeleteWingedEdge() _minEdgeSize = DBL_MAX; } -void Controller::DeleteViewMap() +void Controller::DeleteViewMap(bool freeCache) { _pView->DetachSilhouette(); if (NULL != _SilhouetteNode) { @@ -387,14 +418,15 @@ void Controller::DeleteViewMap() _pView->DetachDebug(); if (NULL != _DebugNode) { - int ref = _DebugNode->destroy(); + int ref = _DebugNode->destroy(); if (0 == ref) _DebugNode->addRef(); } - if (NULL != _ViewMap) { + if ((freeCache || !_EnableViewMapCache) && NULL != _ViewMap) { delete _ViewMap; _ViewMap = NULL; + prevSceneHash = -1.0; } } @@ -403,40 +435,7 @@ 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 + DeleteViewMap(true); // retrieve the 3D viewpoint and transformations information //---------------------------------------------------------- @@ -763,6 +762,16 @@ int Controller::getVisibilityAlgo() return FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL; } +void Controller::setViewMapCache(bool iBool) +{ + _EnableViewMapCache = iBool; +} + +bool Controller::getViewMapCache() const +{ + return _EnableViewMapCache; +} + void Controller::setQuantitativeInvisibility(bool iBool) { _EnableQI = iBool; diff --git a/source/blender/freestyle/intern/application/Controller.h b/source/blender/freestyle/intern/application/Controller.h index f5e50347d0f..84ee3382612 100644 --- a/source/blender/freestyle/intern/application/Controller.h +++ b/source/blender/freestyle/intern/application/Controller.h @@ -32,6 +32,7 @@ //#include "ConfigIO.h" #include "../geometry/FastGrid.h" +#include "../scene_graph/SceneHash.h" #include "../system/Interpreter.h" #include "../system/ProgressBar.h" #include "../system/Precision.h" @@ -96,7 +97,7 @@ public: void Clear(); void ClearRootNode(); void DeleteWingedEdge(); - void DeleteViewMap(); + void DeleteViewMap(bool freeCache = false); void toggleLayer(unsigned index, bool iDisplay); void setModified(unsigned index, bool iMod); void resetModified(bool iMod=false); @@ -118,6 +119,8 @@ public: void setVisibilityAlgo(int algo); int getVisibilityAlgo(); + void setViewMapCache(bool iBool); + bool getViewMapCache() const; void setQuantitativeInvisibility(bool iBool); // if true, we compute quantitativeInvisibility bool getQuantitativeInvisibility() const; void setFaceSmoothness(bool iBool); @@ -144,6 +147,8 @@ public: void setModulesDir(const string& dir); string getModulesDir() const; + bool hitViewMapCache(); + void resetInterpreter(); public: @@ -231,6 +236,7 @@ private: string _help_index; string _browser_cmd; + bool _EnableViewMapCache; bool _EnableQI; bool _EnableFaceSmoothness; bool _ComputeRidges; @@ -244,6 +250,9 @@ private: FEdgeXDetector edgeDetector; + SceneHash sceneHashFunc; + real prevSceneHash = -1.0; + #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Controller") #endif diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp index 32f49d48ee7..7443da77399 100644 --- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp +++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp @@ -474,6 +474,9 @@ static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl) cout << " Z = " << (z ? "enabled" : "disabled") << endl; } + if (controller->hitViewMapCache()) + return; + // compute view map re->i.infostr = "Freestyle: View map creation"; re->stats_draw(re->sdh, &re->i); @@ -589,6 +592,7 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render) RenderMonitor monitor(re); controller->setRenderMonitor(&monitor); + controller->setViewMapCache((srl->freestyleConfig.flags & FREESTYLE_VIEW_MAP_CACHE) ? true : false); if (G.debug & G_DEBUG_FREESTYLE) { cout << endl; @@ -647,6 +651,17 @@ void FRS_finish_stroke_rendering(Render *re) controller->Clear(); } +void FRS_free_view_map_cache() +{ + // free cache + controller->DeleteViewMap(true); +#if 0 + if (G.debug & G_DEBUG_FREESTYLE) { + printf("View map cache freed\n"); + } +#endif +} + //======================================================= // Freestyle Panel Configuration //======================================================= diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp new file mode 100644 index 00000000000..6e8856f1b93 --- /dev/null +++ b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp @@ -0,0 +1,39 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/freestyle/intern/scene_graph/SceneHash.cpp + * \ingroup freestyle + */ + +#include "SceneHash.h" + +namespace Freestyle { + +void SceneHash::visitIndexedFaceSet(IndexedFaceSet& ifs) +{ + const real *v = ifs.vertices(); + const unsigned n = ifs.vsize(); + + for (unsigned i = 0; i < n; i++) { + _hashcode += v[i]; + } +} + +} /* namespace Freestyle */ diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.h b/source/blender/freestyle/intern/scene_graph/SceneHash.h new file mode 100644 index 00000000000..8f5f847eaab --- /dev/null +++ b/source/blender/freestyle/intern/scene_graph/SceneHash.h @@ -0,0 +1,67 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __FREESTYLE_SCENE_HASH_H__ +#define __FREESTYLE_SCENE_HASH_H__ + +/** \file blender/freestyle/intern/scene_graph/SceneHash.h + * \ingroup freestyle + */ + +#include "IndexedFaceSet.h" +#include "SceneVisitor.h" + +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + +namespace Freestyle { + +class SceneHash : public SceneVisitor +{ +public: + inline SceneHash() : SceneVisitor() + { + _hashcode = 0.0; + } + + virtual ~SceneHash() {} + + VISIT_DECL(IndexedFaceSet) + + inline real getValue() { + return _hashcode; + } + + inline void reset() { + _hashcode = 0.0; + } + +private: + real _hashcode; + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:SceneHash") +#endif +}; + +} /* namespace Freestyle */ + +#endif // __FREESTYLE_SCENE_HASH_H__ diff --git a/source/blender/makesdna/DNA_freestyle_types.h b/source/blender/makesdna/DNA_freestyle_types.h index 195c7eb4841..d099511a088 100644 --- a/source/blender/makesdna/DNA_freestyle_types.h +++ b/source/blender/makesdna/DNA_freestyle_types.h @@ -50,6 +50,7 @@ struct Text; #define FREESTYLE_FACE_SMOOTHNESS_FLAG (1 << 3) #define FREESTYLE_ADVANCED_OPTIONS_FLAG (1 << 4) #define FREESTYLE_CULLING (1 << 5) +#define FREESTYLE_VIEW_MAP_CACHE (1 << 6) /* FreestyleConfig::mode */ #define FREESTYLE_CONTROL_SCRIPT_MODE 1 diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 15f5253257a..d62a2e2c76e 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -265,6 +265,9 @@ if(WITH_BULLET) endif() if(WITH_FREESTYLE) + list(APPEND INC + ../../freestyle + ) add_definitions(-DWITH_FREESTYLE) endif() diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript index 08cbd6143a5..179a332336e 100644 --- a/source/blender/makesrna/intern/SConscript +++ b/source/blender/makesrna/intern/SConscript @@ -143,6 +143,7 @@ if env['WITH_BF_CYCLES']: if env['WITH_BF_FREESTYLE']: defs.append('WITH_FREESTYLE') + incs += ' ../../freestyle' if env['OURPLATFORM'] == 'linux': cflags='-pthread' diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 97890997bbb..9af38ae2322 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -370,6 +370,10 @@ EnumPropertyItem bake_save_mode_items[] = { #include "RE_engine.h" +#ifdef WITH_FREESTYLE +#include "FRS_freestyle.h" +#endif + static void rna_SpaceImageEditor_uv_sculpt_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) { ED_space_image_uv_sculpt_update(bmain->wm.first, scene->toolsettings); @@ -1179,6 +1183,13 @@ static void rna_Scene_freestyle_update(Main *UNUSED(bmain), Scene *UNUSED(scene) DAG_id_tag_update(&scene->id, 0); } +static void rna_Scene_use_view_map_cache_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ +#ifdef WITH_FREESTYLE + FRS_free_view_map_cache(); +#endif +} + static void rna_SceneRenderLayer_name_set(PointerRNA *ptr, const char *value) { Scene *scene = (Scene *)ptr->id.data; @@ -3109,6 +3120,11 @@ static void rna_def_freestyle_settings(BlenderRNA *brna) "Enable advanced edge detection options (sphere radius and Kr derivative epsilon)"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update"); + prop = RNA_def_property(srna, "use_view_map_cache", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_VIEW_MAP_CACHE); + RNA_def_property_ui_text(prop, "View Map Cache", "Keep the computed view map and avoid re-calculating it if mesh geometry is unchanged"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_use_view_map_cache_update"); + prop = RNA_def_property(srna, "sphere_radius", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "sphere_radius"); RNA_def_property_range(prop, 0.0, 1000.0);