quiet warnings by making undeclared vars static
[blender.git] / source / blender / freestyle / intern / blender_interface / FRS_freestyle.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2010 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
29  *  \ingroup freestyle
30  */
31
32 #include <iostream>
33 #include <map>
34 #include <set>
35
36 #include "../application/AppCanvas.h"
37 #include "../application/AppConfig.h"
38 #include "../application/AppView.h"
39 #include "../application/Controller.h"
40
41 #include "BKE_global.h"
42
43 using namespace std;
44
45 // XXX Are those "ifdef __cplusplus" useful here?
46 #ifdef __cplusplus
47 extern "C" {
48 #endif
49
50 #include "MEM_guardedalloc.h"
51
52 #include "DNA_camera_types.h"
53 #include "DNA_freestyle_types.h"
54 #include "DNA_group_types.h"
55 #include "DNA_text_types.h"
56
57 #include "BKE_global.h"
58 #include "BKE_library.h"
59 #include "BKE_linestyle.h"
60 #include "BKE_main.h"
61 #include "BKE_text.h"
62
63 #include "BLI_blenlib.h"
64 #include "BLI_math.h"
65
66 #include "BPY_extern.h"
67
68 #include "renderpipeline.h"
69 #include "pixelblending.h"
70
71 #include "FRS_freestyle.h"
72 #include "FRS_freestyle_config.h"
73
74 #define DEFAULT_SPHERE_RADIUS 1.0f
75 #define DEFAULT_DKR_EPSILON   0.0f
76
77 // Freestyle configuration
78 static short freestyle_is_initialized = 0;
79 static Config::Path *pathconfig = NULL;
80 static Controller *controller = NULL;
81 static AppView *view = NULL;
82
83 // line set buffer for copy & paste
84 static FreestyleLineSet lineset_buffer;
85 static bool lineset_copied = false;
86
87 // camera information
88 float freestyle_viewpoint[3];
89 float freestyle_mv[4][4];
90 float freestyle_proj[4][4];
91 int freestyle_viewport[4];
92
93 // current scene
94 Scene *freestyle_scene;
95
96 static string default_module_path;
97
98 // function declarations
99 static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset);
100 static void copy_module(FreestyleModuleConfig *new_module, FreestyleModuleConfig *module);
101
102 //=======================================================
103 //   Initialization 
104 //=======================================================
105
106 void FRS_initialize()
107 {
108         if (freestyle_is_initialized)
109                 return;
110
111         pathconfig = new Config::Path;
112         controller = new Controller();
113         view = new AppView;
114         controller->setView(view);
115         controller->Clear();
116         freestyle_scene = NULL;
117         lineset_copied = false;
118
119         default_module_path = pathconfig->getProjectDir() + Config::DIR_SEP + "style_modules" +
120                               Config::DIR_SEP + "contour.py";
121
122         freestyle_is_initialized = 1;
123 }
124
125 void FRS_set_context(bContext *C)
126 {
127         if (G.debug & G_DEBUG_FREESTYLE) {
128                 cout << "FRS_set_context: context 0x" << C << " scene 0x" << CTX_data_scene(C) << endl;
129         }
130         controller->setContext(C);
131 }
132
133 void FRS_read_file(bContext *C)
134 {
135         lineset_copied = false;
136 }
137
138 void FRS_exit()
139 {
140         delete pathconfig;
141         delete controller;
142         delete view;
143 }
144
145 //=======================================================
146 //   Rendering 
147 //=======================================================
148
149 static void init_view(Render *re)
150 {
151         int width = re->winx;
152         int height = re->winy;
153         int xmin = re->disprect.xmin;
154         int ymin = re->disprect.ymin;
155         int xmax = re->disprect.xmax;
156         int ymax = re->disprect.ymax;
157
158         float thickness = 1.0f;
159         switch (re->r.line_thickness_mode) {
160         case R_LINE_THICKNESS_ABSOLUTE:
161                 thickness = re->r.unit_line_thickness * (re->r.size / 100.f);
162                 break;
163         case R_LINE_THICKNESS_RELATIVE:
164                 thickness = height / 480.f;
165                 break;
166         }
167
168         freestyle_viewport[0] = freestyle_viewport[1] = 0;
169         freestyle_viewport[2] = width;
170         freestyle_viewport[3] = height;
171
172         view->setWidth(width);
173         view->setHeight(height);
174         view->setBorder(xmin, ymin, xmax, ymax);
175         view->setThickness(thickness);
176
177         if (G.debug & G_DEBUG_FREESTYLE) {
178                 cout << "\n===  Dimensions of the 2D image coordinate system  ===" << endl;
179                 cout << "Width  : " << width << endl;
180                 cout << "Height : " << height << endl;
181                 if (re->r.mode & R_BORDER)
182                         cout << "Border : (" << xmin << ", " << ymin << ") - (" << xmax << ", " << ymax << ")" << endl;
183                 cout << "Unit line thickness : " << thickness << " pixel(s)" << endl;
184         }
185 }
186
187 static void init_camera(Render *re)
188 {
189         // It is assumed that imported meshes are in the camera coordinate system.
190         // Therefore, the view point (i.e., camera position) is at the origin, and
191         // the the model-view matrix is simply the identity matrix.
192
193         freestyle_viewpoint[0] = 0.0;
194         freestyle_viewpoint[1] = 0.0;
195         freestyle_viewpoint[2] = 0.0;
196
197         unit_m4(freestyle_mv);
198
199         copy_m4_m4(freestyle_proj, re->winmat);
200
201 #if 0
202         print_m4("mv", freestyle_mv);
203         print_m4("proj", freestyle_proj);
204 #endif
205 }
206
207 static char *escape_quotes(char *name)
208 {
209         char *s = (char *)MEM_mallocN(strlen(name) * 2 + 1, "escape_quotes");
210         char *p = s;
211         while (*name) {
212                 if (*name == '\'')
213                         *(p++) = '\\';
214                 *(p++) = *(name++);
215         }
216         *p = '\0';
217         return s;
218 }
219
220 static Text *create_lineset_handler(char *layer_name, char *lineset_name)
221 {
222         char *s1 = escape_quotes(layer_name);
223         char *s2 = escape_quotes(lineset_name);
224         Text *text = BKE_text_add(G.main, lineset_name);
225         BKE_text_write(text, "import parameter_editor; parameter_editor.process('");
226         BKE_text_write(text, s1);
227         BKE_text_write(text, "', '");
228         BKE_text_write(text, s2);
229         BKE_text_write(text, "')\n");
230         MEM_freeN(s1);
231         MEM_freeN(s2);
232         return text;
233 }
234
235 struct edge_type_condition
236 {
237         int edge_type, value;
238 };
239
240 // examines the conditions and returns true if the target edge type needs to be computed
241 static bool test_edge_type_conditions(struct edge_type_condition *conditions,
242                                       int num_edge_types, bool logical_and, int target, bool distinct)
243 {
244         int target_condition = 0;
245         int num_non_target_positive_conditions = 0;
246         int num_non_target_negative_conditions = 0;
247
248         for (int i = 0; i < num_edge_types; i++) {
249                 if (conditions[i].edge_type == target)
250                         target_condition = conditions[i].value;
251                 else if (conditions[i].value > 0)
252                         ++num_non_target_positive_conditions;
253                 else if (conditions[i].value < 0)
254                         ++num_non_target_negative_conditions;
255         }
256         if (distinct) {
257                 // In this case, the 'target' edge type is assumed to appear on distinct edge
258                 // of its own and never together with other edge types.
259                 if (logical_and) {
260                         if (num_non_target_positive_conditions > 0)
261                                 return false;
262                         if (target_condition > 0)
263                                 return true;
264                         if (target_condition < 0)
265                                 return false;
266                         if (num_non_target_negative_conditions > 0)
267                                 return true;
268                 }
269                 else {
270                         if (target_condition > 0)
271                                 return true;
272                         if (num_non_target_negative_conditions > 0)
273                                 return true;
274                         if (target_condition < 0)
275                                 return false;
276                         if (num_non_target_positive_conditions > 0)
277                                 return false;
278                 }
279         }
280         else {
281                 // In this case, the 'target' edge type may appear together with other edge types.
282                 if (target_condition > 0)
283                         return true;
284                 if (target_condition < 0)
285                         return true;
286                 if (logical_and) {
287                         if (num_non_target_positive_conditions > 0)
288                                 return false;
289                         if (num_non_target_negative_conditions > 0)
290                                 return true;
291                 }
292                 else {
293                         if (num_non_target_negative_conditions > 0)
294                                 return true;
295                         if (num_non_target_positive_conditions > 0)
296                                 return false;
297                 }
298         }
299         return true;
300 }
301
302 static void prepare(Render *re, SceneRenderLayer *srl)
303 {
304         // load mesh
305         re->i.infostr = "Freestyle: Mesh loading";
306         re->stats_draw(re->sdh, &re->i);
307         re->i.infostr = NULL;
308         if (controller->LoadMesh(re, srl)) // returns if scene cannot be loaded or if empty
309                 return;
310         if (re->test_break(re->tbh))
311                 return;
312
313         // add style modules
314         FreestyleConfig *config = &srl->freestyleConfig;
315
316         if (G.debug & G_DEBUG_FREESTYLE) {
317                 cout << "\n===  Rendering options  ===" << endl;
318         }
319         int layer_count = 0;
320
321         switch (config->mode) {
322         case FREESTYLE_CONTROL_SCRIPT_MODE:
323                 if (G.debug & G_DEBUG_FREESTYLE) {
324                         cout << "Modules :" << endl;
325                 }
326                 for (FreestyleModuleConfig *module_conf = (FreestyleModuleConfig *)config->modules.first;
327                      module_conf;
328                      module_conf = module_conf->next)
329                 {
330                         if (module_conf->is_displayed) {
331                                 if (G.debug & G_DEBUG_FREESTYLE) {
332                                         cout << "  " << layer_count + 1 << ": " << module_conf->module_path << endl;
333                                 }
334                                 controller->InsertStyleModule(layer_count, module_conf->module_path);
335                                 controller->toggleLayer(layer_count, true);
336                                 layer_count++;
337                         }
338                 }
339                 if (G.debug & G_DEBUG_FREESTYLE) {
340                         cout << endl;
341                 }
342                 controller->setComputeRidgesAndValleysFlag((config->flags & FREESTYLE_RIDGES_AND_VALLEYS_FLAG) ? true : false);
343                 controller->setComputeSuggestiveContoursFlag((config->flags & FREESTYLE_SUGGESTIVE_CONTOURS_FLAG) ? true : false);
344                 controller->setComputeMaterialBoundariesFlag((config->flags & FREESTYLE_MATERIAL_BOUNDARIES_FLAG) ? true : false);
345                 break;
346         case FREESTYLE_CONTROL_EDITOR_MODE:
347                 int use_ridges_and_valleys = 0;
348                 int use_suggestive_contours = 0;
349                 int use_material_boundaries = 0;
350                 struct edge_type_condition conditions[] = {
351                         {FREESTYLE_FE_SILHOUETTE, 0},
352                         {FREESTYLE_FE_BORDER, 0},
353                         {FREESTYLE_FE_CREASE, 0},
354                         {FREESTYLE_FE_RIDGE_VALLEY, 0},
355                         {FREESTYLE_FE_SUGGESTIVE_CONTOUR, 0},
356                         {FREESTYLE_FE_MATERIAL_BOUNDARY, 0},
357                         {FREESTYLE_FE_CONTOUR, 0},
358                         {FREESTYLE_FE_EXTERNAL_CONTOUR, 0},
359                         {FREESTYLE_FE_EDGE_MARK, 0}
360                 };
361                 int num_edge_types = sizeof(conditions) / sizeof(struct edge_type_condition);
362                 if (G.debug & G_DEBUG_FREESTYLE) {
363                         cout << "Linesets:" << endl;
364                 }
365                 for (FreestyleLineSet *lineset = (FreestyleLineSet *)config->linesets.first;
366                      lineset;
367                      lineset = lineset->next)
368                 {
369                         if (lineset->flags & FREESTYLE_LINESET_ENABLED) {
370                                 if (G.debug & G_DEBUG_FREESTYLE) {
371                                         cout << "  " << layer_count+1 << ": " << lineset->name << " - " <<
372                                                 lineset->linestyle->id.name + 2 << endl;
373                                 }
374                                 Text *text = create_lineset_handler(srl->name, lineset->name);
375                                 controller->InsertStyleModule(layer_count, lineset->name, text);
376                                 controller->toggleLayer(layer_count, true);
377                                 if (!(lineset->selection & FREESTYLE_SEL_EDGE_TYPES) || !lineset->edge_types) {
378                                         ++use_ridges_and_valleys;
379                                         ++use_suggestive_contours;
380                                         ++use_material_boundaries;
381                                 }
382                                 else {
383                                         // conditions for feature edge selection by edge types
384                                         for (int i = 0; i < num_edge_types; i++) {
385                                                 if (!(lineset->edge_types & conditions[i].edge_type))
386                                                         conditions[i].value = 0; // no condition specified
387                                                 else if (!(lineset->exclude_edge_types & conditions[i].edge_type))
388                                                         conditions[i].value = 1; // condition: X
389                                                 else
390                                                         conditions[i].value = -1; // condition: NOT X
391                                         }
392                                         // logical operator for the selection conditions
393                                         bool logical_and = ((lineset->flags & FREESTYLE_LINESET_FE_AND) != 0);
394                                         // negation operator
395                                         if (lineset->flags & FREESTYLE_LINESET_FE_NOT) {
396                                                 // convert an Exclusive condition into an Inclusive equivalent using De Morgan's laws:
397                                                 //   NOT (X OR Y) --> (NOT X) AND (NOT Y)
398                                                 //   NOT (X AND Y) --> (NOT X) OR (NOT Y)
399                                                 for (int i = 0; i < num_edge_types; i++)
400                                                         conditions[i].value *= -1;
401                                                 logical_and = !logical_and;
402                                         }
403                                         if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
404                                                                       FREESTYLE_FE_RIDGE_VALLEY, true))
405                                         {
406                                                 ++use_ridges_and_valleys;
407                                         }
408                                         if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
409                                                                       FREESTYLE_FE_SUGGESTIVE_CONTOUR, true))
410                                         {
411                                                 ++use_suggestive_contours;
412                                         }
413                                         if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
414                                                                       FREESTYLE_FE_MATERIAL_BOUNDARY, true))
415                                         {
416                                                 ++use_material_boundaries;
417                                         }
418                                 }
419                                 layer_count++;
420                         }
421                 }
422                 controller->setComputeRidgesAndValleysFlag(use_ridges_and_valleys > 0);
423                 controller->setComputeSuggestiveContoursFlag(use_suggestive_contours > 0);
424                 controller->setComputeMaterialBoundariesFlag(use_material_boundaries > 0);
425                 break;
426         }
427
428         // set parameters
429         if (config->flags & FREESTYLE_ADVANCED_OPTIONS_FLAG) {
430                 controller->setSphereRadius(config->sphere_radius);
431                 controller->setSuggestiveContourKrDerivativeEpsilon(config->dkr_epsilon);
432         }
433         else {
434                 controller->setSphereRadius(DEFAULT_SPHERE_RADIUS);
435                 controller->setSuggestiveContourKrDerivativeEpsilon(DEFAULT_DKR_EPSILON);
436         }
437         controller->setFaceSmoothness((config->flags & FREESTYLE_FACE_SMOOTHNESS_FLAG) ? true : false);
438         controller->setCreaseAngle(RAD2DEGF(config->crease_angle));
439         controller->setVisibilityAlgo((config->flags & FREESTYLE_CULLING) ?
440                                       FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE :
441                                       FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE);
442
443         if (G.debug & G_DEBUG_FREESTYLE) {
444                 cout << "Crease angle : " << controller->getCreaseAngle() << endl;
445                 cout << "Sphere radius : " << controller->getSphereRadius() << endl;
446                 cout << "Face smoothness : " << (controller->getFaceSmoothness() ? "enabled" : "disabled") << endl;
447                 cout << "Redges and valleys : " << (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled") <<
448                         endl;
449                 cout << "Suggestive contours : " <<
450                         (controller->getComputeSuggestiveContoursFlag() ? "enabled" : "disabled") << endl;
451                 cout << "Suggestive contour Kr derivative epsilon : " <<
452                         controller->getSuggestiveContourKrDerivativeEpsilon() << endl;
453                 cout << "Material boundaries : " <<
454                         (controller->getComputeMaterialBoundariesFlag() ? "enabled" : "disabled") << endl;
455                 cout << endl;
456         }
457
458         // set diffuse and z depth passes
459         RenderLayer *rl = RE_GetRenderLayer(re->result, srl->name);
460         bool diffuse = false, z = false;
461         for (RenderPass *rpass = (RenderPass *)rl->passes.first; rpass; rpass = rpass->next) {
462                 switch (rpass->passtype) {
463                 case SCE_PASS_DIFFUSE:
464                         controller->setPassDiffuse(rpass->rect, rpass->rectx, rpass->recty);
465                         diffuse = true;
466                         break;
467                 case SCE_PASS_Z:
468                         controller->setPassZ(rpass->rect, rpass->rectx, rpass->recty);
469                         z = true;
470                         break;
471                 }
472         }
473         if (G.debug & G_DEBUG_FREESTYLE) {
474                 cout << "Passes :" << endl;
475                 cout << "  Diffuse = " << (diffuse ? "enabled" : "disabled") << endl;
476                 cout << "  Z = " << (z ? "enabled" : "disabled") << endl;
477         }
478
479         // compute view map
480         re->i.infostr = "Freestyle: View map creation";
481         re->stats_draw(re->sdh, &re->i);
482         re->i.infostr = NULL;
483         controller->ComputeViewMap();
484 }
485
486 void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_render)
487 {
488         RenderLayer *rl;
489         float *src, *dest, *pixSrc, *pixDest;
490         int x, y, rectx, recty;
491
492         if (freestyle_render == NULL || freestyle_render->result == NULL)
493                 return;
494
495         rl = render_get_active_layer( freestyle_render, freestyle_render->result );
496         if (!rl || rl->rectf == NULL) {
497                 if (G.debug & G_DEBUG_FREESTYLE) {
498                         cout << "Cannot find Freestyle result image" << endl;
499                 }
500                 return;
501         }
502         src  = rl->rectf;
503 #if 0
504         if (G.debug & G_DEBUG_FREESTYLE) {
505                 cout << "src: " << rl->rectx << " x " << rl->recty << endl;
506         }
507 #endif
508
509         rl = RE_GetRenderLayer(re->result, srl->name);
510         if (!rl || rl->rectf == NULL) {
511                 if (G.debug & G_DEBUG_FREESTYLE) {
512                         cout << "No layer to composite to" << endl;
513                 }
514                 return;
515         }
516         dest = rl->rectf;
517 #if 0
518         if (G.debug & G_DEBUG_FREESTYLE) {
519                 cout << "dest: " << rl->rectx << " x " << rl->recty << endl;
520         }
521 #endif
522
523         rectx = re->rectx;
524         recty = re->recty;
525         for (y = 0; y < recty; y++) {
526                 for (x = 0; x < rectx; x++) {
527                         pixSrc = src + 4 * (rectx * y + x);
528                         if (pixSrc[3] > 0.0) {
529                                 pixDest = dest + 4 * (rectx * y + x);
530                                 addAlphaOverFloat(pixDest, pixSrc);
531                         }
532                 }
533         }
534 }
535
536 static int displayed_layer_count(SceneRenderLayer *srl)
537 {
538         int count = 0;
539
540         switch (srl->freestyleConfig.mode) {
541         case FREESTYLE_CONTROL_SCRIPT_MODE:
542                 for (FreestyleModuleConfig *module = (FreestyleModuleConfig *)srl->freestyleConfig.modules.first;
543                      module;
544                      module = module->next)
545                 {
546                         if (module->is_displayed)
547                                 count++;
548                 }
549                 break;
550         case FREESTYLE_CONTROL_EDITOR_MODE:
551                 for (FreestyleLineSet *lineset = (FreestyleLineSet *)srl->freestyleConfig.linesets.first;
552                      lineset;
553                      lineset = lineset->next)
554                 {
555                         if (lineset->flags & FREESTYLE_LINESET_ENABLED)
556                                 count++;
557                 }
558                 break;
559         }
560         return count;
561 }
562
563 int FRS_is_freestyle_enabled(SceneRenderLayer *srl)
564 {
565         return (!(srl->layflag & SCE_LAY_DISABLE) && srl->layflag & SCE_LAY_FRS && displayed_layer_count(srl) > 0);
566 }
567
568 void FRS_init_stroke_rendering(Render *re)
569 {
570         if (G.debug & G_DEBUG_FREESTYLE) {
571                 cout << endl;
572                 cout << "#===============================================================" << endl;
573                 cout << "#  Freestyle" << endl;
574                 cout << "#===============================================================" << endl;
575         }
576
577         init_view(re);
578         init_camera(re);
579
580         controller->ResetRenderCount();
581 }
582
583 Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl)
584 {
585         Render *freestyle_render = NULL;
586
587         RenderMonitor monitor(re);
588         controller->setRenderMonitor(&monitor);
589
590         if (G.debug & G_DEBUG_FREESTYLE) {
591                 cout << endl;
592                 cout << "----------------------------------------------------------" << endl;
593                 cout << "|  " << (re->scene->id.name + 2) << "|" << srl->name << endl;
594                 cout << "----------------------------------------------------------" << endl;
595         }
596
597         // prepare Freestyle:
598         //   - load mesh
599         //   - add style modules
600         //   - set parameters
601         //   - compute view map
602         prepare(re, srl);
603
604         if (re->test_break(re->tbh)) {
605                 controller->CloseFile();
606                 if (G.debug & G_DEBUG_FREESTYLE) {
607                         cout << "Break" << endl;
608                 }
609                 return NULL;
610         }
611
612         // render and composite Freestyle result
613         if (controller->_ViewMap) {
614                 // render strokes
615                 re->i.infostr = "Freestyle: Stroke rendering";
616                 re->stats_draw(re->sdh, &re->i);
617                 re->i.infostr = NULL;
618                 freestyle_scene = re->scene;
619                 controller->DrawStrokes();
620                 freestyle_render = controller->RenderStrokes(re);
621                 controller->CloseFile();
622                 freestyle_scene = NULL;
623
624                 // composite result
625                 FRS_composite_result(re, srl, freestyle_render);
626                 RE_FreeRenderResult(freestyle_render->result);
627                 freestyle_render->result = NULL;
628         }
629
630         return freestyle_render;
631 }
632
633 void FRS_finish_stroke_rendering(Render *re)
634 {
635         // clear canvas
636         controller->Clear();
637 }
638
639 //=======================================================
640 //   Freestyle Panel Configuration
641 //=======================================================
642
643 void FRS_init_freestyle_config(FreestyleConfig *config)
644 {
645         config->mode = FREESTYLE_CONTROL_SCRIPT_MODE;
646
647         config->modules.first = config->modules.last = NULL;
648         config->flags = 0;
649         config->sphere_radius = DEFAULT_SPHERE_RADIUS;
650         config->dkr_epsilon = DEFAULT_DKR_EPSILON;
651         config->crease_angle = DEG2RADF(120.0f);
652
653         config->linesets.first = config->linesets.last = NULL;
654 }
655
656 void FRS_free_freestyle_config(FreestyleConfig *config)
657 {
658         FreestyleLineSet *lineset;
659
660         for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
661                 if (lineset->group) {
662                         lineset->group->id.us--;
663                         lineset->group = NULL;
664                 }
665                 lineset->linestyle->id.us--;
666                 lineset->linestyle = NULL;
667         }
668         BLI_freelistN(&config->linesets);
669         BLI_freelistN(&config->modules);
670 }
671
672 void FRS_copy_freestyle_config(FreestyleConfig *new_config, FreestyleConfig *config)
673 {
674         FreestyleLineSet *lineset, *new_lineset;
675         FreestyleModuleConfig *module, *new_module;
676
677         new_config->mode = config->mode;
678         new_config->raycasting_algorithm = config->raycasting_algorithm; /* deprecated */
679         new_config->flags = config->flags;
680         new_config->sphere_radius = config->sphere_radius;
681         new_config->dkr_epsilon = config->dkr_epsilon;
682         new_config->crease_angle = config->crease_angle;
683
684         new_config->linesets.first = new_config->linesets.last = NULL;
685         for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
686                 new_lineset = FRS_alloc_lineset();
687                 copy_lineset(new_lineset, lineset);
688                 BLI_addtail(&new_config->linesets, (void *)new_lineset);
689         }
690
691         new_config->modules.first = new_config->modules.last = NULL;
692         for (module = (FreestyleModuleConfig *)config->modules.first; module; module = module->next) {
693                 new_module = FRS_alloc_module();
694                 copy_module(new_module, module);
695                 BLI_addtail(&new_config->modules, (void *)new_module);
696         }
697 }
698
699 static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset)
700 {
701         new_lineset->linestyle = lineset->linestyle;
702         new_lineset->linestyle->id.us++;
703         new_lineset->flags = lineset->flags;
704         new_lineset->selection = lineset->selection;
705         new_lineset->qi = lineset->qi;
706         new_lineset->qi_start = lineset->qi_start;
707         new_lineset->qi_end = lineset->qi_end;
708         new_lineset->edge_types = lineset->edge_types;
709         new_lineset->exclude_edge_types = lineset->exclude_edge_types;
710         new_lineset->group = lineset->group;
711         if (new_lineset->group) {
712                 new_lineset->group->id.us++;
713         }
714         strcpy(new_lineset->name, lineset->name);
715 }
716
717 FreestyleModuleConfig *FRS_alloc_module()
718 {
719         return (FreestyleModuleConfig *)MEM_callocN(sizeof(FreestyleModuleConfig), "style module configuration");
720 }
721
722 void FRS_add_module(FreestyleConfig *config)
723 {
724         FreestyleModuleConfig *module_conf = (FreestyleModuleConfig *)MEM_callocN(sizeof(FreestyleModuleConfig),
725                                                                                   "style module configuration");
726         BLI_addtail(&config->modules, (void *)module_conf);
727
728         strcpy(module_conf->module_path, default_module_path.c_str());
729         module_conf->is_displayed = 1;
730 }
731
732 static void copy_module(FreestyleModuleConfig *new_module, FreestyleModuleConfig *module)
733 {
734         strcpy(new_module->module_path, module->module_path);
735         new_module->is_displayed = module->is_displayed;
736 }
737
738 void FRS_delete_module(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
739 {
740         BLI_freelinkN(&config->modules, module_conf);
741 }
742
743 void FRS_move_module_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
744 {
745         BLI_remlink(&config->modules, module_conf);
746         BLI_insertlinkbefore(&config->modules, module_conf->prev, module_conf);
747 }
748
749 void FRS_move_module_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
750 {
751         BLI_remlink(&config->modules, module_conf);
752         BLI_insertlinkafter(&config->modules, module_conf->next, module_conf);
753 }
754
755 static void unique_lineset_name(FreestyleConfig *config, FreestyleLineSet *lineset)
756 {
757         BLI_uniquename(&config->linesets, lineset, "FreestyleLineSet", '.', offsetof(FreestyleLineSet, name),
758                        sizeof(lineset->name));
759 }
760
761 FreestyleLineSet *FRS_alloc_lineset()
762 {
763         return (FreestyleLineSet *)MEM_callocN(sizeof(FreestyleLineSet), "Freestyle line set");
764 }
765
766 FreestyleLineSet *FRS_add_lineset(FreestyleConfig *config)
767 {
768         int lineset_index = BLI_countlist(&config->linesets);
769
770         FreestyleLineSet *lineset = FRS_alloc_lineset();
771         BLI_addtail(&config->linesets, (void *)lineset);
772         FRS_set_active_lineset_index(config, lineset_index);
773
774         lineset->linestyle = FRS_new_linestyle("LineStyle", NULL);
775         lineset->flags |= FREESTYLE_LINESET_ENABLED;
776         lineset->selection = FREESTYLE_SEL_IMAGE_BORDER;
777         lineset->qi = FREESTYLE_QI_VISIBLE;
778         lineset->qi_start = 0;
779         lineset->qi_end = 100;
780         lineset->edge_types = FREESTYLE_FE_SILHOUETTE | FREESTYLE_FE_BORDER | FREESTYLE_FE_CREASE;
781         lineset->exclude_edge_types = 0;
782         lineset->group = NULL;
783         if (lineset_index > 0)
784                 sprintf(lineset->name, "LineSet %i", lineset_index + 1);
785         else
786                 strcpy(lineset->name, "LineSet");
787         unique_lineset_name(config, lineset);
788
789         return lineset;
790 }
791
792 void FRS_copy_active_lineset(FreestyleConfig *config)
793 {
794         FreestyleLineSet *lineset = FRS_get_active_lineset(config);
795
796         if (lineset) {
797                 lineset_buffer.linestyle = lineset->linestyle;
798                 lineset_buffer.flags = lineset->flags;
799                 lineset_buffer.selection = lineset->selection;
800                 lineset_buffer.qi = lineset->qi;
801                 lineset_buffer.qi_start = lineset->qi_start;
802                 lineset_buffer.qi_end = lineset->qi_end;
803                 lineset_buffer.edge_types = lineset->edge_types;
804                 lineset_buffer.exclude_edge_types = lineset->exclude_edge_types;
805                 lineset_buffer.group = lineset->group;
806                 strcpy(lineset_buffer.name, lineset->name);
807                 lineset_copied = true;
808         }
809 }
810
811 void FRS_paste_active_lineset(FreestyleConfig *config)
812 {
813         if (!lineset_copied)
814                 return;
815
816         FreestyleLineSet *lineset = FRS_get_active_lineset(config);
817
818         if (lineset) {
819                 lineset->linestyle->id.us--;
820                 lineset->linestyle = lineset_buffer.linestyle;
821                 lineset->linestyle->id.us++;
822                 lineset->flags = lineset_buffer.flags;
823                 lineset->selection = lineset_buffer.selection;
824                 lineset->qi = lineset_buffer.qi;
825                 lineset->qi_start = lineset_buffer.qi_start;
826                 lineset->qi_end = lineset_buffer.qi_end;
827                 lineset->edge_types = lineset_buffer.edge_types;
828                 lineset->exclude_edge_types = lineset_buffer.exclude_edge_types;
829                 if (lineset->group) {
830                         lineset->group->id.us--;
831                         lineset->group = NULL;
832                 }
833                 if (lineset_buffer.group) {
834                         lineset->group = lineset_buffer.group;
835                         lineset->group->id.us++;
836                 }
837                 strcpy(lineset->name, lineset_buffer.name);
838                 unique_lineset_name(config, lineset);
839                 lineset->flags |= FREESTYLE_LINESET_CURRENT;
840         }
841 }
842
843 void FRS_delete_active_lineset(FreestyleConfig *config)
844 {
845         FreestyleLineSet *lineset = FRS_get_active_lineset(config);
846
847         if (lineset) {
848                 if (lineset->group) {
849                         lineset->group->id.us--;
850                         lineset->group = NULL;
851                 }
852                 lineset->linestyle->id.us--;
853                 lineset->linestyle = NULL;
854                 BLI_remlink(&config->linesets, lineset);
855                 MEM_freeN(lineset);
856                 FRS_set_active_lineset_index(config, 0);
857         }
858 }
859
860 void FRS_move_active_lineset_up(FreestyleConfig *config)
861 {
862         FreestyleLineSet *lineset = FRS_get_active_lineset(config);
863
864         if (lineset) {
865                 BLI_remlink(&config->linesets, lineset);
866                 BLI_insertlinkbefore(&config->linesets, lineset->prev, lineset);
867         }
868 }
869
870 void FRS_move_active_lineset_down(FreestyleConfig *config)
871 {
872         FreestyleLineSet *lineset = FRS_get_active_lineset(config);
873
874         if (lineset) {
875                 BLI_remlink(&config->linesets, lineset);
876                 BLI_insertlinkafter(&config->linesets, lineset->next, lineset);
877         }
878 }
879
880 FreestyleLineSet *FRS_get_active_lineset(FreestyleConfig *config)
881 {
882         FreestyleLineSet *lineset;
883
884         for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
885                 if (lineset->flags & FREESTYLE_LINESET_CURRENT)
886                         return lineset;
887         }
888         return NULL;
889 }
890
891 short FRS_get_active_lineset_index(FreestyleConfig *config)
892 {
893         FreestyleLineSet *lineset;
894         short i;
895
896         for (lineset = (FreestyleLineSet *)config->linesets.first, i = 0; lineset; lineset = lineset->next, i++) {
897                 if (lineset->flags & FREESTYLE_LINESET_CURRENT)
898                         return i;
899         }
900         return 0;
901 }
902
903 void FRS_set_active_lineset_index(FreestyleConfig *config, short index)
904 {
905         FreestyleLineSet *lineset;
906         short i;
907
908         for (lineset = (FreestyleLineSet *)config->linesets.first, i = 0; lineset; lineset = lineset->next, i++) {
909                 if (i == index)
910                         lineset->flags |= FREESTYLE_LINESET_CURRENT;
911                 else
912                         lineset->flags &= ~FREESTYLE_LINESET_CURRENT;
913         }
914 }
915
916 void FRS_unlink_target_object(FreestyleConfig *config, Object *ob)
917 {
918         FreestyleLineSet *lineset;
919
920         for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
921                 FRS_unlink_linestyle_target_object(lineset->linestyle, ob);
922         }
923 }
924
925 #ifdef __cplusplus
926 } // extern "C"
927 #endif