1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup freestyle
19  */
20 
21 #include <iostream>
22 #include <map>
23 #include <set>
24 
25 #include "../application/AppCanvas.h"
26 #include "../application/AppConfig.h"
27 #include "../application/AppView.h"
28 #include "../application/Controller.h"
29 
30 #include "BlenderStrokeRenderer.h"
31 
32 using namespace std;
33 using namespace Freestyle;
34 
35 #include "MEM_guardedalloc.h"
36 
37 #include "DNA_camera_types.h"
38 #include "DNA_collection_types.h"
39 #include "DNA_freestyle_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_text_types.h"
42 
43 #include "BKE_callbacks.h"
44 #include "BKE_context.h"
45 #include "BKE_freestyle.h"
46 #include "BKE_global.h"
47 #include "BKE_lib_id.h"
48 #include "BKE_linestyle.h"
49 #include "BKE_scene.h"
50 #include "BKE_text.h"
51 
52 #include "BLT_translation.h"
53 
54 #include "BLI_blenlib.h"
55 #include "BLI_math.h"
56 #include "BLI_math_color_blend.h"
57 
58 #include "BPY_extern.h"
59 
60 #include "DEG_depsgraph_query.h"
61 
62 #include "renderpipeline.h"
63 
64 #include "FRS_freestyle.h"
65 
66 extern "C" {
67 
68 #define DEFAULT_SPHERE_RADIUS 1.0f
69 #define DEFAULT_DKR_EPSILON 0.0f
70 
71 struct FreestyleGlobals g_freestyle;
72 
73 // Freestyle configuration
74 static bool freestyle_is_initialized = false;
75 static Config::Path *pathconfig = NULL;
76 static Controller *controller = NULL;
77 static AppView *view = NULL;
78 
79 // line set buffer for copy & paste
80 static FreestyleLineSet lineset_buffer;
81 static bool lineset_copied = false;
82 
load_post_callback(struct Main *,struct PointerRNA **,const int,void *)83 static void load_post_callback(struct Main * /*main*/,
84                                struct PointerRNA ** /*pointers*/,
85                                const int /*num_pointers*/,
86                                void * /*arg*/)
87 {
88   lineset_copied = false;
89 }
90 
91 static bCallbackFuncStore load_post_callback_funcstore = {
92     NULL,
93     NULL,               /* next, prev */
94     load_post_callback, /* func */
95     NULL,               /* arg */
96     0                   /* alloc */
97 };
98 
99 //=======================================================
100 //   Initialization
101 //=======================================================
102 
FRS_init()103 void FRS_init()
104 {
105   if (freestyle_is_initialized) {
106     return;
107   }
108 
109   pathconfig = new Config::Path;
110   controller = new Controller();
111   view = new AppView;
112   controller->setView(view);
113   controller->Clear();
114   g_freestyle.scene = NULL;
115   lineset_copied = false;
116 
117   BKE_callback_add(&load_post_callback_funcstore, BKE_CB_EVT_LOAD_POST);
118 
119   freestyle_is_initialized = 1;
120 }
121 
FRS_set_context(bContext * C)122 void FRS_set_context(bContext *C)
123 {
124   if (G.debug & G_DEBUG_FREESTYLE) {
125     cout << "FRS_set_context: context 0x" << C << " scene 0x" << CTX_data_scene(C) << endl;
126   }
127   controller->setContext(C);
128 }
129 
FRS_exit()130 void FRS_exit()
131 {
132   delete pathconfig;
133   delete controller;
134   delete view;
135 }
136 
137 //=======================================================
138 //   Rendering
139 //=======================================================
140 
init_view(Render * re)141 static void init_view(Render *re)
142 {
143   int width = re->winx;
144   int height = re->winy;
145   int xmin = re->disprect.xmin;
146   int ymin = re->disprect.ymin;
147   int xmax = re->disprect.xmax;
148   int ymax = re->disprect.ymax;
149 
150   float thickness = 1.0f;
151   switch (re->r.line_thickness_mode) {
152     case R_LINE_THICKNESS_ABSOLUTE:
153       thickness = re->r.unit_line_thickness * (re->r.size / 100.f);
154       break;
155     case R_LINE_THICKNESS_RELATIVE:
156       thickness = height / 480.f;
157       break;
158   }
159 
160   g_freestyle.viewport[0] = g_freestyle.viewport[1] = 0;
161   g_freestyle.viewport[2] = width;
162   g_freestyle.viewport[3] = height;
163 
164   view->setWidth(width);
165   view->setHeight(height);
166   view->setBorder(xmin, ymin, xmax, ymax);
167   view->setThickness(thickness);
168 
169   if (G.debug & G_DEBUG_FREESTYLE) {
170     cout << "\n===  Dimensions of the 2D image coordinate system  ===" << endl;
171     cout << "Width  : " << width << endl;
172     cout << "Height : " << height << endl;
173     if (re->r.mode & R_BORDER) {
174       cout << "Border : (" << xmin << ", " << ymin << ") - (" << xmax << ", " << ymax << ")"
175            << endl;
176     }
177     cout << "Unit line thickness : " << thickness << " pixel(s)" << endl;
178   }
179 }
180 
init_camera(Render * re)181 static void init_camera(Render *re)
182 {
183   // It is assumed that imported meshes are in the camera coordinate system.
184   // Therefore, the view point (i.e., camera position) is at the origin, and
185   // the model-view matrix is simply the identity matrix.
186 
187   zero_v3(g_freestyle.viewpoint);
188 
189   unit_m4(g_freestyle.mv);
190 
191   copy_m4_m4(g_freestyle.proj, re->winmat);
192 
193 #if 0
194   print_m4("mv", g_freestyle.mv);
195   print_m4("proj", g_freestyle.proj);
196 #endif
197 }
198 
escape_quotes(char * name)199 static char *escape_quotes(char *name)
200 {
201   char *s = (char *)MEM_mallocN(strlen(name) * 2 + 1, "escape_quotes");
202   char *p = s;
203   while (*name) {
204     if (*name == '\'') {
205       *(p++) = '\\';
206     }
207     *(p++) = *(name++);
208   }
209   *p = '\0';
210   return s;
211 }
212 
create_lineset_handler(char * layer_name,char * lineset_name)213 static char *create_lineset_handler(char *layer_name, char *lineset_name)
214 {
215   const char *fmt = "__import__('parameter_editor').process('%s', '%s')\n";
216   char *s1 = escape_quotes(layer_name);
217   char *s2 = escape_quotes(lineset_name);
218   char *text = BLI_sprintfN(fmt, s1, s2);
219   MEM_freeN(s1);
220   MEM_freeN(s2);
221   return text;
222 }
223 
224 struct edge_type_condition {
225   int edge_type, value;
226 };
227 
228 // examines the conditions and returns true if the target edge type needs to be computed
test_edge_type_conditions(struct edge_type_condition * conditions,int num_edge_types,bool logical_and,int target,bool distinct)229 static bool test_edge_type_conditions(struct edge_type_condition *conditions,
230                                       int num_edge_types,
231                                       bool logical_and,
232                                       int target,
233                                       bool distinct)
234 {
235   int target_condition = 0;
236   int num_non_target_positive_conditions = 0;
237   int num_non_target_negative_conditions = 0;
238 
239   for (int i = 0; i < num_edge_types; i++) {
240     if (conditions[i].edge_type == target) {
241       target_condition = conditions[i].value;
242     }
243     else if (conditions[i].value > 0) {
244       ++num_non_target_positive_conditions;
245     }
246     else if (conditions[i].value < 0) {
247       ++num_non_target_negative_conditions;
248     }
249   }
250   if (distinct) {
251     // In this case, the 'target' edge type is assumed to appear on distinct edge
252     // of its own and never together with other edge types.
253     if (logical_and) {
254       if (num_non_target_positive_conditions > 0) {
255         return false;
256       }
257       if (target_condition > 0) {
258         return true;
259       }
260       if (target_condition < 0) {
261         return false;
262       }
263       if (num_non_target_negative_conditions > 0) {
264         return true;
265       }
266     }
267     else {
268       if (target_condition > 0) {
269         return true;
270       }
271       if (num_non_target_negative_conditions > 0) {
272         return true;
273       }
274       if (target_condition < 0) {
275         return false;
276       }
277       if (num_non_target_positive_conditions > 0) {
278         return false;
279       }
280     }
281   }
282   else {
283     // In this case, the 'target' edge type may appear together with other edge types.
284     if (target_condition > 0) {
285       return true;
286     }
287     if (target_condition < 0) {
288       return true;
289     }
290     if (logical_and) {
291       if (num_non_target_positive_conditions > 0) {
292         return false;
293       }
294       if (num_non_target_negative_conditions > 0) {
295         return true;
296       }
297     }
298     else {
299       if (num_non_target_negative_conditions > 0) {
300         return true;
301       }
302       if (num_non_target_positive_conditions > 0) {
303         return false;
304       }
305     }
306   }
307   return true;
308 }
309 
prepare(Render * re,ViewLayer * view_layer,Depsgraph * depsgraph)310 static void prepare(Render *re, ViewLayer *view_layer, Depsgraph *depsgraph)
311 {
312   // load mesh
313   re->i.infostr = TIP_("Freestyle: Mesh loading");
314   re->stats_draw(re->sdh, &re->i);
315   re->i.infostr = NULL;
316   if (controller->LoadMesh(
317           re, view_layer, depsgraph)) {  // returns if scene cannot be loaded or if empty
318     return;
319   }
320   if (re->test_break(re->tbh)) {
321     return;
322   }
323 
324   // add style modules
325   FreestyleConfig *config = &view_layer->freestyle_config;
326 
327   if (G.debug & G_DEBUG_FREESTYLE) {
328     cout << "\n===  Rendering options  ===" << endl;
329   }
330   int layer_count = 0;
331 
332   switch (config->mode) {
333     case FREESTYLE_CONTROL_SCRIPT_MODE:
334       if (G.debug & G_DEBUG_FREESTYLE) {
335         cout << "Modules :" << endl;
336       }
337       for (FreestyleModuleConfig *module_conf = (FreestyleModuleConfig *)config->modules.first;
338            module_conf;
339            module_conf = module_conf->next) {
340         if (module_conf->script && module_conf->is_displayed) {
341           const char *id_name = module_conf->script->id.name + 2;
342           if (G.debug & G_DEBUG_FREESTYLE) {
343             cout << "  " << layer_count + 1 << ": " << id_name;
344             if (module_conf->script->filepath) {
345               cout << " (" << module_conf->script->filepath << ")";
346             }
347             cout << endl;
348           }
349           controller->InsertStyleModule(layer_count, id_name, module_conf->script);
350           controller->toggleLayer(layer_count, true);
351           layer_count++;
352         }
353       }
354       if (G.debug & G_DEBUG_FREESTYLE) {
355         cout << endl;
356       }
357       controller->setComputeRidgesAndValleysFlag(
358           (config->flags & FREESTYLE_RIDGES_AND_VALLEYS_FLAG) ? true : false);
359       controller->setComputeSuggestiveContoursFlag(
360           (config->flags & FREESTYLE_SUGGESTIVE_CONTOURS_FLAG) ? true : false);
361       controller->setComputeMaterialBoundariesFlag(
362           (config->flags & FREESTYLE_MATERIAL_BOUNDARIES_FLAG) ? true : false);
363       break;
364     case FREESTYLE_CONTROL_EDITOR_MODE:
365       int use_ridges_and_valleys = 0;
366       int use_suggestive_contours = 0;
367       int use_material_boundaries = 0;
368       struct edge_type_condition conditions[] = {
369           {FREESTYLE_FE_SILHOUETTE, 0},
370           {FREESTYLE_FE_BORDER, 0},
371           {FREESTYLE_FE_CREASE, 0},
372           {FREESTYLE_FE_RIDGE_VALLEY, 0},
373           {FREESTYLE_FE_SUGGESTIVE_CONTOUR, 0},
374           {FREESTYLE_FE_MATERIAL_BOUNDARY, 0},
375           {FREESTYLE_FE_CONTOUR, 0},
376           {FREESTYLE_FE_EXTERNAL_CONTOUR, 0},
377           {FREESTYLE_FE_EDGE_MARK, 0},
378       };
379       int num_edge_types = ARRAY_SIZE(conditions);
380       if (G.debug & G_DEBUG_FREESTYLE) {
381         cout << "Linesets:" << endl;
382       }
383       for (FreestyleLineSet *lineset = (FreestyleLineSet *)config->linesets.first; lineset;
384            lineset = lineset->next) {
385         if (lineset->flags & FREESTYLE_LINESET_ENABLED) {
386           if (G.debug & G_DEBUG_FREESTYLE) {
387             cout << "  " << layer_count + 1 << ": " << lineset->name << " - "
388                  << (lineset->linestyle ? (lineset->linestyle->id.name + 2) : "<NULL>") << endl;
389           }
390           char *buffer = create_lineset_handler(view_layer->name, lineset->name);
391           controller->InsertStyleModule(layer_count, lineset->name, buffer);
392           controller->toggleLayer(layer_count, true);
393           MEM_freeN(buffer);
394           if (!(lineset->selection & FREESTYLE_SEL_EDGE_TYPES) || !lineset->edge_types) {
395             ++use_ridges_and_valleys;
396             ++use_suggestive_contours;
397             ++use_material_boundaries;
398           }
399           else {
400             // conditions for feature edge selection by edge types
401             for (int i = 0; i < num_edge_types; i++) {
402               if (!(lineset->edge_types & conditions[i].edge_type)) {
403                 conditions[i].value = 0;  // no condition specified
404               }
405               else if (!(lineset->exclude_edge_types & conditions[i].edge_type)) {
406                 conditions[i].value = 1;  // condition: X
407               }
408               else {
409                 conditions[i].value = -1;  // condition: NOT X
410               }
411             }
412             // logical operator for the selection conditions
413             bool logical_and = ((lineset->flags & FREESTYLE_LINESET_FE_AND) != 0);
414             // negation operator
415             if (lineset->flags & FREESTYLE_LINESET_FE_NOT) {
416               // convert an Exclusive condition into an
417               // Inclusive equivalent using De Morgan's laws:
418               // - NOT (X OR Y) --> (NOT X) AND (NOT Y)
419               // - NOT (X AND Y) --> (NOT X) OR (NOT Y)
420               for (int i = 0; i < num_edge_types; i++) {
421                 conditions[i].value *= -1;
422               }
423               logical_and = !logical_and;
424             }
425             if (test_edge_type_conditions(
426                     conditions, num_edge_types, logical_and, FREESTYLE_FE_RIDGE_VALLEY, true)) {
427               ++use_ridges_and_valleys;
428             }
429             if (test_edge_type_conditions(conditions,
430                                           num_edge_types,
431                                           logical_and,
432                                           FREESTYLE_FE_SUGGESTIVE_CONTOUR,
433                                           true)) {
434               ++use_suggestive_contours;
435             }
436             if (test_edge_type_conditions(conditions,
437                                           num_edge_types,
438                                           logical_and,
439                                           FREESTYLE_FE_MATERIAL_BOUNDARY,
440                                           true)) {
441               ++use_material_boundaries;
442             }
443           }
444           layer_count++;
445         }
446       }
447       controller->setComputeRidgesAndValleysFlag(use_ridges_and_valleys > 0);
448       controller->setComputeSuggestiveContoursFlag(use_suggestive_contours > 0);
449       controller->setComputeMaterialBoundariesFlag(use_material_boundaries > 0);
450       break;
451   }
452 
453   // set parameters
454   if (config->flags & FREESTYLE_ADVANCED_OPTIONS_FLAG) {
455     controller->setSphereRadius(config->sphere_radius);
456     controller->setSuggestiveContourKrDerivativeEpsilon(config->dkr_epsilon);
457   }
458   else {
459     controller->setSphereRadius(DEFAULT_SPHERE_RADIUS);
460     controller->setSuggestiveContourKrDerivativeEpsilon(DEFAULT_DKR_EPSILON);
461   }
462   controller->setFaceSmoothness((config->flags & FREESTYLE_FACE_SMOOTHNESS_FLAG) ? true : false);
463   controller->setCreaseAngle(RAD2DEGF(config->crease_angle));
464   controller->setVisibilityAlgo((config->flags & FREESTYLE_CULLING) ?
465                                     FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE :
466                                     FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE);
467 
468   if (G.debug & G_DEBUG_FREESTYLE) {
469     cout << "Crease angle : " << controller->getCreaseAngle() << endl;
470     cout << "Sphere radius : " << controller->getSphereRadius() << endl;
471     cout << "Face smoothness : " << (controller->getFaceSmoothness() ? "enabled" : "disabled")
472          << endl;
473     cout << "Ridges and valleys : "
474          << (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled") << endl;
475     cout << "Suggestive contours : "
476          << (controller->getComputeSuggestiveContoursFlag() ? "enabled" : "disabled") << endl;
477     cout << "Suggestive contour Kr derivative epsilon : "
478          << controller->getSuggestiveContourKrDerivativeEpsilon() << endl;
479     cout << "Material boundaries : "
480          << (controller->getComputeMaterialBoundariesFlag() ? "enabled" : "disabled") << endl;
481     cout << endl;
482   }
483 
484   // set diffuse and z depth passes
485   RenderLayer *rl = RE_GetRenderLayer(re->result, view_layer->name);
486   bool diffuse = false, z = false;
487   for (RenderPass *rpass = (RenderPass *)rl->passes.first; rpass; rpass = rpass->next) {
488     if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE_COLOR)) {
489       controller->setPassDiffuse(rpass->rect, rpass->rectx, rpass->recty);
490       diffuse = true;
491     }
492     if (STREQ(rpass->name, RE_PASSNAME_Z)) {
493       controller->setPassZ(rpass->rect, rpass->rectx, rpass->recty);
494       z = true;
495     }
496   }
497   if (G.debug & G_DEBUG_FREESTYLE) {
498     cout << "Passes :" << endl;
499     cout << "  Diffuse = " << (diffuse ? "enabled" : "disabled") << endl;
500     cout << "  Z = " << (z ? "enabled" : "disabled") << endl;
501   }
502 
503   if (controller->hitViewMapCache()) {
504     return;
505   }
506 
507   // compute view map
508   re->i.infostr = TIP_("Freestyle: View map creation");
509   re->stats_draw(re->sdh, &re->i);
510   re->i.infostr = NULL;
511   controller->ComputeViewMap();
512 }
513 
FRS_composite_result(Render * re,ViewLayer * view_layer,Render * freestyle_render)514 void FRS_composite_result(Render *re, ViewLayer *view_layer, Render *freestyle_render)
515 {
516   RenderLayer *rl;
517   float *src, *dest, *pixSrc, *pixDest;
518   int x, y, rectx, recty;
519 
520   if (freestyle_render == NULL || freestyle_render->result == NULL) {
521     return;
522   }
523 
524   rl = render_get_active_layer(freestyle_render, freestyle_render->result);
525   if (!rl) {
526     if (G.debug & G_DEBUG_FREESTYLE) {
527       cout << "No source render layer to composite" << endl;
528     }
529     return;
530   }
531 
532   src = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, freestyle_render->viewname);
533   if (!src) {
534     if (G.debug & G_DEBUG_FREESTYLE) {
535       cout << "No source result image to composite" << endl;
536     }
537     return;
538   }
539 #if 0
540   if (G.debug & G_DEBUG_FREESTYLE) {
541     cout << "src: " << rl->rectx << " x " << rl->recty << endl;
542   }
543 #endif
544 
545   rl = RE_GetRenderLayer(re->result, view_layer->name);
546   if (!rl) {
547     if (G.debug & G_DEBUG_FREESTYLE) {
548       cout << "No destination render layer to composite to" << endl;
549     }
550     return;
551   }
552 
553   if (view_layer->freestyle_config.flags & FREESTYLE_AS_RENDER_PASS) {
554     RE_create_render_pass(
555         re->result, RE_PASSNAME_FREESTYLE, 4, "RGBA", view_layer->name, re->viewname);
556     dest = RE_RenderLayerGetPass(rl, RE_PASSNAME_FREESTYLE, re->viewname);
557   }
558   else {
559     dest = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, re->viewname);
560   }
561   if (!dest) {
562     if (G.debug & G_DEBUG_FREESTYLE) {
563       cout << "No destination result image to composite to" << endl;
564     }
565     return;
566   }
567 #if 0
568   if (G.debug & G_DEBUG_FREESTYLE) {
569     cout << "dest: " << rl->rectx << " x " << rl->recty << endl;
570   }
571 #endif
572 
573   rectx = re->rectx;
574   recty = re->recty;
575   for (y = 0; y < recty; y++) {
576     for (x = 0; x < rectx; x++) {
577       pixSrc = src + 4 * (rectx * y + x);
578       if (pixSrc[3] > 0.0) {
579         pixDest = dest + 4 * (rectx * y + x);
580         blend_color_mix_float(pixDest, pixDest, pixSrc);
581       }
582     }
583   }
584 }
585 
displayed_layer_count(ViewLayer * view_layer)586 static int displayed_layer_count(ViewLayer *view_layer)
587 {
588   int count = 0;
589 
590   switch (view_layer->freestyle_config.mode) {
591     case FREESTYLE_CONTROL_SCRIPT_MODE:
592       for (FreestyleModuleConfig *module =
593                (FreestyleModuleConfig *)view_layer->freestyle_config.modules.first;
594            module;
595            module = module->next) {
596         if (module->script && module->is_displayed) {
597           count++;
598         }
599       }
600       break;
601     case FREESTYLE_CONTROL_EDITOR_MODE:
602       for (FreestyleLineSet *lineset =
603                (FreestyleLineSet *)view_layer->freestyle_config.linesets.first;
604            lineset;
605            lineset = lineset->next) {
606         if (lineset->flags & FREESTYLE_LINESET_ENABLED) {
607           count++;
608         }
609       }
610       break;
611   }
612   return count;
613 }
614 
FRS_is_freestyle_enabled(ViewLayer * view_layer)615 int FRS_is_freestyle_enabled(ViewLayer *view_layer)
616 {
617   return ((view_layer->flag & VIEW_LAYER_RENDER) && (view_layer->flag & VIEW_LAYER_FREESTYLE) &&
618           displayed_layer_count(view_layer) > 0);
619 }
620 
FRS_init_stroke_renderer(Render * re)621 void FRS_init_stroke_renderer(Render *re)
622 {
623   if (G.debug & G_DEBUG_FREESTYLE) {
624     cout << endl;
625     cout << "#===============================================================" << endl;
626     cout << "#  Freestyle" << endl;
627     cout << "#===============================================================" << endl;
628   }
629 
630   init_view(re);
631 
632   controller->ResetRenderCount();
633 }
634 
FRS_begin_stroke_rendering(Render * re)635 void FRS_begin_stroke_rendering(Render *re)
636 {
637   init_camera(re);
638 }
639 
FRS_do_stroke_rendering(Render * re,ViewLayer * view_layer)640 void FRS_do_stroke_rendering(Render *re, ViewLayer *view_layer)
641 {
642   RenderMonitor monitor(re);
643   controller->setRenderMonitor(&monitor);
644   controller->setViewMapCache(
645       (view_layer->freestyle_config.flags & FREESTYLE_VIEW_MAP_CACHE) ? true : false);
646 
647   if (G.debug & G_DEBUG_FREESTYLE) {
648     cout << endl;
649     cout << "----------------------------------------------------------" << endl;
650     cout << "|  " << (re->scene->id.name + 2) << "|" << view_layer->name << endl;
651     cout << "----------------------------------------------------------" << endl;
652   }
653 
654   /* Create depsgraph and evaluate scene. */
655   ViewLayer *scene_view_layer = (ViewLayer *)BLI_findstring(
656       &re->scene->view_layers, view_layer->name, offsetof(ViewLayer, name));
657   Depsgraph *depsgraph = DEG_graph_new(re->main, re->scene, scene_view_layer, DAG_EVAL_RENDER);
658   BKE_scene_graph_update_for_newframe(depsgraph);
659 
660   // prepare Freestyle:
661   //   - load mesh
662   //   - add style modules
663   //   - set parameters
664   //   - compute view map
665   prepare(re, view_layer, depsgraph);
666 
667   if (re->test_break(re->tbh)) {
668     controller->CloseFile();
669     if (G.debug & G_DEBUG_FREESTYLE) {
670       cout << "Break" << endl;
671     }
672   }
673   else {
674     // render and composite Freestyle result
675     if (controller->_ViewMap) {
676       // render strokes
677       re->i.infostr = TIP_("Freestyle: Stroke rendering");
678       re->stats_draw(re->sdh, &re->i);
679       re->i.infostr = NULL;
680       g_freestyle.scene = DEG_get_evaluated_scene(depsgraph);
681       int strokeCount = controller->DrawStrokes();
682       Render *freestyle_render = NULL;
683       if (strokeCount > 0) {
684         freestyle_render = controller->RenderStrokes(re, true);
685       }
686       controller->CloseFile();
687       g_freestyle.scene = NULL;
688 
689       // composite result
690       if (freestyle_render) {
691         FRS_composite_result(re, view_layer, freestyle_render);
692         RE_FreeRender(freestyle_render);
693       }
694     }
695   }
696 
697   DEG_graph_free(depsgraph);
698 }
699 
FRS_end_stroke_rendering(Render *)700 void FRS_end_stroke_rendering(Render * /*re*/)
701 {
702   // clear canvas
703   controller->Clear();
704 }
705 
FRS_free_view_map_cache(void)706 void FRS_free_view_map_cache(void)
707 {
708   // free cache
709   controller->DeleteViewMap(true);
710 #if 0
711   if (G.debug & G_DEBUG_FREESTYLE) {
712     printf("View map cache freed\n");
713   }
714 #endif
715 }
716 
717 //=======================================================
718 //   Freestyle Panel Configuration
719 //=======================================================
720 
FRS_copy_active_lineset(FreestyleConfig * config)721 void FRS_copy_active_lineset(FreestyleConfig *config)
722 {
723   FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
724 
725   if (lineset) {
726     lineset_buffer.linestyle = lineset->linestyle;
727     lineset_buffer.flags = lineset->flags;
728     lineset_buffer.selection = lineset->selection;
729     lineset_buffer.qi = lineset->qi;
730     lineset_buffer.qi_start = lineset->qi_start;
731     lineset_buffer.qi_end = lineset->qi_end;
732     lineset_buffer.edge_types = lineset->edge_types;
733     lineset_buffer.exclude_edge_types = lineset->exclude_edge_types;
734     lineset_buffer.group = lineset->group;
735     strcpy(lineset_buffer.name, lineset->name);
736     lineset_copied = true;
737   }
738 }
739 
FRS_paste_active_lineset(FreestyleConfig * config)740 void FRS_paste_active_lineset(FreestyleConfig *config)
741 {
742   if (!lineset_copied) {
743     return;
744   }
745 
746   FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
747 
748   if (lineset) {
749     if (lineset->linestyle) {
750       id_us_min(&lineset->linestyle->id);
751     }
752     lineset->linestyle = lineset_buffer.linestyle;
753     if (lineset->linestyle) {
754       id_us_plus(&lineset->linestyle->id);
755     }
756     lineset->flags = lineset_buffer.flags;
757     lineset->selection = lineset_buffer.selection;
758     lineset->qi = lineset_buffer.qi;
759     lineset->qi_start = lineset_buffer.qi_start;
760     lineset->qi_end = lineset_buffer.qi_end;
761     lineset->edge_types = lineset_buffer.edge_types;
762     lineset->exclude_edge_types = lineset_buffer.exclude_edge_types;
763     if (lineset->group) {
764       id_us_min(&lineset->group->id);
765       lineset->group = NULL;
766     }
767     if (lineset_buffer.group) {
768       lineset->group = lineset_buffer.group;
769       id_us_plus(&lineset->group->id);
770     }
771     strcpy(lineset->name, lineset_buffer.name);
772     BKE_freestyle_lineset_unique_name(config, lineset);
773     lineset->flags |= FREESTYLE_LINESET_CURRENT;
774   }
775 }
776 
FRS_delete_active_lineset(FreestyleConfig * config)777 void FRS_delete_active_lineset(FreestyleConfig *config)
778 {
779   FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
780 
781   if (lineset) {
782     BKE_freestyle_lineset_delete(config, lineset);
783   }
784 }
785 
786 /**
787  * Reinsert the active lineset at an offset \a direction from current position.
788  * \return if position of active lineset has changed.
789  */
FRS_move_active_lineset(FreestyleConfig * config,int direction)790 bool FRS_move_active_lineset(FreestyleConfig *config, int direction)
791 {
792   FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
793   return (lineset != NULL) && BLI_listbase_link_move(&config->linesets, lineset, direction);
794 }
795 
796 // Testing
797 
FRS_create_stroke_material(Main * bmain,struct FreestyleLineStyle * linestyle)798 Material *FRS_create_stroke_material(Main *bmain, struct FreestyleLineStyle *linestyle)
799 {
800   bNodeTree *nt = (linestyle->use_nodes) ? linestyle->nodetree : NULL;
801   Material *ma = BlenderStrokeRenderer::GetStrokeShader(bmain, nt, true);
802   ma->id.us = 0;
803   return ma;
804 }
805 
806 }  // extern "C"
807