Blender V4.3
BlenderStrokeRenderer.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
12#include "../stroke/Canvas.h"
13
14#include "MEM_guardedalloc.h"
15
16#include "RNA_access.hh"
17#include "RNA_prototypes.hh"
18#include "RNA_types.hh"
19
20#include "DNA_camera_types.h"
22#include "DNA_linestyle_types.h"
23#include "DNA_listBase.h"
24#include "DNA_material_types.h"
25#include "DNA_mesh_types.h"
26#include "DNA_meshdata_types.h"
27#include "DNA_object_types.h"
28#include "DNA_scene_types.h"
29#include "DNA_screen_types.h"
30
31#include "BKE_attribute.hh"
32#include "BKE_collection.hh"
33#include "BKE_customdata.hh"
34#include "BKE_global.hh"
35#include "BKE_idprop.hh"
36#include "BKE_layer.hh"
37#include "BKE_lib_id.hh" /* free_libblock */
38#include "BKE_main.hh"
39#include "BKE_material.h"
40#include "BKE_mesh.hh"
41#include "BKE_node.hh"
43#include "BKE_object.hh"
44#include "BKE_scene.hh"
45
46#include "BLI_ghash.h"
47#include "BLI_listbase.h"
48#include "BLI_math_color.h"
49#include "BLI_math_vector.h"
51#include "BLI_utildefines.h"
52
53#include "DEG_depsgraph.hh"
55
56#include "RE_pipeline.h"
57
58#include "render_types.h"
59
60#include <climits>
61
62using blender::float3;
63
64namespace Freestyle {
65
66const char *BlenderStrokeRenderer::uvNames[] = {"along_stroke", "along_stroke_tips"};
67
69{
71
72 /* We use the same window manager for freestyle bmain as
73 * real bmain uses. This is needed because freestyle's
74 * bmain could be used to tag scenes for update, which
75 * implies call of ED_render_scene_update in some cases
76 * and that function requires proper window manager
77 * to present (sergey)
78 */
79 freestyle_bmain->wm = re->main->wm;
80
81 // for stroke mesh generation
82 _width = re->winx;
83 _height = re->winy;
84
85 old_scene = re->scene;
86
87 char name[MAX_ID_NAME - 2];
88 SNPRINTF(name, "FRS%d_%s", render_count, re->scene->id.name + 2);
92 freestyle_scene->r.xsch = re->rectx; // old_scene->r.xsch
93 freestyle_scene->r.ysch = re->recty; // old_scene->r.ysch
94 freestyle_scene->r.xasp = 1.0f; // old_scene->r.xasp;
95 freestyle_scene->r.yasp = 1.0f; // old_scene->r.yasp;
96 freestyle_scene->r.size = 100; // old_scene->r.size
97 freestyle_scene->r.color_mgt_flag = 0; // old_scene->r.color_mgt_flag;
100 (re->r.scemode);
110 if (G.debug & G_DEBUG_FREESTYLE) {
111 cout << "Stroke rendering engine : " << freestyle_scene->r.engine << endl;
112 }
115
116 // Copy ID properties, including Cycles render properties
117 if (old_scene->id.properties) {
119 }
120 // Copy eevee render settings.
122
123 /* Render with transparent background. */
125
126 if (G.debug & G_DEBUG_FREESTYLE) {
127 printf("%s: %d thread(s)\n", __func__, BKE_render_num_threads(&freestyle_scene->r));
128 }
129
131
132 // Scene layer.
134 view_layer->layflag = SCE_LAY_SOLID;
135
136 // Camera
137 Object *object_camera = BKE_object_add(
138 freestyle_bmain, freestyle_scene, view_layer, OB_CAMERA, nullptr);
139
140 Camera *camera = (Camera *)object_camera->data;
141 camera->type = CAM_ORTHO;
142 camera->ortho_scale = max(re->rectx, re->recty);
143 camera->clip_start = 0.1f;
144 camera->clip_end = 100.0f;
145
146 _z_delta = 0.00001f;
147 _z = camera->clip_start + _z_delta;
148
149 object_camera->loc[0] = re->disprect.xmin + 0.5f * re->rectx;
150 object_camera->loc[1] = re->disprect.ymin + 0.5f * re->recty;
151 object_camera->loc[2] = 1.0f;
152
153 freestyle_scene->camera = object_camera;
154
155 // Reset serial mesh ID (used for BlenderStrokeRenderer::NewMesh())
156 _mesh_id = 0xffffffff;
157
158 // Create a bNodeTree-to-Material hash table
159 _nodetree_hash = BLI_ghash_ptr_new("BlenderStrokeRenderer::_nodetree_hash");
160
161 // Depsgraph
167}
168
170{
171 BLI_ghash_free(_nodetree_hash, nullptr, nullptr);
172
174
176
177 /* detach the window manager from freestyle bmain (see comments
178 * in add_freestyle() for more detail)
179 */
181
183}
184
186{
187 float z = _z;
188 BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this);
189 if (!(_z < _z_delta * 100000.0f)) {
190 self->_z_delta *= 10.0f;
191 }
192 self->_z += _z_delta;
193 return -z;
194}
195
197{
198 uint mesh_id = _mesh_id;
199 BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this);
200 self->_mesh_id--;
201 return mesh_id;
202}
203
205 bNodeTree *iNodeTree,
206 bool do_id_user)
207{
208 Material *ma = BKE_material_add(bmain, "stroke_shader");
209 bNodeTree *ntree;
210 bNode *output_linestyle = nullptr;
211 bNodeSocket *fromsock, *tosock;
212 PointerRNA fromptr, toptr;
213 NodeShaderAttribute *storage;
214
215 id_us_min(&ma->id);
216
217 if (iNodeTree) {
218 // make a copy of linestyle->nodetree
219 ntree = blender::bke::node_tree_copy_tree_ex(iNodeTree, bmain, do_id_user);
220
221 // find the active Output Line Style node
222 LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
223 if (node->type == SH_NODE_OUTPUT_LINESTYLE && (node->flag & NODE_DO_OUTPUT)) {
224 output_linestyle = node;
225 break;
226 }
227 }
228 ma->nodetree = ntree;
229 }
230 else {
232 nullptr, &ma->id, "stroke_shader", "ShaderNodeTree");
233 }
234 ma->use_nodes = true;
236
237 bNode *input_attr_color = blender::bke::node_add_static_node(nullptr, ntree, SH_NODE_ATTRIBUTE);
238 input_attr_color->locx = 0.0f;
239 input_attr_color->locy = -200.0f;
240 storage = (NodeShaderAttribute *)input_attr_color->storage;
241 STRNCPY(storage->name, "Color");
242
244 nullptr, ntree, SH_NODE_MIX_RGB_LEGACY);
245 mix_rgb_color->custom1 = MA_RAMP_BLEND; // Mix
246 mix_rgb_color->locx = 200.0f;
247 mix_rgb_color->locy = -200.0f;
248 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 0); // Fac
249 toptr = RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock);
250 RNA_float_set(&toptr, "default_value", 0.0f);
251
252 bNode *input_attr_alpha = blender::bke::node_add_static_node(nullptr, ntree, SH_NODE_ATTRIBUTE);
253 input_attr_alpha->locx = 400.0f;
254 input_attr_alpha->locy = 300.0f;
255 storage = (NodeShaderAttribute *)input_attr_alpha->storage;
256 STRNCPY(storage->name, "Alpha");
257
259 nullptr, ntree, SH_NODE_MIX_RGB_LEGACY);
260 mix_rgb_alpha->custom1 = MA_RAMP_BLEND; // Mix
261 mix_rgb_alpha->locx = 600.0f;
262 mix_rgb_alpha->locy = 300.0f;
263 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 0); // Fac
264 toptr = RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock);
265 RNA_float_set(&toptr, "default_value", 0.0f);
266
267 bNode *shader_emission = blender::bke::node_add_static_node(nullptr, ntree, SH_NODE_EMISSION);
268 shader_emission->locx = 400.0f;
269 shader_emission->locy = -200.0f;
270
271 bNode *input_light_path = blender::bke::node_add_static_node(nullptr, ntree, SH_NODE_LIGHT_PATH);
272 input_light_path->locx = 400.0f;
273 input_light_path->locy = 100.0f;
274
275 bNode *mix_shader_color = blender::bke::node_add_static_node(nullptr, ntree, SH_NODE_MIX_SHADER);
276 mix_shader_color->locx = 600.0f;
277 mix_shader_color->locy = -100.0f;
278
279 bNode *shader_transparent = blender::bke::node_add_static_node(
280 nullptr, ntree, SH_NODE_BSDF_TRANSPARENT);
281 shader_transparent->locx = 600.0f;
282 shader_transparent->locy = 100.0f;
283
284 bNode *mix_shader_alpha = blender::bke::node_add_static_node(nullptr, ntree, SH_NODE_MIX_SHADER);
285 mix_shader_alpha->locx = 800.0f;
286 mix_shader_alpha->locy = 100.0f;
287
288 bNode *output_material = blender::bke::node_add_static_node(
289 nullptr, ntree, SH_NODE_OUTPUT_MATERIAL);
290 output_material->locx = 1000.0f;
291 output_material->locy = 100.0f;
292
293 fromsock = (bNodeSocket *)BLI_findlink(&input_attr_color->outputs, 0); // Color
294 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 1); // Color1
295 blender::bke::node_add_link(ntree, input_attr_color, fromsock, mix_rgb_color, tosock);
296
297 fromsock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->outputs, 0); // Color
298 tosock = (bNodeSocket *)BLI_findlink(&shader_emission->inputs, 0); // Color
299 blender::bke::node_add_link(ntree, mix_rgb_color, fromsock, shader_emission, tosock);
300
301 fromsock = (bNodeSocket *)BLI_findlink(&shader_emission->outputs, 0); // Emission
302 tosock = (bNodeSocket *)BLI_findlink(&mix_shader_color->inputs, 2); // Shader (second)
303 blender::bke::node_add_link(ntree, shader_emission, fromsock, mix_shader_color, tosock);
304
305 fromsock = (bNodeSocket *)BLI_findlink(&input_light_path->outputs, 0); // In Camera Ray
306 tosock = (bNodeSocket *)BLI_findlink(&mix_shader_color->inputs, 0); // Fac
307 blender::bke::node_add_link(ntree, input_light_path, fromsock, mix_shader_color, tosock);
308
309 fromsock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->outputs, 0); // Color
310 tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 0); // Fac
311 blender::bke::node_add_link(ntree, mix_rgb_alpha, fromsock, mix_shader_alpha, tosock);
312
313 fromsock = (bNodeSocket *)BLI_findlink(&input_attr_alpha->outputs, 0); // Color
314 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 1); // Color1
315 blender::bke::node_add_link(ntree, input_attr_alpha, fromsock, mix_rgb_alpha, tosock);
316
317 fromsock = (bNodeSocket *)BLI_findlink(&shader_transparent->outputs, 0); // BSDF
318 tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 1); // Shader (first)
319 blender::bke::node_add_link(ntree, shader_transparent, fromsock, mix_shader_alpha, tosock);
320
321 fromsock = (bNodeSocket *)BLI_findlink(&mix_shader_color->outputs, 0); // Shader
322 tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 2); // Shader (second)
323 blender::bke::node_add_link(ntree, mix_shader_color, fromsock, mix_shader_alpha, tosock);
324
325 fromsock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->outputs, 0); // Shader
326 tosock = (bNodeSocket *)BLI_findlink(&output_material->inputs, 0); // Surface
327 blender::bke::node_add_link(ntree, mix_shader_alpha, fromsock, output_material, tosock);
328
329 if (output_linestyle) {
330 bNodeSocket *outsock;
331 bNodeLink *link;
332
333 mix_rgb_color->custom1 = output_linestyle->custom1; // blend_type
334 mix_rgb_color->custom2 = output_linestyle->custom2; // use_clamp
335
336 outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 0); // Color
337 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 2); // Color2
338 link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
339 if (link) {
340 blender::bke::node_add_link(ntree, link->fromnode, link->fromsock, mix_rgb_color, tosock);
341 }
342 else {
343 float color[4];
344 fromptr = RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock);
345 toptr = RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock);
346 RNA_float_get_array(&fromptr, "default_value", color);
347 RNA_float_set_array(&toptr, "default_value", color);
348 }
349
350 outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 1); // Color Fac
351 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 0); // Fac
352 link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
353 if (link) {
354 blender::bke::node_add_link(ntree, link->fromnode, link->fromsock, mix_rgb_color, tosock);
355 }
356 else {
357 fromptr = RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock);
358 toptr = RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock);
359 RNA_float_set(&toptr, "default_value", RNA_float_get(&fromptr, "default_value"));
360 }
361
362 outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 2); // Alpha
363 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 2); // Color2
364 link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
365 if (link) {
366 blender::bke::node_add_link(ntree, link->fromnode, link->fromsock, mix_rgb_alpha, tosock);
367 }
368 else {
369 float color[4];
370 fromptr = RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock);
371 toptr = RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock);
372 color[0] = color[1] = color[2] = RNA_float_get(&fromptr, "default_value");
373 color[3] = 1.0f;
374 RNA_float_set_array(&toptr, "default_value", color);
375 }
376
377 outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 3); // Alpha Fac
378 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 0); // Fac
379 link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
380 if (link) {
381 blender::bke::node_add_link(ntree, link->fromnode, link->fromsock, mix_rgb_alpha, tosock);
382 }
383 else {
384 fromptr = RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock);
385 toptr = RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock);
386 RNA_float_set(&toptr, "default_value", RNA_float_get(&fromptr, "default_value"));
387 }
388
389 LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
390 if (node->type == SH_NODE_UVALONGSTROKE) {
391 // UV output of the UV Along Stroke node
392 bNodeSocket *sock = (bNodeSocket *)BLI_findlink(&node->outputs, 0);
393
394 // add new UV Map node
395 bNode *input_uvmap = blender::bke::node_add_static_node(nullptr, ntree, SH_NODE_UVMAP);
396 input_uvmap->locx = node->locx - 200.0f;
397 input_uvmap->locy = node->locy;
398 NodeShaderUVMap *storage = (NodeShaderUVMap *)input_uvmap->storage;
399 if (node->custom1 & 1) { // use_tips
400 STRNCPY(storage->uv_map, uvNames[1]);
401 }
402 else {
403 STRNCPY(storage->uv_map, uvNames[0]);
404 }
405 fromsock = (bNodeSocket *)BLI_findlink(&input_uvmap->outputs, 0); // UV
406
407 // replace links from the UV Along Stroke node by links from the UV Map node
408 LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
409 if (link->fromnode == node && link->fromsock == sock) {
410 blender::bke::node_add_link(ntree, input_uvmap, fromsock, link->tonode, link->tosock);
411 }
412 }
414 }
415 }
416 }
417
418 blender::bke::node_set_active(ntree, output_material);
419 BKE_ntree_update_main_tree(bmain, ntree, nullptr);
420
421 return ma;
422}
423
425{
426 RenderStrokeRepBasic(iStrokeRep);
427}
428
430{
431 bNodeTree *nt = iStrokeRep->getNodeTree();
433 if (!ma) {
436 }
437 iStrokeRep->setMaterial(ma);
438
439 const vector<Strip *> &strips = iStrokeRep->getStrips();
440 const bool hasTex = iStrokeRep->hasTex();
441 int totvert = 0, totedge = 0, faces_num = 0, totloop = 0;
442 int visible_faces, visible_segments;
443 for (vector<Strip *>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
444 Strip::vertex_container &strip_vertices = (*s)->vertices();
445
446 // count visible faces and strip segments
447 test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
448 if (visible_faces == 0) {
449 continue;
450 }
451
452 totvert += visible_faces + visible_segments * 2;
453 totedge += visible_faces * 2 + visible_segments;
454 faces_num += visible_faces;
455 totloop += visible_faces * 3;
456 }
457
458 BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this); // FIXME
459 vector<StrokeGroup *> *groups = hasTex ? &self->texturedStrokeGroups : &self->strokeGroups;
460 StrokeGroup *group;
461 if (groups->empty() || !(groups->back()->totvert + totvert < MESH_MAX_VERTS &&
462 groups->back()->materials.size() + 1 < MAXMAT))
463 {
464 group = new StrokeGroup;
465 groups->push_back(group);
466 }
467 else {
468 group = groups->back();
469 }
470 group->strokes.push_back(iStrokeRep);
471 group->totvert += totvert;
472 group->totedge += totedge;
473 group->faces_num += faces_num;
474 group->totloop += totloop;
475
476 if (!group->materials.contains(ma)) {
477 group->materials.add_new(ma, group->materials.size());
478 }
479}
480
481// Check if the triangle is visible (i.e., within the render image boundary)
483{
484 int xl, xu, yl, yu;
485 Vec2r p;
486
487 xl = xu = yl = yu = 0;
488 for (int i = 0; i < 3; i++) {
489 p = svRep[i]->point2d();
490 if (p[0] < 0.0) {
491 xl++;
492 }
493 else if (p[0] > _width) {
494 xu++;
495 }
496 if (p[1] < 0.0) {
497 yl++;
498 }
499 else if (p[1] > _height) {
500 yu++;
501 }
502 }
503 return !(xl == 3 || xu == 3 || yl == 3 || yu == 3);
504}
505
506// Check the visibility of faces and strip segments.
507void BlenderStrokeRenderer::test_strip_visibility(Strip::vertex_container &strip_vertices,
508 int *visible_faces,
509 int *visible_segments) const
510{
511 const int strip_vertex_count = strip_vertices.size();
512 Strip::vertex_container::iterator v[3];
513 StrokeVertexRep *svRep[3];
514 bool visible;
515
516 /* Iterate over all vertices and count visible faces and strip segments
517 * (NOTE: a strip segment is a series of visible faces, while two strip
518 * segments are separated by one or more invisible faces). */
519 v[0] = strip_vertices.begin();
520 v[1] = v[0] + 1;
521 v[2] = v[0] + 2;
522 *visible_faces = *visible_segments = 0;
523 visible = false;
524 for (int n = 2; n < strip_vertex_count; n++, v[0]++, v[1]++, v[2]++) {
525 svRep[0] = *(v[0]);
526 svRep[1] = *(v[1]);
527 svRep[2] = *(v[2]);
528 if (test_triangle_visibility(svRep)) {
529 (*visible_faces)++;
530 if (!visible) {
531 (*visible_segments)++;
532 }
533 visible = true;
534 }
535 else {
536 visible = false;
537 }
538 }
539}
540
541// Release allocated memory for stroke groups
543{
544 vector<StrokeGroup *>::const_iterator it, itend;
545
546 for (it = strokeGroups.begin(), itend = strokeGroups.end(); it != itend; ++it) {
547 delete (*it);
548 }
549 for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end(); it != itend; ++it) {
550 delete (*it);
551 }
552}
553
554// Build a scene populated by mesh objects representing stylized strokes
556{
557 vector<StrokeGroup *>::const_iterator it, itend;
558
559 for (it = strokeGroups.begin(), itend = strokeGroups.end(); it != itend; ++it) {
560 GenerateStrokeMesh(*it, false);
561 }
562 for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end(); it != itend; ++it) {
563 GenerateStrokeMesh(*it, true);
564 }
565 return get_stroke_count();
566}
567
568// Return the number of strokes
570{
571 return strokeGroups.size() + texturedStrokeGroups.size();
572}
573
574// Build a mesh object representing a group of stylized strokes
576{
577#if 0
578 Object *object_mesh = BKE_object_add(
581#else
582 Object *object_mesh = NewMesh();
583#endif
584 Mesh *mesh = (Mesh *)object_mesh->data;
585
586 mesh->verts_num = group->totvert;
587 mesh->edges_num = group->totedge;
588 mesh->faces_num = group->faces_num;
589 mesh->corners_num = group->totloop;
590 mesh->totcol = group->materials.size();
592
593 float3 *vert_positions = (float3 *)CustomData_add_layer_named(
594 &mesh->vert_data, CD_PROP_FLOAT3, CD_SET_DEFAULT, mesh->verts_num, "position");
596 &mesh->edge_data, CD_PROP_INT32_2D, CD_CONSTRUCT, mesh->edges_num, ".edge_verts");
597 blender::MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
598 int *corner_verts = (int *)CustomData_add_layer_named(
599 &mesh->corner_data, CD_PROP_INT32, CD_SET_DEFAULT, mesh->corners_num, ".corner_vert");
600 int *corner_edges = (int *)CustomData_add_layer_named(
601 &mesh->corner_data, CD_PROP_INT32, CD_SET_DEFAULT, mesh->corners_num, ".corner_edge");
602 int *material_indices = (int *)CustomData_add_layer_named(
603 &mesh->face_data, CD_PROP_INT32, CD_SET_DEFAULT, mesh->faces_num, "material_index");
604 blender::float2 *loopsuv[2] = {nullptr};
605
606 if (hasTex) {
607 // First UV layer
608 loopsuv[0] = static_cast<blender::float2 *>(CustomData_add_layer_named(
609 &mesh->corner_data, CD_PROP_FLOAT2, CD_SET_DEFAULT, mesh->corners_num, uvNames[0]));
610 CustomData_set_layer_active(&mesh->corner_data, CD_PROP_FLOAT2, 0);
611
612 // Second UV layer
613 loopsuv[1] = static_cast<blender::float2 *>(CustomData_add_layer_named(
614 &mesh->corner_data, CD_PROP_FLOAT2, CD_SET_DEFAULT, mesh->corners_num, uvNames[1]));
615 CustomData_set_layer_active(&mesh->corner_data, CD_PROP_FLOAT2, 1);
616 }
617
618 // colors and transparency (the latter represented by grayscale colors)
620 &mesh->corner_data, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, mesh->corners_num, "Color");
622 &mesh->corner_data, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, mesh->corners_num, "Alpha");
624 &mesh->id, CustomData_get_layer_name(&mesh->corner_data, CD_PROP_BYTE_COLOR, 0));
625
626 mesh->mat = (Material **)MEM_mallocN(sizeof(Material *) * mesh->totcol, "MaterialList");
627 for (const auto item : group->materials.items()) {
628 Material *material = item.key;
629 const int matnr = item.value;
630 mesh->mat[matnr] = material;
631 if (material) {
632 id_us_plus(&material->id);
633 }
634 }
635
637 // Data copy
639
640 int vertex_index = 0, edge_index = 0, loop_index = 0, face_index = 0;
641 int visible_faces, visible_segments;
642 bool visible;
643 Strip::vertex_container::iterator v[3];
644 StrokeVertexRep *svRep[3];
645 Vec2r p;
646
647 for (vector<StrokeRep *>::const_iterator it = group->strokes.begin(),
648 itend = group->strokes.end();
649 it != itend;
650 ++it)
651 {
652 const int matnr = group->materials.lookup_default((*it)->getMaterial(), 0);
653
654 vector<Strip *> &strips = (*it)->getStrips();
655 for (vector<Strip *>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
656 Strip::vertex_container &strip_vertices = (*s)->vertices();
657 int strip_vertex_count = strip_vertices.size();
658
659 // count visible faces and strip segments
660 test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
661 if (visible_faces == 0) {
662 continue;
663 }
664
665 v[0] = strip_vertices.begin();
666 v[1] = v[0] + 1;
667 v[2] = v[0] + 2;
668
669 visible = false;
670
671 // NOTE: Mesh generation in the following loop assumes stroke strips
672 // to be triangle strips.
673 for (int n = 2; n < strip_vertex_count; n++, v[0]++, v[1]++, v[2]++) {
674 svRep[0] = *(v[0]);
675 svRep[1] = *(v[1]);
676 svRep[2] = *(v[2]);
677 if (!test_triangle_visibility(svRep)) {
678 visible = false;
679 }
680 else {
681 if (!visible) {
682 // first vertex
683 vert_positions[vertex_index][0] = svRep[0]->point2d()[0];
684 vert_positions[vertex_index][1] = svRep[0]->point2d()[1];
685 vert_positions[vertex_index][2] = get_stroke_vertex_z();
686
687 ++vertex_index;
688
689 // second vertex
690 vert_positions[vertex_index][0] = svRep[1]->point2d()[0];
691 vert_positions[vertex_index][1] = svRep[1]->point2d()[1];
692 vert_positions[vertex_index][2] = get_stroke_vertex_z();
693
694 ++vertex_index;
695
696 // first edge
697 edges[edge_index][0] = vertex_index - 2;
698 edges[edge_index][1] = vertex_index - 1;
699 ++edge_index;
700 }
701 visible = true;
702
703 // vertex
704 vert_positions[vertex_index][0] = svRep[2]->point2d()[0];
705 vert_positions[vertex_index][1] = svRep[2]->point2d()[1];
706 vert_positions[vertex_index][2] = get_stroke_vertex_z();
707 ++vertex_index;
708
709 // edges
710 edges[edge_index][0] = vertex_index - 1;
711 edges[edge_index][1] = vertex_index - 3;
712 ++edge_index;
713
714 edges[edge_index][0] = vertex_index - 1;
715 edges[edge_index][1] = vertex_index - 2;
716 ++edge_index;
717
718 // poly
719 face_offsets[face_index] = loop_index;
720 *material_indices = matnr;
721 ++material_indices;
722 ++face_index;
723
724 // Even and odd loops connect triangles vertices differently
725 bool is_odd = n % 2;
726 // loops
727 if (is_odd) {
728 corner_verts[0] = vertex_index - 1;
729 corner_edges[0] = edge_index - 2;
730
731 corner_verts[1] = vertex_index - 3;
732 corner_edges[1] = edge_index - 3;
733
734 corner_verts[2] = vertex_index - 2;
735 corner_edges[2] = edge_index - 1;
736 }
737 else {
738 corner_verts[0] = vertex_index - 1;
739 corner_edges[0] = edge_index - 1;
740
741 corner_verts[1] = vertex_index - 2;
742 corner_edges[1] = edge_index - 3;
743
744 corner_verts[2] = vertex_index - 3;
745 corner_edges[2] = edge_index - 2;
746 }
747 corner_verts += 3;
748 corner_edges += 3;
749 loop_index += 3;
750
751 // UV
752 if (hasTex) {
753 // First UV layer (loopsuv[0]) has no tips (texCoord(0)).
754 // Second UV layer (loopsuv[1]) has tips: (texCoord(1)).
755 for (int L = 0; L < 2; L++) {
756 if (is_odd) {
757 loopsuv[L][0][0] = svRep[2]->texCoord(L).x();
758 loopsuv[L][0][1] = svRep[2]->texCoord(L).y();
759
760 loopsuv[L][1][0] = svRep[0]->texCoord(L).x();
761 loopsuv[L][1][1] = svRep[0]->texCoord(L).y();
762
763 loopsuv[L][2][0] = svRep[1]->texCoord(L).x();
764 loopsuv[L][2][1] = svRep[1]->texCoord(L).y();
765 }
766 else {
767 loopsuv[L][0][0] = svRep[2]->texCoord(L).x();
768 loopsuv[L][0][1] = svRep[2]->texCoord(L).y();
769
770 loopsuv[L][1][0] = svRep[1]->texCoord(L).x();
771 loopsuv[L][1][1] = svRep[1]->texCoord(L).y();
772
773 loopsuv[L][2][0] = svRep[0]->texCoord(L).x();
774 loopsuv[L][2][1] = svRep[0]->texCoord(L).y();
775 }
776 loopsuv[L] += 3;
777 }
778 }
779
780 // colors and alpha transparency. vertex colors are in sRGB
781 // space by convention, so convert from linear
782 float rgba[3][4];
783
784 for (int i = 0; i < 3; i++) {
785 copy_v3fl_v3db(rgba[i], &svRep[i]->color()[0]);
786 rgba[i][3] = svRep[i]->alpha();
787 }
788
789 if (is_odd) {
790 linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]);
791 linearrgb_to_srgb_uchar4(&colors[1].r, rgba[0]);
792 linearrgb_to_srgb_uchar4(&colors[2].r, rgba[1]);
793 }
794 else {
795 linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]);
796 linearrgb_to_srgb_uchar4(&colors[1].r, rgba[1]);
797 linearrgb_to_srgb_uchar4(&colors[2].r, rgba[0]);
798 }
799 transp[0].r = transp[0].g = transp[0].b = colors[0].a;
800 transp[1].r = transp[1].g = transp[1].b = colors[1].a;
801 transp[2].r = transp[2].g = transp[2].b = colors[2].a;
802 colors += 3;
803 transp += 3;
804 }
805 } // loop over strip vertices
806 } // loop over strips
807 } // loop over strokes
808
809 BKE_object_materials_test(freestyle_bmain, object_mesh, (ID *)mesh);
810
811#if 0 // XXX
812 BLI_assert(mesh->verts_num == vertex_index);
813 BLI_assert(mesh->edges_num == edge_index);
814 BLI_assert(mesh->corners_num == loop_index);
815 BKE_mesh_validate(mesh, true, true);
816#endif
817}
818
819// A replacement of BKE_object_add() for better performance.
821{
822 Object *ob;
823 char name[MAX_ID_NAME];
824 uint mesh_id = get_stroke_mesh_id();
825
826 SNPRINTF(name, "0%08xOB", mesh_id);
828 SNPRINTF(name, "0%08xME", mesh_id);
829 ob->data = BKE_mesh_add(freestyle_bmain, name);
830
831 Collection *collection_master = freestyle_scene->master_collection;
832 BKE_collection_object_add(freestyle_bmain, collection_master, ob);
834
837 &ob->id,
839
840 return ob;
841}
842
844{
845 Camera *camera = (Camera *)freestyle_scene->camera->data;
846 if (camera->clip_end < _z) {
847 camera->clip_end = _z + _z_delta * 100.0f;
848 }
849#if 0
850 if (G.debug & G_DEBUG_FREESTYLE) {
851 cout << "clip_start " << camera->clip_start << ", clip_end " << camera->clip_end << endl;
852 }
853#endif
854
855 Render *freestyle_render = RE_NewSceneRender(freestyle_scene);
857
858 RE_RenderFreestyleStrokes(
859 freestyle_render, freestyle_bmain, freestyle_scene, render && get_stroke_count() > 0);
860
861 return freestyle_render;
862}
863
864} /* namespace Freestyle */
Configuration file.
void BKE_id_attributes_active_color_set(struct ID *id, const char *name)
Definition attribute.cc:965
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
CustomData interface, see also DNA_customdata_types.h.
@ CD_SET_DEFAULT
@ CD_CONSTRUCT
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
const char * CustomData_get_layer_name(const CustomData *data, eCustomDataType type, int n)
void CustomData_set_layer_active(CustomData *data, eCustomDataType type, int n)
@ G_DEBUG_FREESTYLE
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:843
void id_us_plus(ID *id)
Definition lib_id.cc:351
void id_us_min(ID *id)
Definition lib_id.cc:359
Main * BKE_main_new(void)
Definition main.cc:45
void BKE_main_free(Main *bmain)
Definition main.cc:175
General operations, lookup, etc. for materials.
void BKE_object_materials_test(struct Main *bmain, struct Object *ob, struct ID *id)
struct Material * BKE_material_add(struct Main *bmain, const char *name)
bool BKE_mesh_validate(Mesh *mesh, bool do_verbose, bool cddata_check_mask)
Mesh * BKE_mesh_add(Main *bmain, const char *name)
void BKE_mesh_face_offsets_ensure_alloc(Mesh *mesh)
#define SH_NODE_MIX_RGB_LEGACY
Definition BKE_node.hh:893
#define SH_NODE_UVMAP
Definition BKE_node.hh:970
#define SH_NODE_UVALONGSTROKE
Definition BKE_node.hh:974
#define SH_NODE_OUTPUT_MATERIAL
Definition BKE_node.hh:913
#define SH_NODE_OUTPUT_LINESTYLE
Definition BKE_node.hh:973
void BKE_ntree_update_main_tree(Main *bmain, bNodeTree *ntree, NodeTreeUpdateExtraParams *params)
General operations, lookup, etc. for blender objects.
Object * BKE_object_add(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name) ATTR_NONNULL(1
Object * BKE_object_add_only_object(Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
void BKE_scene_copy_data_eevee(Scene *sce_dst, const Scene *sce_src)
Definition scene.cc:1772
int BKE_render_num_threads(const RenderData *r)
Definition scene.cc:2850
Scene * BKE_scene_add(Main *bmain, const char *name)
Definition scene.cc:1954
void BKE_scene_set_background(Main *bmain, Scene *sce)
Definition scene.cc:1987
#define BLI_assert(a)
Definition BLI_assert.h:50
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findptr(const struct ListBase *listbase, const void *ptr, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE void linearrgb_to_srgb_uchar4(unsigned char srgb[4], const float linear[4])
MINLINE void copy_v3fl_v3db(float r[3], const double a[3])
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned int uint
Class to define a canvas designed to draw style modules.
@ DAG_EVAL_RENDER
Depsgraph * DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
Definition depsgraph.cc:273
void DEG_graph_id_tag_update(Main *bmain, Depsgraph *depsgraph, ID *id, unsigned int flags)
void DEG_graph_free(Depsgraph *graph)
Definition depsgraph.cc:301
void DEG_relations_tag_update(Main *bmain)
void DEG_graph_tag_relations_update(Depsgraph *graph)
void DEG_graph_relations_update(Depsgraph *graph)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:1044
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define MAX_ID_NAME
Definition DNA_ID.h:377
@ CAM_ORTHO
Object groups, one object can be in many groups at once.
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
These structs are the foundation for all linked lists in the library system.
@ MA_RAMP_BLEND
#define MAXMAT
@ MA_BM_HASHED
#define MESH_MAX_VERTS
@ NODE_DO_OUTPUT
Object is a sort of wrapper for general info.
@ OB_CAMERA
@ OB_MESH
@ R_MULTIVIEW
@ R_SINGLE_LAYER
@ R_NO_FRAME_UPDATE
@ R_ALPHAPREMUL
@ R_EDGE_FRS
@ R_BORDER
@ R_IMF_IMTYPE_PNG
@ SCE_LAY_SOLID
@ R_IMF_PLANES_RGBA
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
ATTR_WARN_UNUSED_RESULT const BMVert * v
PyObject * self
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
bool test_triangle_visibility(StrokeVertexRep *svRep[3]) const
vector< StrokeGroup * > texturedStrokeGroups
Render * RenderScene(Render *re, bool render)
void test_strip_visibility(Strip::vertex_container &strip_vertices, int *visible_faces, int *visible_segments) const
void GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
static Material * GetStrokeShader(Main *bmain, bNodeTree *iNodeTree, bool do_id_user)
virtual void RenderStrokeRep(StrokeRep *iStrokeRep) const
BlenderStrokeRenderer(Render *re, int render_count)
virtual void RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
bool hasTex() const
Definition StrokeRep.h:216
void setMaterial(Material *mat)
Definition StrokeRep.h:247
vector< Strip * > & getStrips()
Definition StrokeRep.h:221
bNodeTree * getNodeTree() const
Definition StrokeRep.h:211
Vec2r & texCoord(bool tips=false)
Definition StrokeRep.h:64
value_type x() const
Definition VecMat.h:296
value_type y() const
Definition VecMat.h:306
#define printf
OperationNode * node
Material material
#define offsetof(t, d)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
#define L
#define G(x, y, z)
inherits from class Rep
Definition AppCanvas.cpp:20
bNodeTree * node_tree_copy_tree_ex(const bNodeTree *ntree, Main *bmain, bool do_id_user)
Definition node.cc:3247
void node_set_active(bNodeTree *ntree, bNode *node)
Definition node.cc:3896
void node_remove_socket_links(bNodeTree *ntree, bNodeSocket *sock)
Definition node.cc:2984
bNode * node_add_static_node(const bContext *C, bNodeTree *ntree, int type)
Definition node.cc:2642
bNodeLink * node_add_link(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
Definition node.cc:2912
bNodeTree * node_tree_add_tree_embedded(Main *bmain, ID *owner_id, const char *name, const char *idname)
Definition node.cc:3239
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
Render * RE_NewSceneRender(const Scene *scene)
Definition DNA_ID.h:413
IDProperty * properties
Definition DNA_ID.h:456
char name[66]
Definition DNA_ID.h:425
void * first
unsigned char b
unsigned char r
unsigned char g
ListBase wm
Definition BKE_main.hh:239
struct bNodeTree * nodetree
float loc[3]
char engine[32]
struct ImageFormatData im_format
char pic[1024]
float dither_intensity
RenderData r
struct Main * main
Scene * scene
rcti disprect
struct Collection * master_collection
struct RenderData r
ListBase view_layers
struct Object * camera
ListBase nodes
ListBase links
int16_t custom1
float locy
ListBase inputs
float locx
void * storage
ListBase outputs
int16_t custom2
float xmax
float xmin
float ymax
float ymin
int ymin
int xmin
float max