Code clean-up: used copy_m4_m4() and unit_m4() instead of verbose loops.
[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 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 : " << (controller->getComputeSuggestiveContoursFlag() ? "enabled" : "disabled")
450                      << endl;
451                 cout << "Suggestive contour Kr derivative epsilon : " << controller->getSuggestiveContourKrDerivativeEpsilon()
452                      << endl;
453                 cout << "Material boundaries : " << (controller->getComputeMaterialBoundariesFlag() ? "enabled" : "disabled")
454                      << 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         // clear canvas
635         controller->Clear();
636 }
637
638 //=======================================================
639 //   Freestyle Panel Configuration
640 //=======================================================
641
642 void FRS_init_freestyle_config(FreestyleConfig *config)
643 {
644         config->mode = FREESTYLE_CONTROL_SCRIPT_MODE;
645
646         config->modules.first = config->modules.last = NULL;
647         config->flags = 0;
648         config->sphere_radius = DEFAULT_SPHERE_RADIUS;
649         config->dkr_epsilon = DEFAULT_DKR_EPSILON;
650         config->crease_angle = DEG2RADF(120.0f);
651
652         config->linesets.first = config->linesets.last = NULL;
653 }
654
655 void FRS_free_freestyle_config(FreestyleConfig *config)
656 {
657         FreestyleLineSet *lineset;
658
659         for (lineset = (FreestyleLineSet*)config->linesets.first; lineset; lineset = lineset->next) {
660                 if (lineset->group) {
661                         lineset->group->id.us--;
662                         lineset->group = NULL;
663                 }
664                 lineset->linestyle->id.us--;
665                 lineset->linestyle = NULL;
666         }
667         BLI_freelistN(&config->linesets);
668         BLI_freelistN(&config->modules);
669 }
670
671 void FRS_copy_freestyle_config(FreestyleConfig *new_config, FreestyleConfig *config)
672 {
673         FreestyleLineSet *lineset, *new_lineset;
674         FreestyleModuleConfig *module, *new_module;
675
676         new_config->mode = config->mode;
677         new_config->raycasting_algorithm = config->raycasting_algorithm; /* deprecated */
678         new_config->flags = config->flags;
679         new_config->sphere_radius = config->sphere_radius;
680         new_config->dkr_epsilon = config->dkr_epsilon;
681         new_config->crease_angle = config->crease_angle;
682
683         new_config->linesets.first = new_config->linesets.last = NULL;
684         for (lineset = (FreestyleLineSet*)config->linesets.first; lineset; lineset = lineset->next) {
685                 new_lineset = FRS_alloc_lineset();
686                 copy_lineset(new_lineset, lineset);
687                 BLI_addtail(&new_config->linesets, (void*)new_lineset);
688         }
689
690         new_config->modules.first = new_config->modules.last = NULL;
691         for (module = (FreestyleModuleConfig*)config->modules.first; module; module = module->next) {
692                 new_module = FRS_alloc_module();
693                 copy_module(new_module, module);
694                 BLI_addtail(&new_config->modules, (void*)new_module);
695         }
696 }
697
698 static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset)
699 {
700         new_lineset->linestyle = lineset->linestyle;
701         new_lineset->linestyle->id.us++;
702         new_lineset->flags = lineset->flags;
703         new_lineset->selection = lineset->selection;
704         new_lineset->qi = lineset->qi;
705         new_lineset->qi_start = lineset->qi_start;
706         new_lineset->qi_end = lineset->qi_end;
707         new_lineset->edge_types = lineset->edge_types;
708         new_lineset->exclude_edge_types = lineset->exclude_edge_types;
709         new_lineset->group = lineset->group;
710         if (new_lineset->group) {
711                 new_lineset->group->id.us++;
712         }
713         strcpy(new_lineset->name, lineset->name);
714 }
715
716 FreestyleModuleConfig *FRS_alloc_module()
717 {
718         return (FreestyleModuleConfig*)MEM_callocN(sizeof(FreestyleModuleConfig), "style module configuration");
719 }
720
721 void FRS_add_module(FreestyleConfig *config)
722 {
723         FreestyleModuleConfig *module_conf = (FreestyleModuleConfig*)MEM_callocN(sizeof(FreestyleModuleConfig),
724                                                                                  "style module configuration");
725         BLI_addtail(&config->modules, (void*)module_conf);
726
727         strcpy(module_conf->module_path, default_module_path.c_str());
728         module_conf->is_displayed = 1;
729 }
730
731 static void copy_module(FreestyleModuleConfig *new_module, FreestyleModuleConfig *module)
732 {
733         strcpy(new_module->module_path, module->module_path);
734         new_module->is_displayed = module->is_displayed;
735 }
736
737 void FRS_delete_module(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
738 {
739         BLI_freelinkN(&config->modules, module_conf);
740 }
741
742 void FRS_move_module_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
743 {
744         BLI_remlink(&config->modules, module_conf);
745         BLI_insertlinkbefore(&config->modules, module_conf->prev, module_conf);
746 }
747
748 void FRS_move_module_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
749 {
750         BLI_remlink(&config->modules, module_conf);
751         BLI_insertlinkafter(&config->modules, module_conf->next, module_conf);
752 }
753
754 static void unique_lineset_name(FreestyleConfig *config, FreestyleLineSet *lineset)
755 {
756         BLI_uniquename(&config->linesets, lineset, "FreestyleLineSet", '.', offsetof(FreestyleLineSet, name),
757                        sizeof(lineset->name));
758 }
759
760 FreestyleLineSet *FRS_alloc_lineset()
761 {
762         return (FreestyleLineSet*)MEM_callocN(sizeof(FreestyleLineSet), "Freestyle line set");
763 }
764
765 FreestyleLineSet *FRS_add_lineset(FreestyleConfig *config)
766 {
767         int lineset_index = BLI_countlist(&config->linesets);
768
769         FreestyleLineSet *lineset = FRS_alloc_lineset();
770         BLI_addtail(&config->linesets, (void*)lineset);
771         FRS_set_active_lineset_index(config, lineset_index);
772
773         lineset->linestyle = FRS_new_linestyle("LineStyle", NULL);
774         lineset->flags |= FREESTYLE_LINESET_ENABLED;
775         lineset->selection = FREESTYLE_SEL_IMAGE_BORDER;
776         lineset->qi = FREESTYLE_QI_VISIBLE;
777         lineset->qi_start = 0;
778         lineset->qi_end = 100;
779         lineset->edge_types = FREESTYLE_FE_SILHOUETTE | FREESTYLE_FE_BORDER | FREESTYLE_FE_CREASE;
780         lineset->exclude_edge_types = 0;
781         lineset->group = NULL;
782         if (lineset_index > 0)
783                 sprintf(lineset->name, "LineSet %i", lineset_index + 1);
784         else
785                 strcpy(lineset->name, "LineSet");
786         unique_lineset_name(config, lineset);
787
788         return lineset;
789 }
790
791 void FRS_copy_active_lineset(FreestyleConfig *config)
792 {
793         FreestyleLineSet *lineset = FRS_get_active_lineset(config);
794
795         if (lineset) {
796                 lineset_buffer.linestyle = lineset->linestyle;
797                 lineset_buffer.flags = lineset->flags;
798                 lineset_buffer.selection = lineset->selection;
799                 lineset_buffer.qi = lineset->qi;
800                 lineset_buffer.qi_start = lineset->qi_start;
801                 lineset_buffer.qi_end = lineset->qi_end;
802                 lineset_buffer.edge_types = lineset->edge_types;
803                 lineset_buffer.exclude_edge_types = lineset->exclude_edge_types;
804                 lineset_buffer.group = lineset->group;
805                 strcpy(lineset_buffer.name, lineset->name);
806                 lineset_copied = true;
807         }
808 }
809
810 void FRS_paste_active_lineset(FreestyleConfig *config)
811 {
812         if (!lineset_copied)
813                 return;
814
815         FreestyleLineSet *lineset = FRS_get_active_lineset(config);
816
817         if (lineset) {
818                 lineset->linestyle->id.us--;
819                 lineset->linestyle = lineset_buffer.linestyle;
820                 lineset->linestyle->id.us++;
821                 lineset->flags = lineset_buffer.flags;
822                 lineset->selection = lineset_buffer.selection;
823                 lineset->qi = lineset_buffer.qi;
824                 lineset->qi_start = lineset_buffer.qi_start;
825                 lineset->qi_end = lineset_buffer.qi_end;
826                 lineset->edge_types = lineset_buffer.edge_types;
827                 lineset->exclude_edge_types = lineset_buffer.exclude_edge_types;
828                 if (lineset->group) {
829                         lineset->group->id.us--;
830                         lineset->group = NULL;
831                 }
832                 if (lineset_buffer.group) {
833                         lineset->group = lineset_buffer.group;
834                         lineset->group->id.us++;
835                 }
836                 strcpy(lineset->name, lineset_buffer.name);
837                 unique_lineset_name(config, lineset);
838                 lineset->flags |= FREESTYLE_LINESET_CURRENT;
839         }
840 }
841
842 void FRS_delete_active_lineset(FreestyleConfig *config)
843 {
844         FreestyleLineSet *lineset = FRS_get_active_lineset(config);
845
846         if (lineset) {
847                 if (lineset->group) {
848                         lineset->group->id.us--;
849                         lineset->group = NULL;
850                 }
851                 lineset->linestyle->id.us--;
852                 lineset->linestyle = NULL;
853                 BLI_remlink(&config->linesets, lineset);
854                 MEM_freeN(lineset);
855                 FRS_set_active_lineset_index(config, 0);
856         }
857 }
858
859 void FRS_move_active_lineset_up(FreestyleConfig *config)
860 {
861         FreestyleLineSet *lineset = FRS_get_active_lineset(config);
862
863         if (lineset) {
864                 BLI_remlink(&config->linesets, lineset);
865                 BLI_insertlinkbefore(&config->linesets, lineset->prev, lineset);
866         }
867 }
868
869 void FRS_move_active_lineset_down(FreestyleConfig *config)
870 {
871         FreestyleLineSet *lineset = FRS_get_active_lineset(config);
872
873         if (lineset) {
874                 BLI_remlink(&config->linesets, lineset);
875                 BLI_insertlinkafter(&config->linesets, lineset->next, lineset);
876         }
877 }
878
879 FreestyleLineSet *FRS_get_active_lineset(FreestyleConfig *config)
880 {
881         FreestyleLineSet *lineset;
882
883         for (lineset = (FreestyleLineSet*)config->linesets.first; lineset; lineset = lineset->next) {
884                 if (lineset->flags & FREESTYLE_LINESET_CURRENT)
885                         return lineset;
886         }
887         return NULL;
888 }
889
890 short FRS_get_active_lineset_index(FreestyleConfig *config)
891 {
892         FreestyleLineSet *lineset;
893         short i;
894
895         for (lineset = (FreestyleLineSet*)config->linesets.first, i = 0; lineset; lineset = lineset->next, i++) {
896                 if (lineset->flags & FREESTYLE_LINESET_CURRENT)
897                         return i;
898         }
899         return 0;
900 }
901
902 void FRS_set_active_lineset_index(FreestyleConfig *config, short index)
903 {
904         FreestyleLineSet *lineset;
905         short i;
906
907         for (lineset = (FreestyleLineSet*)config->linesets.first, i = 0; lineset; lineset = lineset->next, i++) {
908                 if (i == index)
909                         lineset->flags |= FREESTYLE_LINESET_CURRENT;
910                 else
911                         lineset->flags &= ~FREESTYLE_LINESET_CURRENT;
912         }
913 }
914
915 void FRS_unlink_target_object(FreestyleConfig *config, Object *ob)
916 {
917         FreestyleLineSet *lineset;
918
919         for (lineset = (FreestyleLineSet*)config->linesets.first; lineset; lineset = lineset->next) {
920                 FRS_unlink_linestyle_target_object(lineset->linestyle, ob);
921         }
922 }
923
924 #ifdef __cplusplus
925 } // extern "C"
926 #endif