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