747 lines
21 KiB
C++
747 lines
21 KiB
C++
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
|
|
* \ingroup freestyle
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <set>
|
|
|
|
#include "../application/AppCanvas.h"
|
|
#include "../application/AppConfig.h"
|
|
#include "../application/AppView.h"
|
|
#include "../application/Controller.h"
|
|
|
|
using namespace std;
|
|
using namespace Freestyle;
|
|
|
|
extern "C" {
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_camera_types.h"
|
|
#include "DNA_freestyle_types.h"
|
|
#include "DNA_group_types.h"
|
|
#include "DNA_text_types.h"
|
|
|
|
#include "BKE_freestyle.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_library.h"
|
|
#include "BKE_linestyle.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_text.h"
|
|
#include "BKE_context.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_math.h"
|
|
#include "BLI_callbacks.h"
|
|
|
|
#include "BPY_extern.h"
|
|
|
|
#include "renderpipeline.h"
|
|
#include "pixelblending.h"
|
|
|
|
#include "FRS_freestyle.h"
|
|
|
|
#define DEFAULT_SPHERE_RADIUS 1.0f
|
|
#define DEFAULT_DKR_EPSILON 0.0f
|
|
|
|
// Freestyle configuration
|
|
static bool freestyle_is_initialized = false;
|
|
static Config::Path *pathconfig = NULL;
|
|
static Controller *controller = NULL;
|
|
static AppView *view = NULL;
|
|
|
|
// line set buffer for copy & paste
|
|
static FreestyleLineSet lineset_buffer;
|
|
static bool lineset_copied = false;
|
|
|
|
// camera information
|
|
float freestyle_viewpoint[3];
|
|
float freestyle_mv[4][4];
|
|
float freestyle_proj[4][4];
|
|
int freestyle_viewport[4];
|
|
|
|
// current scene
|
|
Scene *freestyle_scene;
|
|
|
|
static string default_module_path;
|
|
|
|
static void load_post_callback(struct Main *main, struct ID *id, void *arg)
|
|
{
|
|
lineset_copied = false;
|
|
}
|
|
|
|
static bCallbackFuncStore load_post_callback_funcstore = {
|
|
NULL, NULL, /* next, prev */
|
|
load_post_callback, /* func */
|
|
NULL, /* arg */
|
|
0 /* alloc */
|
|
};
|
|
|
|
//=======================================================
|
|
// Initialization
|
|
//=======================================================
|
|
|
|
void FRS_initialize()
|
|
{
|
|
if (freestyle_is_initialized)
|
|
return;
|
|
|
|
pathconfig = new Config::Path;
|
|
controller = new Controller();
|
|
view = new AppView;
|
|
controller->setView(view);
|
|
controller->Clear();
|
|
freestyle_scene = NULL;
|
|
lineset_copied = false;
|
|
|
|
default_module_path = pathconfig->getProjectDir() + Config::DIR_SEP + "style_modules" +
|
|
Config::DIR_SEP + "contour.py";
|
|
|
|
BLI_callback_add(&load_post_callback_funcstore, BLI_CB_EVT_LOAD_POST);
|
|
|
|
freestyle_is_initialized = 1;
|
|
}
|
|
|
|
void FRS_set_context(bContext *C)
|
|
{
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "FRS_set_context: context 0x" << C << " scene 0x" << CTX_data_scene(C) << endl;
|
|
}
|
|
controller->setContext(C);
|
|
}
|
|
|
|
void FRS_exit()
|
|
{
|
|
delete pathconfig;
|
|
delete controller;
|
|
delete view;
|
|
}
|
|
|
|
//=======================================================
|
|
// Rendering
|
|
//=======================================================
|
|
|
|
static void init_view(Render *re)
|
|
{
|
|
int width = re->winx;
|
|
int height = re->winy;
|
|
int xmin = re->disprect.xmin;
|
|
int ymin = re->disprect.ymin;
|
|
int xmax = re->disprect.xmax;
|
|
int ymax = re->disprect.ymax;
|
|
|
|
float thickness = 1.0f;
|
|
switch (re->r.line_thickness_mode) {
|
|
case R_LINE_THICKNESS_ABSOLUTE:
|
|
thickness = re->r.unit_line_thickness * (re->r.size / 100.f);
|
|
break;
|
|
case R_LINE_THICKNESS_RELATIVE:
|
|
thickness = height / 480.f;
|
|
break;
|
|
}
|
|
|
|
freestyle_viewport[0] = freestyle_viewport[1] = 0;
|
|
freestyle_viewport[2] = width;
|
|
freestyle_viewport[3] = height;
|
|
|
|
view->setWidth(width);
|
|
view->setHeight(height);
|
|
view->setBorder(xmin, ymin, xmax, ymax);
|
|
view->setThickness(thickness);
|
|
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "\n=== Dimensions of the 2D image coordinate system ===" << endl;
|
|
cout << "Width : " << width << endl;
|
|
cout << "Height : " << height << endl;
|
|
if (re->r.mode & R_BORDER)
|
|
cout << "Border : (" << xmin << ", " << ymin << ") - (" << xmax << ", " << ymax << ")" << endl;
|
|
cout << "Unit line thickness : " << thickness << " pixel(s)" << endl;
|
|
}
|
|
}
|
|
|
|
static void init_camera(Render *re)
|
|
{
|
|
// It is assumed that imported meshes are in the camera coordinate system.
|
|
// Therefore, the view point (i.e., camera position) is at the origin, and
|
|
// the the model-view matrix is simply the identity matrix.
|
|
|
|
freestyle_viewpoint[0] = 0.0;
|
|
freestyle_viewpoint[1] = 0.0;
|
|
freestyle_viewpoint[2] = 0.0;
|
|
|
|
unit_m4(freestyle_mv);
|
|
|
|
copy_m4_m4(freestyle_proj, re->winmat);
|
|
|
|
#if 0
|
|
print_m4("mv", freestyle_mv);
|
|
print_m4("proj", freestyle_proj);
|
|
#endif
|
|
}
|
|
|
|
static char *escape_quotes(char *name)
|
|
{
|
|
char *s = (char *)MEM_mallocN(strlen(name) * 2 + 1, "escape_quotes");
|
|
char *p = s;
|
|
while (*name) {
|
|
if (*name == '\'')
|
|
*(p++) = '\\';
|
|
*(p++) = *(name++);
|
|
}
|
|
*p = '\0';
|
|
return s;
|
|
}
|
|
|
|
static Text *create_lineset_handler(Main *bmain, char *layer_name, char *lineset_name)
|
|
{
|
|
char *s1 = escape_quotes(layer_name);
|
|
char *s2 = escape_quotes(lineset_name);
|
|
Text *text = BKE_text_add(bmain, lineset_name);
|
|
BKE_text_write(text, "import parameter_editor; parameter_editor.process('");
|
|
BKE_text_write(text, s1);
|
|
BKE_text_write(text, "', '");
|
|
BKE_text_write(text, s2);
|
|
BKE_text_write(text, "')\n");
|
|
MEM_freeN(s1);
|
|
MEM_freeN(s2);
|
|
return text;
|
|
}
|
|
|
|
struct edge_type_condition
|
|
{
|
|
int edge_type, value;
|
|
};
|
|
|
|
// examines the conditions and returns true if the target edge type needs to be computed
|
|
static bool test_edge_type_conditions(struct edge_type_condition *conditions,
|
|
int num_edge_types, bool logical_and, int target, bool distinct)
|
|
{
|
|
int target_condition = 0;
|
|
int num_non_target_positive_conditions = 0;
|
|
int num_non_target_negative_conditions = 0;
|
|
|
|
for (int i = 0; i < num_edge_types; i++) {
|
|
if (conditions[i].edge_type == target)
|
|
target_condition = conditions[i].value;
|
|
else if (conditions[i].value > 0)
|
|
++num_non_target_positive_conditions;
|
|
else if (conditions[i].value < 0)
|
|
++num_non_target_negative_conditions;
|
|
}
|
|
if (distinct) {
|
|
// In this case, the 'target' edge type is assumed to appear on distinct edge
|
|
// of its own and never together with other edge types.
|
|
if (logical_and) {
|
|
if (num_non_target_positive_conditions > 0)
|
|
return false;
|
|
if (target_condition > 0)
|
|
return true;
|
|
if (target_condition < 0)
|
|
return false;
|
|
if (num_non_target_negative_conditions > 0)
|
|
return true;
|
|
}
|
|
else {
|
|
if (target_condition > 0)
|
|
return true;
|
|
if (num_non_target_negative_conditions > 0)
|
|
return true;
|
|
if (target_condition < 0)
|
|
return false;
|
|
if (num_non_target_positive_conditions > 0)
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
// In this case, the 'target' edge type may appear together with other edge types.
|
|
if (target_condition > 0)
|
|
return true;
|
|
if (target_condition < 0)
|
|
return true;
|
|
if (logical_and) {
|
|
if (num_non_target_positive_conditions > 0)
|
|
return false;
|
|
if (num_non_target_negative_conditions > 0)
|
|
return true;
|
|
}
|
|
else {
|
|
if (num_non_target_negative_conditions > 0)
|
|
return true;
|
|
if (num_non_target_positive_conditions > 0)
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl)
|
|
{
|
|
// load mesh
|
|
re->i.infostr = "Freestyle: Mesh loading";
|
|
re->stats_draw(re->sdh, &re->i);
|
|
re->i.infostr = NULL;
|
|
if (controller->LoadMesh(re, srl)) // returns if scene cannot be loaded or if empty
|
|
return;
|
|
if (re->test_break(re->tbh))
|
|
return;
|
|
|
|
// add style modules
|
|
FreestyleConfig *config = &srl->freestyleConfig;
|
|
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "\n=== Rendering options ===" << endl;
|
|
}
|
|
int layer_count = 0;
|
|
|
|
switch (config->mode) {
|
|
case FREESTYLE_CONTROL_SCRIPT_MODE:
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "Modules :" << endl;
|
|
}
|
|
for (FreestyleModuleConfig *module_conf = (FreestyleModuleConfig *)config->modules.first;
|
|
module_conf;
|
|
module_conf = module_conf->next)
|
|
{
|
|
if (module_conf->script && module_conf->is_displayed) {
|
|
const char *id_name = module_conf->script->id.name + 2;
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << " " << layer_count + 1 << ": " << id_name;
|
|
if (module_conf->script->name)
|
|
cout << " (" << module_conf->script->name << ")";
|
|
cout << endl;
|
|
}
|
|
controller->InsertStyleModule(layer_count, id_name, module_conf->script);
|
|
controller->toggleLayer(layer_count, true);
|
|
layer_count++;
|
|
}
|
|
}
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << endl;
|
|
}
|
|
controller->setComputeRidgesAndValleysFlag((config->flags & FREESTYLE_RIDGES_AND_VALLEYS_FLAG) ? true : false);
|
|
controller->setComputeSuggestiveContoursFlag((config->flags & FREESTYLE_SUGGESTIVE_CONTOURS_FLAG) ? true : false);
|
|
controller->setComputeMaterialBoundariesFlag((config->flags & FREESTYLE_MATERIAL_BOUNDARIES_FLAG) ? true : false);
|
|
break;
|
|
case FREESTYLE_CONTROL_EDITOR_MODE:
|
|
int use_ridges_and_valleys = 0;
|
|
int use_suggestive_contours = 0;
|
|
int use_material_boundaries = 0;
|
|
struct edge_type_condition conditions[] = {
|
|
{FREESTYLE_FE_SILHOUETTE, 0},
|
|
{FREESTYLE_FE_BORDER, 0},
|
|
{FREESTYLE_FE_CREASE, 0},
|
|
{FREESTYLE_FE_RIDGE_VALLEY, 0},
|
|
{FREESTYLE_FE_SUGGESTIVE_CONTOUR, 0},
|
|
{FREESTYLE_FE_MATERIAL_BOUNDARY, 0},
|
|
{FREESTYLE_FE_CONTOUR, 0},
|
|
{FREESTYLE_FE_EXTERNAL_CONTOUR, 0},
|
|
{FREESTYLE_FE_EDGE_MARK, 0}
|
|
};
|
|
int num_edge_types = sizeof(conditions) / sizeof(struct edge_type_condition);
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "Linesets:" << endl;
|
|
}
|
|
for (FreestyleLineSet *lineset = (FreestyleLineSet *)config->linesets.first;
|
|
lineset;
|
|
lineset = lineset->next)
|
|
{
|
|
if (lineset->flags & FREESTYLE_LINESET_ENABLED) {
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << " " << layer_count+1 << ": " << lineset->name << " - " <<
|
|
(lineset->linestyle ? (lineset->linestyle->id.name + 2) : "<NULL>") << endl;
|
|
}
|
|
Text *text = create_lineset_handler(bmain, srl->name, lineset->name);
|
|
controller->InsertStyleModule(layer_count, lineset->name, text);
|
|
controller->toggleLayer(layer_count, true);
|
|
if (!(lineset->selection & FREESTYLE_SEL_EDGE_TYPES) || !lineset->edge_types) {
|
|
++use_ridges_and_valleys;
|
|
++use_suggestive_contours;
|
|
++use_material_boundaries;
|
|
}
|
|
else {
|
|
// conditions for feature edge selection by edge types
|
|
for (int i = 0; i < num_edge_types; i++) {
|
|
if (!(lineset->edge_types & conditions[i].edge_type))
|
|
conditions[i].value = 0; // no condition specified
|
|
else if (!(lineset->exclude_edge_types & conditions[i].edge_type))
|
|
conditions[i].value = 1; // condition: X
|
|
else
|
|
conditions[i].value = -1; // condition: NOT X
|
|
}
|
|
// logical operator for the selection conditions
|
|
bool logical_and = ((lineset->flags & FREESTYLE_LINESET_FE_AND) != 0);
|
|
// negation operator
|
|
if (lineset->flags & FREESTYLE_LINESET_FE_NOT) {
|
|
// convert an Exclusive condition into an Inclusive equivalent using De Morgan's laws:
|
|
// NOT (X OR Y) --> (NOT X) AND (NOT Y)
|
|
// NOT (X AND Y) --> (NOT X) OR (NOT Y)
|
|
for (int i = 0; i < num_edge_types; i++)
|
|
conditions[i].value *= -1;
|
|
logical_and = !logical_and;
|
|
}
|
|
if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
|
|
FREESTYLE_FE_RIDGE_VALLEY, true))
|
|
{
|
|
++use_ridges_and_valleys;
|
|
}
|
|
if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
|
|
FREESTYLE_FE_SUGGESTIVE_CONTOUR, true))
|
|
{
|
|
++use_suggestive_contours;
|
|
}
|
|
if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
|
|
FREESTYLE_FE_MATERIAL_BOUNDARY, true))
|
|
{
|
|
++use_material_boundaries;
|
|
}
|
|
}
|
|
layer_count++;
|
|
}
|
|
}
|
|
controller->setComputeRidgesAndValleysFlag(use_ridges_and_valleys > 0);
|
|
controller->setComputeSuggestiveContoursFlag(use_suggestive_contours > 0);
|
|
controller->setComputeMaterialBoundariesFlag(use_material_boundaries > 0);
|
|
break;
|
|
}
|
|
|
|
// set parameters
|
|
if (config->flags & FREESTYLE_ADVANCED_OPTIONS_FLAG) {
|
|
controller->setSphereRadius(config->sphere_radius);
|
|
controller->setSuggestiveContourKrDerivativeEpsilon(config->dkr_epsilon);
|
|
}
|
|
else {
|
|
controller->setSphereRadius(DEFAULT_SPHERE_RADIUS);
|
|
controller->setSuggestiveContourKrDerivativeEpsilon(DEFAULT_DKR_EPSILON);
|
|
}
|
|
controller->setFaceSmoothness((config->flags & FREESTYLE_FACE_SMOOTHNESS_FLAG) ? true : false);
|
|
controller->setCreaseAngle(RAD2DEGF(config->crease_angle));
|
|
controller->setVisibilityAlgo((config->flags & FREESTYLE_CULLING) ?
|
|
FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE :
|
|
FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE);
|
|
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "Crease angle : " << controller->getCreaseAngle() << endl;
|
|
cout << "Sphere radius : " << controller->getSphereRadius() << endl;
|
|
cout << "Face smoothness : " << (controller->getFaceSmoothness() ? "enabled" : "disabled") << endl;
|
|
cout << "Redges and valleys : " << (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled") <<
|
|
endl;
|
|
cout << "Suggestive contours : " <<
|
|
(controller->getComputeSuggestiveContoursFlag() ? "enabled" : "disabled") << endl;
|
|
cout << "Suggestive contour Kr derivative epsilon : " <<
|
|
controller->getSuggestiveContourKrDerivativeEpsilon() << endl;
|
|
cout << "Material boundaries : " <<
|
|
(controller->getComputeMaterialBoundariesFlag() ? "enabled" : "disabled") << endl;
|
|
cout << endl;
|
|
}
|
|
|
|
// set diffuse and z depth passes
|
|
RenderLayer *rl = RE_GetRenderLayer(re->result, srl->name);
|
|
bool diffuse = false, z = false;
|
|
for (RenderPass *rpass = (RenderPass *)rl->passes.first; rpass; rpass = rpass->next) {
|
|
switch (rpass->passtype) {
|
|
case SCE_PASS_DIFFUSE:
|
|
controller->setPassDiffuse(rpass->rect, rpass->rectx, rpass->recty);
|
|
diffuse = true;
|
|
break;
|
|
case SCE_PASS_Z:
|
|
controller->setPassZ(rpass->rect, rpass->rectx, rpass->recty);
|
|
z = true;
|
|
break;
|
|
}
|
|
}
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "Passes :" << endl;
|
|
cout << " Diffuse = " << (diffuse ? "enabled" : "disabled") << endl;
|
|
cout << " Z = " << (z ? "enabled" : "disabled") << endl;
|
|
}
|
|
|
|
// compute view map
|
|
re->i.infostr = "Freestyle: View map creation";
|
|
re->stats_draw(re->sdh, &re->i);
|
|
re->i.infostr = NULL;
|
|
controller->ComputeViewMap();
|
|
}
|
|
|
|
void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_render)
|
|
{
|
|
RenderLayer *rl;
|
|
float *src, *dest, *pixSrc, *pixDest;
|
|
int x, y, rectx, recty;
|
|
|
|
if (freestyle_render == NULL || freestyle_render->result == NULL)
|
|
return;
|
|
|
|
rl = render_get_active_layer( freestyle_render, freestyle_render->result );
|
|
if (!rl || rl->rectf == NULL) {
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "Cannot find Freestyle result image" << endl;
|
|
}
|
|
return;
|
|
}
|
|
src = rl->rectf;
|
|
#if 0
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "src: " << rl->rectx << " x " << rl->recty << endl;
|
|
}
|
|
#endif
|
|
|
|
rl = RE_GetRenderLayer(re->result, srl->name);
|
|
if (!rl || rl->rectf == NULL) {
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "No layer to composite to" << endl;
|
|
}
|
|
return;
|
|
}
|
|
dest = rl->rectf;
|
|
#if 0
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "dest: " << rl->rectx << " x " << rl->recty << endl;
|
|
}
|
|
#endif
|
|
|
|
rectx = re->rectx;
|
|
recty = re->recty;
|
|
for (y = 0; y < recty; y++) {
|
|
for (x = 0; x < rectx; x++) {
|
|
pixSrc = src + 4 * (rectx * y + x);
|
|
if (pixSrc[3] > 0.0) {
|
|
pixDest = dest + 4 * (rectx * y + x);
|
|
addAlphaOverFloat(pixDest, pixSrc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int displayed_layer_count(SceneRenderLayer *srl)
|
|
{
|
|
int count = 0;
|
|
|
|
switch (srl->freestyleConfig.mode) {
|
|
case FREESTYLE_CONTROL_SCRIPT_MODE:
|
|
for (FreestyleModuleConfig *module = (FreestyleModuleConfig *)srl->freestyleConfig.modules.first;
|
|
module;
|
|
module = module->next)
|
|
{
|
|
if (module->script && module->is_displayed)
|
|
count++;
|
|
}
|
|
break;
|
|
case FREESTYLE_CONTROL_EDITOR_MODE:
|
|
for (FreestyleLineSet *lineset = (FreestyleLineSet *)srl->freestyleConfig.linesets.first;
|
|
lineset;
|
|
lineset = lineset->next)
|
|
{
|
|
if (lineset->flags & FREESTYLE_LINESET_ENABLED)
|
|
count++;
|
|
}
|
|
break;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int FRS_is_freestyle_enabled(SceneRenderLayer *srl)
|
|
{
|
|
return (!(srl->layflag & SCE_LAY_DISABLE) && srl->layflag & SCE_LAY_FRS && displayed_layer_count(srl) > 0);
|
|
}
|
|
|
|
void FRS_init_stroke_rendering(Render *re)
|
|
{
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << endl;
|
|
cout << "#===============================================================" << endl;
|
|
cout << "# Freestyle" << endl;
|
|
cout << "#===============================================================" << endl;
|
|
}
|
|
|
|
init_view(re);
|
|
init_camera(re);
|
|
|
|
controller->ResetRenderCount();
|
|
}
|
|
|
|
Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
|
|
{
|
|
Main bmain = {0};
|
|
Render *freestyle_render = NULL;
|
|
Text *text, *next_text;
|
|
|
|
if (!render)
|
|
return controller->RenderStrokes(re, false);
|
|
|
|
RenderMonitor monitor(re);
|
|
controller->setRenderMonitor(&monitor);
|
|
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << endl;
|
|
cout << "----------------------------------------------------------" << endl;
|
|
cout << "| " << (re->scene->id.name + 2) << "|" << srl->name << endl;
|
|
cout << "----------------------------------------------------------" << endl;
|
|
}
|
|
|
|
// prepare Freestyle:
|
|
// - load mesh
|
|
// - add style modules
|
|
// - set parameters
|
|
// - compute view map
|
|
prepare(&bmain, re, srl);
|
|
|
|
if (re->test_break(re->tbh)) {
|
|
controller->CloseFile();
|
|
if (G.debug & G_DEBUG_FREESTYLE) {
|
|
cout << "Break" << endl;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// render and composite Freestyle result
|
|
if (controller->_ViewMap) {
|
|
// render strokes
|
|
re->i.infostr = "Freestyle: Stroke rendering";
|
|
re->stats_draw(re->sdh, &re->i);
|
|
re->i.infostr = NULL;
|
|
freestyle_scene = re->scene;
|
|
controller->DrawStrokes();
|
|
freestyle_render = controller->RenderStrokes(re, true);
|
|
controller->CloseFile();
|
|
freestyle_scene = NULL;
|
|
|
|
// composite result
|
|
FRS_composite_result(re, srl, freestyle_render);
|
|
RE_FreeRenderResult(freestyle_render->result);
|
|
freestyle_render->result = NULL;
|
|
}
|
|
|
|
// Free temp main (currently only text blocks are stored there)
|
|
for (text = (Text *) bmain.text.first; text; text = next_text) {
|
|
next_text = (Text *) text->id.next;
|
|
|
|
BKE_text_unlink(&bmain, text);
|
|
BKE_libblock_free(&bmain, text);
|
|
}
|
|
|
|
return freestyle_render;
|
|
}
|
|
|
|
void FRS_finish_stroke_rendering(Render *re)
|
|
{
|
|
// clear canvas
|
|
controller->Clear();
|
|
}
|
|
|
|
//=======================================================
|
|
// Freestyle Panel Configuration
|
|
//=======================================================
|
|
|
|
void FRS_copy_active_lineset(FreestyleConfig *config)
|
|
{
|
|
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
|
|
|
|
if (lineset) {
|
|
lineset_buffer.linestyle = lineset->linestyle;
|
|
lineset_buffer.flags = lineset->flags;
|
|
lineset_buffer.selection = lineset->selection;
|
|
lineset_buffer.qi = lineset->qi;
|
|
lineset_buffer.qi_start = lineset->qi_start;
|
|
lineset_buffer.qi_end = lineset->qi_end;
|
|
lineset_buffer.edge_types = lineset->edge_types;
|
|
lineset_buffer.exclude_edge_types = lineset->exclude_edge_types;
|
|
lineset_buffer.group = lineset->group;
|
|
strcpy(lineset_buffer.name, lineset->name);
|
|
lineset_copied = true;
|
|
}
|
|
}
|
|
|
|
void FRS_paste_active_lineset(FreestyleConfig *config)
|
|
{
|
|
if (!lineset_copied)
|
|
return;
|
|
|
|
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
|
|
|
|
if (lineset) {
|
|
if (lineset->linestyle)
|
|
lineset->linestyle->id.us--;
|
|
lineset->linestyle = lineset_buffer.linestyle;
|
|
if (lineset->linestyle)
|
|
lineset->linestyle->id.us++;
|
|
lineset->flags = lineset_buffer.flags;
|
|
lineset->selection = lineset_buffer.selection;
|
|
lineset->qi = lineset_buffer.qi;
|
|
lineset->qi_start = lineset_buffer.qi_start;
|
|
lineset->qi_end = lineset_buffer.qi_end;
|
|
lineset->edge_types = lineset_buffer.edge_types;
|
|
lineset->exclude_edge_types = lineset_buffer.exclude_edge_types;
|
|
if (lineset->group) {
|
|
lineset->group->id.us--;
|
|
lineset->group = NULL;
|
|
}
|
|
if (lineset_buffer.group) {
|
|
lineset->group = lineset_buffer.group;
|
|
lineset->group->id.us++;
|
|
}
|
|
strcpy(lineset->name, lineset_buffer.name);
|
|
BKE_freestyle_lineset_unique_name(config, lineset);
|
|
lineset->flags |= FREESTYLE_LINESET_CURRENT;
|
|
}
|
|
}
|
|
|
|
void FRS_delete_active_lineset(FreestyleConfig *config)
|
|
{
|
|
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
|
|
|
|
if (lineset) {
|
|
if (lineset->group) {
|
|
lineset->group->id.us--;
|
|
}
|
|
if (lineset->linestyle) {
|
|
lineset->linestyle->id.us--;
|
|
}
|
|
BLI_remlink(&config->linesets, lineset);
|
|
MEM_freeN(lineset);
|
|
BKE_freestyle_lineset_set_active_index(config, 0);
|
|
}
|
|
}
|
|
|
|
void FRS_move_active_lineset_up(FreestyleConfig *config)
|
|
{
|
|
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
|
|
|
|
if (lineset) {
|
|
BLI_remlink(&config->linesets, lineset);
|
|
BLI_insertlinkbefore(&config->linesets, lineset->prev, lineset);
|
|
}
|
|
}
|
|
|
|
void FRS_move_active_lineset_down(FreestyleConfig *config)
|
|
{
|
|
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
|
|
|
|
if (lineset) {
|
|
BLI_remlink(&config->linesets, lineset);
|
|
BLI_insertlinkafter(&config->linesets, lineset->next, lineset);
|
|
}
|
|
}
|
|
|
|
} // extern "C"
|