Blender V5.0
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
8
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.hh"
40#include "BKE_mesh.hh"
41#include "BKE_node.hh"
44#include "BKE_object.hh"
45#include "BKE_scene.hh"
46
47#include "BLI_ghash.h"
48#include "BLI_listbase.h"
49#include "BLI_math_color.h"
50#include "BLI_math_vector.h"
52#include "BLI_utildefines.h"
53
54#include "DEG_depsgraph.hh"
56
57#include "RE_pipeline.h"
58
59#include "render_types.h"
60
61#include <climits>
62
63using blender::float3;
64
65namespace Freestyle {
66
67const char *BlenderStrokeRenderer::uvNames[] = {"along_stroke", "along_stroke_tips"};
68
70{
72
73 /* NOTE(@sergey): We use the same window manager for freestyle `bmain` as real `bmain` uses.
74 * This is needed because freestyle's `bmain` could be used to tag scenes for update,
75 * which implies call of #ED_render_scene_update in some cases and that function
76 * requires proper window manager to present. */
77 freestyle_bmain->wm = re->main->wm;
78
79 // for stroke mesh generation
80 _width = re->winx;
81 _height = re->winy;
82
83 old_scene = re->scene;
84
85 char name[MAX_ID_NAME - 2];
86 SNPRINTF(name, "FRS%d_%s", render_count, re->scene->id.name + 2);
88 freestyle_scene->r.cfra = old_scene->r.cfra;
89 freestyle_scene->r.mode = old_scene->r.mode & ~(R_EDGE_FRS | R_BORDER);
90 freestyle_scene->r.xsch = re->rectx; // old_scene->r.xsch
91 freestyle_scene->r.ysch = re->recty; // old_scene->r.ysch
92 freestyle_scene->r.xasp = 1.0f; // old_scene->r.xasp;
93 freestyle_scene->r.yasp = 1.0f; // old_scene->r.yasp;
94 freestyle_scene->r.size = 100; // old_scene->r.size
95 freestyle_scene->r.color_mgt_flag = 0; // old_scene->r.color_mgt_flag;
96 freestyle_scene->r.scemode = (old_scene->r.scemode &
98 (re->r.scemode);
99 freestyle_scene->r.flag = old_scene->r.flag;
100 freestyle_scene->r.threads = old_scene->r.threads;
101 freestyle_scene->r.border.xmin = old_scene->r.border.xmin;
102 freestyle_scene->r.border.ymin = old_scene->r.border.ymin;
103 freestyle_scene->r.border.xmax = old_scene->r.border.xmax;
104 freestyle_scene->r.border.ymax = old_scene->r.border.ymax;
105 STRNCPY(freestyle_scene->r.pic, old_scene->r.pic);
106 freestyle_scene->r.dither_intensity = old_scene->r.dither_intensity;
107 STRNCPY(freestyle_scene->r.engine, old_scene->r.engine);
108 if (G.debug & G_DEBUG_FREESTYLE) {
109 cout << "Stroke rendering engine : " << freestyle_scene->r.engine << endl;
110 }
111 freestyle_scene->r.im_format.planes = R_IMF_PLANES_RGBA;
112 freestyle_scene->r.im_format.imtype = R_IMF_IMTYPE_PNG;
113
114 // Copy ID properties, including Cycles render properties
115 if (old_scene->id.properties) {
116 freestyle_scene->id.properties = IDP_CopyProperty_ex(old_scene->id.properties, 0);
117 }
118 if (old_scene->id.system_properties) {
119 freestyle_scene->id.system_properties = IDP_CopyProperty_ex(old_scene->id.system_properties,
120 0);
121 }
122 // Copy eevee render settings.
124
125 /* Render with transparent background. */
126 freestyle_scene->r.alphamode = R_ALPHAPREMUL;
127
128 if (G.debug & G_DEBUG_FREESTYLE) {
129 printf("%s: %d thread(s)\n", __func__, BKE_render_num_threads(&freestyle_scene->r));
130 }
131
133
134 // Scene layer.
135 ViewLayer *view_layer = (ViewLayer *)freestyle_scene->view_layers.first;
136 view_layer->layflag = SCE_LAY_SOLID;
137
138 // Camera
139 Object *object_camera = BKE_object_add(
140 freestyle_bmain, freestyle_scene, view_layer, OB_CAMERA, nullptr);
141
142 Camera *camera = (Camera *)object_camera->data;
143 camera->type = CAM_ORTHO;
144 camera->ortho_scale = max(re->rectx, re->recty);
145 camera->clip_start = 0.1f;
146 camera->clip_end = 100.0f;
147
148 _z_delta = 0.00001f;
149 _z = camera->clip_start + _z_delta;
150
151 object_camera->loc[0] = re->disprect.xmin + 0.5f * re->rectx;
152 object_camera->loc[1] = re->disprect.ymin + 0.5f * re->recty;
153 object_camera->loc[2] = 1.0f;
154
155 freestyle_scene->camera = object_camera;
156
157 // Reset serial mesh ID (used for BlenderStrokeRenderer::NewMesh())
158 _mesh_id = 0xffffffff;
159
160 // Create a bNodeTree-to-Material hash table
161 _nodetree_hash = BLI_ghash_ptr_new("BlenderStrokeRenderer::_nodetree_hash");
162
163 // Depsgraph
169}
170
172{
173 BLI_ghash_free(_nodetree_hash, nullptr, nullptr);
174
176
178
179 /* detach the window manager from freestyle bmain (see comments
180 * in add_freestyle() for more detail)
181 */
183
185}
186
188{
189 float z = _z;
190 BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this);
191 if (!(_z < _z_delta * 100000.0f)) {
192 self->_z_delta *= 10.0f;
193 }
194 self->_z += _z_delta;
195 return -z;
196}
197
199{
200 uint mesh_id = _mesh_id;
201 BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this);
202 self->_mesh_id--;
203 return mesh_id;
204}
205
207 bNodeTree *iNodeTree,
208 bool do_id_user)
209{
210 Material *ma = BKE_material_add(bmain, "stroke_shader");
211 bNodeTree *ntree;
212 bNode *output_linestyle = nullptr;
213 bNodeSocket *fromsock, *tosock;
214 PointerRNA fromptr, toptr;
215 NodeShaderAttribute *storage;
216
217 id_us_min(&ma->id);
218
219 if (iNodeTree) {
220 // make a copy of linestyle->nodetree
221 ntree = blender::bke::node_tree_copy_tree_ex(*iNodeTree, bmain, do_id_user);
222
223 // find the active Output Line Style node
224 LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
225 if (node->type_legacy == SH_NODE_OUTPUT_LINESTYLE && (node->flag & NODE_DO_OUTPUT)) {
226 output_linestyle = node;
227 break;
228 }
229 }
230 ma->nodetree = ntree;
231 }
232 else {
234 nullptr, &ma->id, "stroke_shader", "ShaderNodeTree");
235 }
237
238 bNode *input_attr_color = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_ATTRIBUTE);
239 input_attr_color->location[0] = 0.0f;
240 input_attr_color->location[1] = -200.0f;
241 storage = (NodeShaderAttribute *)input_attr_color->storage;
242 STRNCPY(storage->name, "Color");
243
245 nullptr, *ntree, SH_NODE_MIX_RGB_LEGACY);
246 mix_rgb_color->custom1 = MA_RAMP_BLEND; // Mix
247 mix_rgb_color->location[0] = 200.0f;
248 mix_rgb_color->location[1] = -200.0f;
249 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 0); // Fac
250 toptr = RNA_pointer_create_discrete((ID *)ntree, &RNA_NodeSocket, tosock);
251 RNA_float_set(&toptr, "default_value", 0.0f);
252
253 bNode *input_attr_alpha = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_ATTRIBUTE);
254 input_attr_alpha->location[0] = 400.0f;
255 input_attr_alpha->location[1] = 300.0f;
256 storage = (NodeShaderAttribute *)input_attr_alpha->storage;
257 STRNCPY(storage->name, "Alpha");
258
260 nullptr, *ntree, SH_NODE_MIX_RGB_LEGACY);
261 mix_rgb_alpha->custom1 = MA_RAMP_BLEND; // Mix
262 mix_rgb_alpha->location[0] = 600.0f;
263 mix_rgb_alpha->location[1] = 300.0f;
264 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 0); // Fac
265 toptr = RNA_pointer_create_discrete((ID *)ntree, &RNA_NodeSocket, tosock);
266 RNA_float_set(&toptr, "default_value", 0.0f);
267
268 bNode *shader_emission = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_EMISSION);
269 shader_emission->location[0] = 400.0f;
270 shader_emission->location[1] = -200.0f;
271
272 bNode *input_light_path = blender::bke::node_add_static_node(
273 nullptr, *ntree, SH_NODE_LIGHT_PATH);
274 input_light_path->location[0] = 400.0f;
275 input_light_path->location[1] = 100.0f;
276
277 bNode *mix_shader_color = blender::bke::node_add_static_node(
278 nullptr, *ntree, SH_NODE_MIX_SHADER);
279 mix_shader_color->location[0] = 600.0f;
280 mix_shader_color->location[1] = -100.0f;
281
282 bNode *shader_transparent = blender::bke::node_add_static_node(
283 nullptr, *ntree, SH_NODE_BSDF_TRANSPARENT);
284 shader_transparent->location[0] = 600.0f;
285 shader_transparent->location[1] = 100.0f;
286
287 bNode *mix_shader_alpha = blender::bke::node_add_static_node(
288 nullptr, *ntree, SH_NODE_MIX_SHADER);
289 mix_shader_alpha->location[0] = 800.0f;
290 mix_shader_alpha->location[1] = 100.0f;
291
292 bNode *output_material = blender::bke::node_add_static_node(
293 nullptr, *ntree, SH_NODE_OUTPUT_MATERIAL);
294 output_material->location[0] = 1000.0f;
295 output_material->location[1] = 100.0f;
296
297 fromsock = (bNodeSocket *)BLI_findlink(&input_attr_color->outputs, 0); // Color
298 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 1); // Color1
299 blender::bke::node_add_link(*ntree, *input_attr_color, *fromsock, *mix_rgb_color, *tosock);
300
301 fromsock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->outputs, 0); // Color
302 tosock = (bNodeSocket *)BLI_findlink(&shader_emission->inputs, 0); // Color
303 blender::bke::node_add_link(*ntree, *mix_rgb_color, *fromsock, *shader_emission, *tosock);
304
305 fromsock = (bNodeSocket *)BLI_findlink(&shader_emission->outputs, 0); // Emission
306 tosock = (bNodeSocket *)BLI_findlink(&mix_shader_color->inputs, 2); // Shader (second)
307 blender::bke::node_add_link(*ntree, *shader_emission, *fromsock, *mix_shader_color, *tosock);
308
309 fromsock = (bNodeSocket *)BLI_findlink(&input_light_path->outputs, 0); // In Camera Ray
310 tosock = (bNodeSocket *)BLI_findlink(&mix_shader_color->inputs, 0); // Fac
311 blender::bke::node_add_link(*ntree, *input_light_path, *fromsock, *mix_shader_color, *tosock);
312
313 fromsock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->outputs, 0); // Color
314 tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 0); // Fac
315 blender::bke::node_add_link(*ntree, *mix_rgb_alpha, *fromsock, *mix_shader_alpha, *tosock);
316
317 fromsock = (bNodeSocket *)BLI_findlink(&input_attr_alpha->outputs, 0); // Color
318 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 1); // Color1
319 blender::bke::node_add_link(*ntree, *input_attr_alpha, *fromsock, *mix_rgb_alpha, *tosock);
320
321 fromsock = (bNodeSocket *)BLI_findlink(&shader_transparent->outputs, 0); // BSDF
322 tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 1); // Shader (first)
323 blender::bke::node_add_link(*ntree, *shader_transparent, *fromsock, *mix_shader_alpha, *tosock);
324
325 fromsock = (bNodeSocket *)BLI_findlink(&mix_shader_color->outputs, 0); // Shader
326 tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 2); // Shader (second)
327 blender::bke::node_add_link(*ntree, *mix_shader_color, *fromsock, *mix_shader_alpha, *tosock);
328
329 fromsock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->outputs, 0); // Shader
330 tosock = (bNodeSocket *)BLI_findlink(&output_material->inputs, 0); // Surface
331 blender::bke::node_add_link(*ntree, *mix_shader_alpha, *fromsock, *output_material, *tosock);
332
333 if (output_linestyle) {
334 bNodeSocket *outsock;
335 bNodeLink *link;
336
337 mix_rgb_color->custom1 = output_linestyle->custom1; // blend_type
338 mix_rgb_color->custom2 = output_linestyle->custom2; // use_clamp
339
340 outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 0); // Color
341 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 2); // Color2
342 link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
343 if (link) {
345 *ntree, *link->fromnode, *link->fromsock, *mix_rgb_color, *tosock);
346 }
347 else {
348 float color[4];
349 fromptr = RNA_pointer_create_discrete((ID *)ntree, &RNA_NodeSocket, outsock);
350 toptr = RNA_pointer_create_discrete((ID *)ntree, &RNA_NodeSocket, tosock);
351 RNA_float_get_array(&fromptr, "default_value", color);
352 RNA_float_set_array(&toptr, "default_value", color);
353 }
354
355 outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 1); // Color Fac
356 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 0); // Fac
357 link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
358 if (link) {
360 *ntree, *link->fromnode, *link->fromsock, *mix_rgb_color, *tosock);
361 }
362 else {
363 fromptr = RNA_pointer_create_discrete((ID *)ntree, &RNA_NodeSocket, outsock);
364 toptr = RNA_pointer_create_discrete((ID *)ntree, &RNA_NodeSocket, tosock);
365 RNA_float_set(&toptr, "default_value", RNA_float_get(&fromptr, "default_value"));
366 }
367
368 outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 2); // Alpha
369 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 2); // Color2
370 link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
371 if (link) {
373 *ntree, *link->fromnode, *link->fromsock, *mix_rgb_alpha, *tosock);
374 }
375 else {
376 float color[4];
377 fromptr = RNA_pointer_create_discrete((ID *)ntree, &RNA_NodeSocket, outsock);
378 toptr = RNA_pointer_create_discrete((ID *)ntree, &RNA_NodeSocket, tosock);
379 color[0] = color[1] = color[2] = RNA_float_get(&fromptr, "default_value");
380 color[3] = 1.0f;
381 RNA_float_set_array(&toptr, "default_value", color);
382 }
383
384 outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 3); // Alpha Fac
385 tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 0); // Fac
386 link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
387 if (link) {
389 *ntree, *link->fromnode, *link->fromsock, *mix_rgb_alpha, *tosock);
390 }
391 else {
392 fromptr = RNA_pointer_create_discrete((ID *)ntree, &RNA_NodeSocket, outsock);
393 toptr = RNA_pointer_create_discrete((ID *)ntree, &RNA_NodeSocket, tosock);
394 RNA_float_set(&toptr, "default_value", RNA_float_get(&fromptr, "default_value"));
395 }
396
397 LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
398 if (node->type_legacy == SH_NODE_UVALONGSTROKE) {
399 // UV output of the UV Along Stroke node
400 bNodeSocket *sock = (bNodeSocket *)BLI_findlink(&node->outputs, 0);
401
402 // add new UV Map node
403 bNode *input_uvmap = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_UVMAP);
404 input_uvmap->location[0] = node->location[0] - 200.0f;
405 input_uvmap->location[1] = node->location[1];
406 NodeShaderUVMap *storage = (NodeShaderUVMap *)input_uvmap->storage;
407 if (node->custom1 & 1) { // use_tips
408 STRNCPY(storage->uv_map, uvNames[1]);
409 }
410 else {
411 STRNCPY(storage->uv_map, uvNames[0]);
412 }
413 fromsock = (bNodeSocket *)BLI_findlink(&input_uvmap->outputs, 0); // UV
414
415 // replace links from the UV Along Stroke node by links from the UV Map node
416 LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
417 if (link->fromnode == node && link->fromsock == sock) {
419 *ntree, *input_uvmap, *fromsock, *link->tonode, *link->tosock);
420 }
421 }
423 }
424 }
425 }
426
427 blender::bke::node_set_active(*ntree, *output_material);
429
430 return ma;
431}
432
434{
435 RenderStrokeRepBasic(iStrokeRep);
436}
437
439{
440 bNodeTree *nt = iStrokeRep->getNodeTree();
442 if (!ma) {
445 }
446 iStrokeRep->setMaterial(ma);
447
448 const vector<Strip *> &strips = iStrokeRep->getStrips();
449 const bool hasTex = iStrokeRep->hasTex();
450 int totvert = 0, totedge = 0, faces_num = 0, totloop = 0;
451 int visible_faces, visible_segments;
452 for (vector<Strip *>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
453 Strip::vertex_container &strip_vertices = (*s)->vertices();
454
455 // count visible faces and strip segments
456 test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
457 if (visible_faces == 0) {
458 continue;
459 }
460
461 totvert += visible_faces + visible_segments * 2;
462 totedge += visible_faces * 2 + visible_segments;
463 faces_num += visible_faces;
464 totloop += visible_faces * 3;
465 }
466
467 BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this); // FIXME
468 vector<StrokeGroup *> *groups = hasTex ? &self->texturedStrokeGroups : &self->strokeGroups;
469 StrokeGroup *group;
470 if (groups->empty() || !(groups->back()->totvert + totvert < MESH_MAX_VERTS &&
471 groups->back()->materials.size() + 1 < MAXMAT))
472 {
473 group = new StrokeGroup;
474 groups->push_back(group);
475 }
476 else {
477 group = groups->back();
478 }
479 group->strokes.push_back(iStrokeRep);
480 group->totvert += totvert;
481 group->totedge += totedge;
482 group->faces_num += faces_num;
483 group->totloop += totloop;
484
485 if (!group->materials.contains(ma)) {
486 group->materials.add_new(ma, group->materials.size());
487 }
488}
489
490// Check if the triangle is visible (i.e., within the render image boundary)
492{
493 int xl, xu, yl, yu;
494 Vec2r p;
495
496 xl = xu = yl = yu = 0;
497 for (int i = 0; i < 3; i++) {
498 p = svRep[i]->point2d();
499 if (p[0] < 0.0) {
500 xl++;
501 }
502 else if (p[0] > _width) {
503 xu++;
504 }
505 if (p[1] < 0.0) {
506 yl++;
507 }
508 else if (p[1] > _height) {
509 yu++;
510 }
511 }
512 return !(xl == 3 || xu == 3 || yl == 3 || yu == 3);
513}
514
515// Check the visibility of faces and strip segments.
516void BlenderStrokeRenderer::test_strip_visibility(Strip::vertex_container &strip_vertices,
517 int *visible_faces,
518 int *visible_segments) const
519{
520 const int strip_vertex_count = strip_vertices.size();
521 Strip::vertex_container::iterator v[3];
522 StrokeVertexRep *svRep[3];
523 bool visible;
524
525 /* Iterate over all vertices and count visible faces and strip segments
526 * (NOTE: a strip segment is a series of visible faces, while two strip
527 * segments are separated by one or more invisible faces). */
528 v[0] = strip_vertices.begin();
529 v[1] = v[0] + 1;
530 v[2] = v[0] + 2;
531 *visible_faces = *visible_segments = 0;
532 visible = false;
533 for (int n = 2; n < strip_vertex_count; n++, v[0]++, v[1]++, v[2]++) {
534 svRep[0] = *(v[0]);
535 svRep[1] = *(v[1]);
536 svRep[2] = *(v[2]);
537 if (test_triangle_visibility(svRep)) {
538 (*visible_faces)++;
539 if (!visible) {
540 (*visible_segments)++;
541 }
542 visible = true;
543 }
544 else {
545 visible = false;
546 }
547 }
548}
549
550// Release allocated memory for stroke groups
552{
553 vector<StrokeGroup *>::const_iterator it, itend;
554
555 for (it = strokeGroups.begin(), itend = strokeGroups.end(); it != itend; ++it) {
556 delete (*it);
557 }
558 for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end(); it != itend; ++it) {
559 delete (*it);
560 }
561}
562
563// Build a scene populated by mesh objects representing stylized strokes
565{
566 vector<StrokeGroup *>::const_iterator it, itend;
567
568 for (it = strokeGroups.begin(), itend = strokeGroups.end(); it != itend; ++it) {
569 GenerateStrokeMesh(*it, false);
570 }
571 for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end(); it != itend; ++it) {
572 GenerateStrokeMesh(*it, true);
573 }
574 return get_stroke_count();
575}
576
577// Return the number of strokes
579{
580 return strokeGroups.size() + texturedStrokeGroups.size();
581}
582
583// Build a mesh object representing a group of stylized strokes
585{
586 using namespace blender;
587#if 0
588 Object *object_mesh = BKE_object_add(
589 freestyle_bmain, (ViewLayer *)freestyle_scene->view_layers.first, OB_MESH);
591#else
592 Object *object_mesh = NewMesh();
593#endif
594 Mesh *mesh = (Mesh *)object_mesh->data;
595
596 mesh->verts_num = group->totvert;
597 mesh->edges_num = group->totedge;
598 mesh->faces_num = group->faces_num;
599 mesh->corners_num = group->totloop;
600 mesh->totcol = group->materials.size();
602 blender::bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
603 blender::MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
605 "position", bke::AttrDomain::Point);
606 bke::SpanAttributeWriter edge_verts_attr = attributes.lookup_or_add_for_write_span<int2>(
607 ".edge_verts", bke::AttrDomain::Edge);
608 bke::SpanAttributeWriter corner_vert_attr = attributes.lookup_or_add_for_write_span<int>(
609 ".corner_vert", bke::AttrDomain::Corner);
610 bke::SpanAttributeWriter corner_edge_attr = attributes.lookup_or_add_for_write_span<int>(
611 ".corner_edge", bke::AttrDomain::Corner);
612 bke::SpanAttributeWriter material_index_attr = attributes.lookup_or_add_for_write_span<int>(
613 "material_index", bke::AttrDomain::Face);
614 float3 *vert_positions = position_attr.span.data();
615 int2 *edges = edge_verts_attr.span.data();
616 int *corner_verts = corner_vert_attr.span.data();
617 int *corner_edges = corner_edge_attr.span.data();
618 int *material_indices = material_index_attr.span.data();
619
620 blender::float2 *loopsuv[2] = {nullptr};
621
622 if (hasTex) {
623 // First UV layer
624 loopsuv[0] = static_cast<blender::float2 *>(CustomData_add_layer_named(
627
628 // Second UV layer
629 loopsuv[1] = static_cast<blender::float2 *>(CustomData_add_layer_named(
632 }
633
634 // colors and transparency (the latter represented by grayscale colors)
641
642 mesh->mat = MEM_malloc_arrayN<Material *>(size_t(mesh->totcol), "MaterialList");
643 for (const auto item : group->materials.items()) {
644 Material *material = item.key;
645 const int matnr = item.value;
646 mesh->mat[matnr] = material;
647 if (material) {
648 id_us_plus(&material->id);
649 }
650 }
651
653 // Data copy
655
656 int vertex_index = 0, edge_index = 0, loop_index = 0, face_index = 0;
657 int visible_faces, visible_segments;
658 bool visible;
659 Strip::vertex_container::iterator v[3];
660 StrokeVertexRep *svRep[3];
661 Vec2r p;
662
663 for (vector<StrokeRep *>::const_iterator it = group->strokes.begin(),
664 itend = group->strokes.end();
665 it != itend;
666 ++it)
667 {
668 const int matnr = group->materials.lookup_default((*it)->getMaterial(), 0);
669
670 vector<Strip *> &strips = (*it)->getStrips();
671 for (vector<Strip *>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
672 Strip::vertex_container &strip_vertices = (*s)->vertices();
673 int strip_vertex_count = strip_vertices.size();
674
675 // count visible faces and strip segments
676 test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
677 if (visible_faces == 0) {
678 continue;
679 }
680
681 v[0] = strip_vertices.begin();
682 v[1] = v[0] + 1;
683 v[2] = v[0] + 2;
684
685 visible = false;
686
687 // NOTE: Mesh generation in the following loop assumes stroke strips
688 // to be triangle strips.
689 for (int n = 2; n < strip_vertex_count; n++, v[0]++, v[1]++, v[2]++) {
690 svRep[0] = *(v[0]);
691 svRep[1] = *(v[1]);
692 svRep[2] = *(v[2]);
693 if (!test_triangle_visibility(svRep)) {
694 visible = false;
695 }
696 else {
697 if (!visible) {
698 // first vertex
699 vert_positions[vertex_index][0] = svRep[0]->point2d()[0];
700 vert_positions[vertex_index][1] = svRep[0]->point2d()[1];
701 vert_positions[vertex_index][2] = get_stroke_vertex_z();
702
703 ++vertex_index;
704
705 // second vertex
706 vert_positions[vertex_index][0] = svRep[1]->point2d()[0];
707 vert_positions[vertex_index][1] = svRep[1]->point2d()[1];
708 vert_positions[vertex_index][2] = get_stroke_vertex_z();
709
710 ++vertex_index;
711
712 // first edge
713 edges[edge_index][0] = vertex_index - 2;
714 edges[edge_index][1] = vertex_index - 1;
715 ++edge_index;
716 }
717 visible = true;
718
719 // vertex
720 vert_positions[vertex_index][0] = svRep[2]->point2d()[0];
721 vert_positions[vertex_index][1] = svRep[2]->point2d()[1];
722 vert_positions[vertex_index][2] = get_stroke_vertex_z();
723 ++vertex_index;
724
725 // edges
726 edges[edge_index][0] = vertex_index - 1;
727 edges[edge_index][1] = vertex_index - 3;
728 ++edge_index;
729
730 edges[edge_index][0] = vertex_index - 1;
731 edges[edge_index][1] = vertex_index - 2;
732 ++edge_index;
733
734 // poly
735 face_offsets[face_index] = loop_index;
736 *material_indices = matnr;
737 ++material_indices;
738 ++face_index;
739
740 // Even and odd loops connect triangles vertices differently
741 bool is_odd = n % 2;
742 // loops
743 if (is_odd) {
744 corner_verts[0] = vertex_index - 1;
745 corner_edges[0] = edge_index - 2;
746
747 corner_verts[1] = vertex_index - 3;
748 corner_edges[1] = edge_index - 3;
749
750 corner_verts[2] = vertex_index - 2;
751 corner_edges[2] = edge_index - 1;
752 }
753 else {
754 corner_verts[0] = vertex_index - 1;
755 corner_edges[0] = edge_index - 1;
756
757 corner_verts[1] = vertex_index - 2;
758 corner_edges[1] = edge_index - 3;
759
760 corner_verts[2] = vertex_index - 3;
761 corner_edges[2] = edge_index - 2;
762 }
763 corner_verts += 3;
764 corner_edges += 3;
765 loop_index += 3;
766
767 // UV
768 if (hasTex) {
769 // First UV layer (loopsuv[0]) has no tips (texCoord(0)).
770 // Second UV layer (loopsuv[1]) has tips: (texCoord(1)).
771 for (int L = 0; L < 2; L++) {
772 if (is_odd) {
773 loopsuv[L][0][0] = svRep[2]->texCoord(L).x();
774 loopsuv[L][0][1] = svRep[2]->texCoord(L).y();
775
776 loopsuv[L][1][0] = svRep[0]->texCoord(L).x();
777 loopsuv[L][1][1] = svRep[0]->texCoord(L).y();
778
779 loopsuv[L][2][0] = svRep[1]->texCoord(L).x();
780 loopsuv[L][2][1] = svRep[1]->texCoord(L).y();
781 }
782 else {
783 loopsuv[L][0][0] = svRep[2]->texCoord(L).x();
784 loopsuv[L][0][1] = svRep[2]->texCoord(L).y();
785
786 loopsuv[L][1][0] = svRep[1]->texCoord(L).x();
787 loopsuv[L][1][1] = svRep[1]->texCoord(L).y();
788
789 loopsuv[L][2][0] = svRep[0]->texCoord(L).x();
790 loopsuv[L][2][1] = svRep[0]->texCoord(L).y();
791 }
792 loopsuv[L] += 3;
793 }
794 }
795
796 // colors and alpha transparency. vertex colors are in sRGB
797 // space by convention, so convert from linear
798 float rgba[3][4];
799
800 for (int i = 0; i < 3; i++) {
801 copy_v3fl_v3db(rgba[i], &svRep[i]->color()[0]);
802 rgba[i][3] = svRep[i]->alpha();
803 }
804
805 if (is_odd) {
806 linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]);
807 linearrgb_to_srgb_uchar4(&colors[1].r, rgba[0]);
808 linearrgb_to_srgb_uchar4(&colors[2].r, rgba[1]);
809 }
810 else {
811 linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]);
812 linearrgb_to_srgb_uchar4(&colors[1].r, rgba[1]);
813 linearrgb_to_srgb_uchar4(&colors[2].r, rgba[0]);
814 }
815 transp[0].r = transp[0].g = transp[0].b = colors[0].a;
816 transp[1].r = transp[1].g = transp[1].b = colors[1].a;
817 transp[2].r = transp[2].g = transp[2].b = colors[2].a;
818 colors += 3;
819 transp += 3;
820 }
821 } // loop over strip vertices
822 } // loop over strips
823 } // loop over strokes
824
826
827 position_attr.finish();
828 edge_verts_attr.finish();
829 corner_vert_attr.finish();
830 corner_edge_attr.finish();
831 material_index_attr.finish();
832
833#if 0 // XXX
834 BLI_assert(mesh->verts_num == vertex_index);
835 BLI_assert(mesh->edges_num == edge_index);
836 BLI_assert(mesh->corners_num == loop_index);
837 BKE_mesh_validate(mesh, true, true);
838#endif
839}
840
841// A replacement of BKE_object_add() for better performance.
843{
844 Object *ob;
845 char name[MAX_ID_NAME];
846 uint mesh_id = get_stroke_mesh_id();
847
848 SNPRINTF(name, "0%08xOB", mesh_id);
850 SNPRINTF(name, "0%08xME", mesh_id);
852
853 Collection *collection_master = freestyle_scene->master_collection;
854 BKE_collection_object_add(freestyle_bmain, collection_master, ob);
856
859 &ob->id,
861
862 return ob;
863}
864
866{
867 Camera *camera = (Camera *)freestyle_scene->camera->data;
868 if (camera->clip_end < _z) {
869 camera->clip_end = _z + _z_delta * 100.0f;
870 }
871#if 0
872 if (G.debug & G_DEBUG_FREESTYLE) {
873 cout << "clip_start " << camera->clip_start << ", clip_end " << camera->clip_end << endl;
874 }
875#endif
876
877 Render *freestyle_render = RE_NewSceneRender(freestyle_scene);
879
880 RE_RenderFreestyleStrokes(
881 freestyle_render, freestyle_bmain, freestyle_scene, render && get_stroke_count() > 0);
882
883 return freestyle_render;
884}
885
886} /* namespace Freestyle */
Configuration file.
void BKE_id_attributes_active_color_set(struct ID *id, std::optional< blender::StringRef > name)
Definition attribute.cc:985
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
CustomData interface, see also DNA_customdata_types.h.
@ CD_SET_DEFAULT
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:845
void id_us_plus(ID *id)
Definition lib_id.cc:358
void id_us_min(ID *id)
Definition lib_id.cc:366
Main * BKE_main_new()
Definition main.cc:89
void BKE_main_free(Main *bmain)
Definition main.cc:192
General operations, lookup, etc. for materials.
void BKE_object_materials_sync_length(Main *bmain, Object *ob, ID *id)
Material * BKE_material_add(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_SHADER
#define SH_NODE_MIX_RGB_LEGACY
#define SH_NODE_UVMAP
#define SH_NODE_EMISSION
#define SH_NODE_UVALONGSTROKE
#define SH_NODE_BSDF_TRANSPARENT
#define SH_NODE_OUTPUT_MATERIAL
#define SH_NODE_OUTPUT_LINESTYLE
#define SH_NODE_ATTRIBUTE
#define SH_NODE_LIGHT_PATH
void BKE_ntree_update_after_single_tree_change(Main &bmain, bNodeTree &modified_tree, const 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:1777
int BKE_render_num_threads(const RenderData *r)
Definition scene.cc:2888
Scene * BKE_scene_add(Main *bmain, const char *name)
Definition scene.cc:2001
void BKE_scene_set_background(Main *bmain, Scene *sce)
Definition scene.cc:2034
#define BLI_assert(a)
Definition BLI_assert.h:46
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.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
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 SNPRINTF(dst, format,...)
Definition BLI_string.h:604
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
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:278
void DEG_graph_id_tag_update(Main *bmain, Depsgraph *depsgraph, ID *id, unsigned int flags)
void DEG_graph_free(Depsgraph *graph)
Definition depsgraph.cc:306
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:1054
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:1077
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define MAX_ID_NAME
Definition DNA_ID.h:373
@ CAM_ORTHO
Object groups, one object can be in many groups at once.
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT2
These structs are the foundation for all linked lists in the library system.
@ MA_BM_HASHED
#define MAXMAT
@ MA_RAMP_BLEND
#define MESH_MAX_VERTS
@ NODE_DO_OUTPUT
Object is a sort of wrapper for general info.
@ OB_CAMERA
@ OB_MESH
@ SCE_LAY_SOLID
@ R_EDGE_FRS
@ R_BORDER
@ R_IMF_PLANES_RGBA
@ R_ALPHAPREMUL
@ R_IMF_IMTYPE_PNG
@ R_MULTIVIEW
@ R_SINGLE_LAYER
@ R_NO_FRAME_UPDATE
Read Guarded memory(de)allocation.
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:210
void setMaterial(Material *mat)
Definition StrokeRep.h:241
vector< Strip * > & getStrips()
Definition StrokeRep.h:215
bNodeTree * getNodeTree() const
Definition StrokeRep.h:205
Vec2r & texCoord(bool tips=false)
Definition StrokeRep.h:62
value_type x() const
Definition VecMat.h:292
value_type y() const
Definition VecMat.h:302
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:265
int64_t size() const
Definition BLI_map.hh:976
bool contains(const Key &key) const
Definition BLI_map.hh:353
ItemIterator items() const &
Definition BLI_map.hh:902
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
#define offsetof(t, d)
#define printf(...)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
#define L
#define G(x, y, z)
VecMat::Vec2< real > Vec2r
Definition Geom.h:24
inherits from class Rep
Definition AppCanvas.cpp:20
bNodeTree * node_tree_add_tree_embedded(Main *bmain, ID *owner_id, StringRefNull name, StringRefNull idname)
Definition node.cc:4098
bNode * node_add_static_node(const bContext *C, bNodeTree &ntree, int type)
Definition node.cc:3500
bNodeTree * node_tree_copy_tree_ex(const bNodeTree &ntree, Main *bmain, bool do_id_user)
Definition node.cc:4106
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:3810
void node_remove_socket_links(bNodeTree &ntree, bNodeSocket &sock)
Definition node.cc:3873
void node_set_active(bNodeTree &ntree, bNode &node)
Definition node.cc:4724
VecBase< float, 2 > float2
VecBase< float, 3 > float3
const char * name
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_discrete(ID *id, StructRNA *type, void *data)
Render * RE_NewSceneRender(const Scene *scene)
float clip_end
float clip_start
float ortho_scale
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
unsigned char a
unsigned char b
unsigned char r
unsigned char g
ListBase wm
Definition BKE_main.hh:307
struct bNodeTree * nodetree
int corners_num
int edges_num
struct Material ** mat
CustomData corner_data
short totcol
int faces_num
int verts_num
float loc[3]
RenderData r
struct Main * main
Scene * scene
rcti disprect
ListBase nodes
ListBase links
float location[2]
int16_t custom1
ListBase inputs
void * storage
ListBase outputs
int16_t custom2
int ymin
int xmin
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251