Blender V5.0
blenkernel/intern/material.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cmath>
11#include <cstring>
12#include <optional>
13
14#include "CLG_log.h"
15
16#include "MEM_guardedalloc.h"
17
18/* Allow using deprecated functionality for .blend file I/O. */
19#define DNA_DEPRECATED_ALLOW
20
21#include "DNA_ID.h"
22#include "DNA_curve_types.h"
23#include "DNA_curves_types.h"
25#include "DNA_defaults.h"
28#include "DNA_material_types.h"
29#include "DNA_meta_types.h"
30#include "DNA_node_types.h"
31#include "DNA_object_types.h"
32#include "DNA_particle_types.h"
34#include "DNA_scene_types.h"
35#include "DNA_userdef_types.h"
36#include "DNA_volume_types.h"
37
38#include "BLI_array_utils.h"
39#include "BLI_listbase.h"
40#include "BLI_math_color.h"
41#include "BLI_math_vector.h"
42#include "BLI_string.h"
43#include "BLI_utildefines.h"
44
45#include "BLT_translation.hh"
46
47#include "BKE_anim_data.hh"
48#include "BKE_brush.hh"
49#include "BKE_curve.hh"
50#include "BKE_curves.hh"
51#include "BKE_displist.h"
52#include "BKE_editmesh.hh"
53#include "BKE_grease_pencil.hh"
54#include "BKE_icons.h"
55#include "BKE_idtype.hh"
56#include "BKE_image.hh"
57#include "BKE_lib_id.hh"
58#include "BKE_lib_query.hh"
59#include "BKE_main.hh"
60#include "BKE_material.hh"
61#include "BKE_mesh.hh"
62#include "BKE_node.hh"
64#include "BKE_node_runtime.hh"
65#include "BKE_object.hh"
66#include "BKE_object_types.hh"
67#include "BKE_preview_image.hh"
68#include "BKE_scene.hh"
69#include "BKE_vfont.hh"
70
71#include "DEG_depsgraph.hh"
74
75#include "GPU_material.hh"
76
77#include "NOD_shader.h"
78
79#include "BLO_read_write.hh"
80
81static CLG_LogRef LOG = {"material"};
82
83static void material_init_data(ID *id)
84{
85 Material *material = (Material *)id;
86
88
90}
91
92static void material_copy_data(Main *bmain,
93 std::optional<Library *> owner_library,
94 ID *id_dst,
95 const ID *id_src,
96 const int flag)
97{
98 Material *material_dst = (Material *)id_dst;
99 const Material *material_src = (const Material *)id_src;
100
101 const bool is_localized = (flag & LIB_ID_CREATE_LOCAL) != 0;
102 /* Never handle user-count here for own sub-data. */
103 const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
104 /* Always need allocation of the embedded ID data. */
105 const int flag_embedded_id_data = flag_subdata & ~LIB_ID_CREATE_NO_ALLOCATE;
106
107 if (material_src->nodetree != nullptr) {
108 if (is_localized) {
109 material_dst->nodetree = blender::bke::node_tree_localize(material_src->nodetree,
110 &material_dst->id);
111 }
112 else {
113 BKE_id_copy_in_lib(bmain,
114 owner_library,
115 &material_src->nodetree->id,
116 &material_dst->id,
117 reinterpret_cast<ID **>(&material_dst->nodetree),
118 flag_embedded_id_data);
119 }
120 }
121
122 if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
123 BKE_previewimg_id_copy(&material_dst->id, &material_src->id);
124 }
125 else {
126 material_dst->preview = nullptr;
127 }
128
129 if (material_src->texpaintslot != nullptr) {
130 /* TODO: Think we can also skip copying this data in the more generic `NO_MAIN` case? */
131 material_dst->texpaintslot = is_localized ? nullptr :
132 static_cast<TexPaintSlot *>(
133 MEM_dupallocN(material_src->texpaintslot));
134 }
135
136 if (material_src->gp_style != nullptr) {
137 material_dst->gp_style = static_cast<MaterialGPencilStyle *>(
138 MEM_dupallocN(material_src->gp_style));
139 }
140
141 BLI_listbase_clear(&material_dst->gpumaterial);
142
143 /* TODO: Duplicate Engine Settings and set runtime to nullptr. */
144}
145
146static void material_free_data(ID *id)
147{
148 Material *material = (Material *)id;
149
150 /* Free gpu material before the ntree */
151 GPU_material_free(&material->gpumaterial);
152
153 /* is no lib link block, but material extension */
154 if (material->nodetree) {
156 MEM_freeN(material->nodetree);
157 material->nodetree = nullptr;
158 }
159
160 MEM_SAFE_FREE(material->texpaintslot);
161
162 MEM_SAFE_FREE(material->gp_style);
163
164 BKE_previewimg_free(&material->preview);
165
166 BKE_icon_id_delete((ID *)material);
167}
168
170{
171 Material *material = reinterpret_cast<Material *>(id);
172
173 /* Node-trees **are owned by IDs**, treat them as mere sub-data and not real ID! */
176 if (material->texpaintslot != nullptr) {
178 }
179 if (material->gp_style != nullptr) {
182 }
183}
184
187{
188 Material *material = reinterpret_cast<Material *>(id);
189
190 fn.single(&material->r);
191 fn.single(&material->specr);
192 fn.single(material->line_col);
193
194 if (material->gp_style) {
195 fn.single(material->gp_style->stroke_rgba);
196 fn.single(material->gp_style->fill_rgba);
197 fn.single(material->gp_style->mix_rgba);
198 }
199}
200
201static void material_blend_write(BlendWriter *writer, ID *id, const void *id_address)
202{
203 Material *ma = (Material *)id;
204
205 /* Clean up, important in undo case to reduce false detection of changed datablocks. */
206 ma->texpaintslot = nullptr;
208
209 /* Set deprecated #use_nodes for forward compatibility. */
210 ma->use_nodes = true;
211
212 /* write LibData */
213 BLO_write_id_struct(writer, Material, id_address, &ma->id);
214 BKE_id_blend_write(writer, &ma->id);
215
216 /* nodetree is integral part of material, no libdata */
217 if (ma->nodetree) {
218 BLO_Write_IDBuffer temp_embedded_id_buffer{ma->nodetree->id, writer};
219 BLO_write_struct_at_address(writer, bNodeTree, ma->nodetree, temp_embedded_id_buffer.get());
221 writer, reinterpret_cast<bNodeTree *>(temp_embedded_id_buffer.get()));
222 }
223
225
226 /* grease pencil settings */
227 if (ma->gp_style) {
229 }
230}
231
233{
234 Material *ma = (Material *)id;
235
236 ma->texpaintslot = nullptr;
237
238 BLO_read_struct(reader, PreviewImage, &ma->preview);
240
242
244}
245
247 /*id_code*/ Material::id_type,
248 /*id_filter*/ FILTER_ID_MA,
249 /*dependencies_id_types*/ FILTER_ID_TE | FILTER_ID_GR,
250 /*main_listbase_index*/ INDEX_ID_MA,
251 /*struct_size*/ sizeof(Material),
252 /*name*/ "Material",
253 /*name_plural*/ N_("materials"),
254 /*translation_context*/ BLT_I18NCONTEXT_ID_MATERIAL,
256 /*asset_type_info*/ nullptr,
257
258 /*init_data*/ material_init_data,
259 /*copy_data*/ material_copy_data,
260 /*free_data*/ material_free_data,
261 /*make_local*/ nullptr,
262 /*foreach_id*/ material_foreach_id,
263 /*foreach_cache*/ nullptr,
264 /*foreach_path*/ nullptr,
265 /*foreach_working_space_color*/ material_foreach_working_space_color,
266 /*owner_pointer_get*/ nullptr,
267
268 /*blend_write*/ material_blend_write,
269 /*blend_read_data*/ material_blend_read_data,
270 /*blend_read_after_liblink*/ nullptr,
271
272 /*blend_read_undo_preserve*/ nullptr,
273
274 /*lib_override_apply_post*/ nullptr,
275};
276
278{
279 if ((ma) && (ma->gp_style == nullptr)) {
280 ma->gp_style = MEM_callocN<MaterialGPencilStyle>("Grease Pencil Material Settings");
281
282 MaterialGPencilStyle *gp_style = ma->gp_style;
283 /* set basic settings */
284 gp_style->stroke_rgba[3] = 1.0f;
285 gp_style->fill_rgba[3] = 1.0f;
286 ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 1.0f);
287 ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
288 gp_style->texture_offset[0] = -0.5f;
289 gp_style->texture_pixsize = 100.0f;
290 gp_style->mix_factor = 0.5f;
291
292 gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
293 }
294}
295
297{
298 if (tree == nullptr) {
299 return;
300 }
301 tree->runtime->previews_refresh_state++;
302 for (bNode *node : tree->all_nodes()) {
303 if (node->is_group()) {
304 bNodeTree *nested_tree = reinterpret_cast<bNodeTree *>(node->id);
306 }
307 }
308}
309
316
317Material *BKE_material_add(Main *bmain, const char *name)
318{
319 Material *ma;
320
321 ma = BKE_id_new<Material>(bmain, name);
322
323 return ma;
324}
325
327{
328 Material *ma;
329
330 ma = BKE_material_add(bmain, name);
331
332 /* grease pencil settings */
333 if (ma != nullptr) {
335 }
336 return ma;
337}
338
340{
341 if (ob->type == OB_MESH) {
342 Mesh *mesh = static_cast<Mesh *>(ob->data);
343 return &(mesh->mat);
344 }
346 Curve *cu = static_cast<Curve *>(ob->data);
347 return &(cu->mat);
348 }
349 if (ob->type == OB_MBALL) {
350 MetaBall *mb = static_cast<MetaBall *>(ob->data);
351 return &(mb->mat);
352 }
353 if (ob->type == OB_CURVES) {
354 Curves *curves = static_cast<Curves *>(ob->data);
355 return &(curves->mat);
356 }
357 if (ob->type == OB_POINTCLOUD) {
358 PointCloud *pointcloud = static_cast<PointCloud *>(ob->data);
359 return &(pointcloud->mat);
360 }
361 if (ob->type == OB_VOLUME) {
362 Volume *volume = static_cast<Volume *>(ob->data);
363 return &(volume->mat);
364 }
365 if (ob->type == OB_GREASE_PENCIL) {
366 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
367 return &(grease_pencil->material_array);
368 }
369 return nullptr;
370}
371
373{
374 if (ob->type == OB_MESH) {
375 Mesh *mesh = static_cast<Mesh *>(ob->data);
376 return &(mesh->totcol);
377 }
379 Curve *cu = static_cast<Curve *>(ob->data);
380 return &(cu->totcol);
381 }
382 if (ob->type == OB_MBALL) {
383 MetaBall *mb = static_cast<MetaBall *>(ob->data);
384 return &(mb->totcol);
385 }
386 if (ob->type == OB_CURVES) {
387 Curves *curves = static_cast<Curves *>(ob->data);
388 return &(curves->totcol);
389 }
390 if (ob->type == OB_POINTCLOUD) {
391 PointCloud *pointcloud = static_cast<PointCloud *>(ob->data);
392 return &(pointcloud->totcol);
393 }
394 if (ob->type == OB_VOLUME) {
395 Volume *volume = static_cast<Volume *>(ob->data);
396 return &(volume->totcol);
397 }
398 if (ob->type == OB_GREASE_PENCIL) {
399 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
400 return &(grease_pencil->material_array_num);
401 }
402 return nullptr;
403}
404
406{
407 /* ensure we don't try get materials from non-obdata */
409
410 switch (GS(id->name)) {
411 case ID_ME:
412 return &(((Mesh *)id)->mat);
413 case ID_CU_LEGACY:
414 return &(((Curve *)id)->mat);
415 case ID_MB:
416 return &(((MetaBall *)id)->mat);
417 case ID_GD_LEGACY:
418 return &(((bGPdata *)id)->mat);
419 case ID_CV:
420 return &(((Curves *)id)->mat);
421 case ID_PT:
422 return &(((PointCloud *)id)->mat);
423 case ID_VO:
424 return &(((Volume *)id)->mat);
425 case ID_GP:
426 return &(((GreasePencil *)id)->material_array);
427 default:
428 break;
429 }
430 return nullptr;
431}
432
434{
435 /* ensure we don't try get materials from non-obdata */
437
438 switch (GS(id->name)) {
439 case ID_ME:
440 return &(((Mesh *)id)->totcol);
441 case ID_CU_LEGACY:
442 return &(((Curve *)id)->totcol);
443 case ID_MB:
444 return &(((MetaBall *)id)->totcol);
445 case ID_GD_LEGACY:
446 return &(((bGPdata *)id)->totcol);
447 case ID_CV:
448 return &(((Curves *)id)->totcol);
449 case ID_PT:
450 return &(((PointCloud *)id)->totcol);
451 case ID_VO:
452 return &(((Volume *)id)->totcol);
453 case ID_GP:
454 return &(((GreasePencil *)id)->material_array_num);
455 default:
456 break;
457 }
458 return nullptr;
459}
460
461static void material_data_index_remove_id(ID *id, short index)
462{
463 /* ensure we don't try get materials from non-obdata */
465
466 switch (GS(id->name)) {
467 case ID_ME:
469 break;
470 case ID_CU_LEGACY:
472 break;
473 case ID_GP:
474 BKE_grease_pencil_material_index_remove(reinterpret_cast<GreasePencil *>(id), index);
475 break;
476 case ID_MB:
477 case ID_CV:
478 case ID_PT:
479 case ID_VO:
480 /* No material indices for these object data types. */
481 break;
482 default:
483 break;
484 }
485}
486
487bool BKE_object_material_slot_used(Object *object, short actcol)
488{
490 return false;
491 }
492
494 if (psys->part->omat == actcol) {
495 return true;
496 }
497 }
498
499 ID *ob_data = static_cast<ID *>(object->data);
500 if (ob_data == nullptr || !OB_DATA_SUPPORT_ID(GS(ob_data->name))) {
501 return false;
502 }
503
504 switch (GS(ob_data->name)) {
505 case ID_ME:
506 return BKE_mesh_material_index_used((Mesh *)ob_data, actcol - 1);
507 case ID_CU_LEGACY:
508 return BKE_curve_material_index_used((Curve *)ob_data, actcol - 1);
509 case ID_MB:
510 /* Meta-elements don't support materials at the moment. */
511 return false;
512 case ID_GP:
513 return BKE_grease_pencil_material_index_used(reinterpret_cast<GreasePencil *>(ob_data),
514 actcol - 1);
515 default:
516 return false;
517 }
518}
519
521{
522 /* ensure we don't try get materials from non-obdata */
524
525 switch (GS(id->name)) {
526 case ID_ME:
528 break;
529 case ID_CU_LEGACY:
531 break;
532 case ID_MB:
533 case ID_CV:
534 case ID_PT:
535 case ID_VO:
536 /* No material indices for these object data types. */
537 break;
538 default:
539 break;
540 }
541}
542
543void BKE_id_materials_copy(Main *bmain, ID *id_src, ID *id_dst)
544{
545 Material ***matar_src = BKE_id_material_array_p(id_src);
546 const short *materials_len_p_src = BKE_id_material_len_p(id_src);
547
548 Material ***matar_dst = BKE_id_material_array_p(id_dst);
549 short *materials_len_p_dst = BKE_id_material_len_p(id_dst);
550
551 *materials_len_p_dst = *materials_len_p_src;
552 if (*materials_len_p_src != 0) {
553 (*matar_dst) = static_cast<Material **>(MEM_dupallocN(*matar_src));
554
555 for (int a = 0; a < *materials_len_p_src; a++) {
556 id_us_plus((ID *)(*matar_dst)[a]);
557 }
558
561 }
562}
563
564void BKE_id_material_resize(Main *bmain, ID *id, short totcol, bool do_id_user)
565{
566 Material ***matar = BKE_id_material_array_p(id);
567 short *totcolp = BKE_id_material_len_p(id);
568
569 if (matar == nullptr) {
570 return;
571 }
572 if (totcol == *totcolp) {
573 /* Prevent depsgraph update and relations tag when nothing changed. */
574 return;
575 }
576
577 if (do_id_user && totcol < (*totcolp)) {
578 short i;
579 for (i = totcol; i < (*totcolp); i++) {
580 id_us_min((ID *)(*matar)[i]);
581 }
582 }
583
584 if (totcol == 0) {
585 if (*totcolp) {
586 MEM_freeN(*matar);
587 *matar = nullptr;
588 }
589 }
590 else {
591 *matar = static_cast<Material **>(MEM_recallocN(*matar, sizeof(void *) * totcol));
592 }
593 *totcolp = totcol;
594
597}
598
600{
601 Material ***matar = BKE_id_material_array_p(id);
602 if (matar) {
603 short *totcol = BKE_id_material_len_p(id);
604 Material **mat = MEM_calloc_arrayN<Material *>((*totcol) + 1, "newmatar");
605 if (*totcol) {
606 memcpy(mat, *matar, sizeof(void *) * (*totcol));
607 }
608 if (*matar) {
609 MEM_freeN(*matar);
610 }
611
612 *matar = mat;
613 (*matar)[(*totcol)++] = ma;
614
615 id_us_plus((ID *)ma);
617
620 }
621}
622
623Material *BKE_id_material_pop(Main *bmain, ID *id, int index_i)
624{
625 short index = short(index_i);
626 Material *ret = nullptr;
627 Material ***matar = BKE_id_material_array_p(id);
628 if (matar) {
629 short *totcol = BKE_id_material_len_p(id);
630 if (index >= 0 && index < (*totcol)) {
631 ret = (*matar)[index];
632 id_us_min((ID *)ret);
633
634 if (*totcol <= 1) {
635 *totcol = 0;
636 MEM_freeN(*matar);
637 *matar = nullptr;
638 }
639 else {
640 if (index + 1 != (*totcol)) {
641 memmove((*matar) + index,
642 (*matar) + (index + 1),
643 sizeof(void *) * ((*totcol) - (index + 1)));
644 }
645
646 (*totcol)--;
647 *matar = static_cast<Material **>(MEM_reallocN(*matar, sizeof(void *) * (*totcol)));
649 }
650
652
655 }
656 }
657
658 return ret;
659}
660
662{
663 Material ***matar = BKE_id_material_array_p(id);
664 if (matar) {
665 short *totcol = BKE_id_material_len_p(id);
666
667 while ((*totcol)--) {
668 id_us_min((ID *)((*matar)[*totcol]));
669 }
670 *totcol = 0;
671 if (*matar) {
672 MEM_freeN(*matar);
673 *matar = nullptr;
674 }
675
678
681 }
682}
683
685{
686 Material ***matarar, **ma_p;
687 const short *totcolp;
688
689 if (ob == nullptr) {
690 return nullptr;
691 }
692
693 /* if object cannot have material, (totcolp == nullptr) */
694 totcolp = BKE_object_material_len_p(ob);
695 if (totcolp == nullptr || *totcolp == 0) {
696 return nullptr;
697 }
698
699 /* Clamp to number of slots if index is out of range, same convention as used for rendering. */
700 const int slot_index = clamp_i(act - 1, 0, *totcolp - 1);
701
702 /* Fix inconsistency which may happen when library linked data reduces the number of
703 * slots but object was not updated. Ideally should be fixed elsewhere. */
704 ob->totcol = std::min<int>(*totcolp, ob->totcol);
705
706 if (slot_index < ob->totcol && ob->matbits && ob->matbits[slot_index]) {
707 /* Use object material slot. */
708 ma_p = &ob->mat[slot_index];
709 }
710 else {
711 /* Use data material slot. */
712 matarar = BKE_object_material_array_p(ob);
713
714 if (matarar && *matarar) {
715 ma_p = &(*matarar)[slot_index];
716 }
717 else {
718 ma_p = nullptr;
719 }
720 }
721
722 return ma_p;
723}
724
726{
727 Material **ma_p = BKE_object_material_get_p(ob, act);
728 /* Grease Pencil objects currently make the assumption that the returned material has Grease
729 * Pencil settings. Ensure that this is the case otherwise return `nullptr`. */
730 if (ob->type == OB_GREASE_PENCIL && ma_p != nullptr) {
731 Material *ma = *ma_p;
732 if (ma != nullptr) {
733 return ma->gp_style != nullptr ? ma : nullptr;
734 }
735 }
736 return ma_p ? *ma_p : nullptr;
737}
738
740{
741 const ID *data = static_cast<ID *>(ob->data);
742 /* Meshes in edit mode need special handling. */
743 if (ob->type == OB_MESH && ob->mode == OB_MODE_EDIT) {
744 const Mesh *mesh = static_cast<const Mesh *>(ob->data);
745 const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
746 if (mesh->runtime->edit_mesh && editmesh_eval_final) {
747 data = &editmesh_eval_final->id;
748 }
749 }
750 return data;
751}
752
754{
756 return const_cast<Material *>(BKE_object_material_get_eval(*ob, *data, act));
757}
758
759const Material *BKE_object_material_get_eval(const Object &ob, const ID &data, const short act)
760{
762
763 const int slots_num = BKE_object_material_count_eval(ob, data);
764
765 if (slots_num == 0) {
766 return nullptr;
767 }
768
769 /* Clamp to number of slots if index is out of range, same convention as used for rendering. */
770 const int slot_index = clamp_i(act - 1, 0, slots_num - 1);
771 const int tot_slots_object = ob.totcol;
772
773 /* Check if slot is overwritten by object. */
774 if (slot_index < tot_slots_object) {
775 if (ob.matbits) {
776 if (ob.matbits[slot_index]) {
777 Material *material = ob.mat[slot_index];
778 if (material != nullptr) {
779 return material;
780 }
781 }
782 }
783 }
784
785 /* Otherwise use data from object-data. */
786 const short *data_slots_num_ptr = BKE_id_material_len_p(const_cast<ID *>(&data));
787 if (!data_slots_num_ptr) {
788 return nullptr;
789 }
790 const int data_slots_num = *data_slots_num_ptr;
791 Material **data_materials = *BKE_id_material_array_p(const_cast<ID *>(&data));
792 if (slot_index < data_slots_num) {
793 Material *material = data_materials[slot_index];
794 return material;
795 }
796 return nullptr;
797}
798
800{
802 if (ob->type == OB_EMPTY) {
803 return 0;
804 }
805 BLI_assert(ob->data != nullptr);
806 const ID *id = get_evaluated_object_data_with_materials(const_cast<Object *>(ob));
807 const short *len_p = BKE_id_material_len_p(const_cast<ID *>(id));
808 return std::max(ob->totcol, len_p ? *len_p : 0);
809}
810
812{
814 if (ob.type == OB_EMPTY) {
815 return 0;
816 }
817 BLI_assert(ob.data != nullptr);
818 const short *len_p = BKE_id_material_len_p(const_cast<ID *>(&data));
819 return std::max(ob.totcol, len_p ? *len_p : 0);
820}
821
822std::optional<int> BKE_id_material_index_max_eval(const ID &id)
823{
824 switch (GS(id.name)) {
825 case ID_ME:
826 return reinterpret_cast<const Mesh &>(id).material_index_max();
827 case ID_CU_LEGACY:
828 return reinterpret_cast<const Curve &>(id).material_index_max();
829 case ID_CV:
830 return reinterpret_cast<const Curves &>(id).geometry.wrap().material_index_max();
831 case ID_PT:
832 return reinterpret_cast<const PointCloud &>(id).material_index_max();
833 case ID_GP:
834 return reinterpret_cast<const GreasePencil &>(id).material_index_max_eval();
835 case ID_VO:
836 case ID_MB:
837 /* Always use the first material. */
838 return 0;
839 case ID_GD_LEGACY:
840 /* Is not rendered anymore. */
842 return 0;
843 default:
844 break;
845 }
846 return 0;
847}
848
850{
851 if (std::optional<int> max_index = BKE_id_material_index_max_eval(id)) {
852 return *max_index + 1;
853 }
854 return 0;
855}
856
858{
859 const int max_material_index = std::max(0, BKE_id_material_index_max_eval(id).value_or(0));
860 return max_material_index + 1;
861}
862
868
869void BKE_id_material_eval_assign(ID *id, int slot, Material *material)
870{
871 BLI_assert(slot >= 1);
872 Material ***materials_ptr = BKE_id_material_array_p(id);
873 short *len_ptr = BKE_id_material_len_p(id);
874 if (ELEM(nullptr, materials_ptr, len_ptr)) {
876 return;
877 }
878
879 const int slot_index = slot - 1;
880 const int old_length = *len_ptr;
881
882 if (slot_index >= old_length) {
883 /* Need to grow slots array. */
884 const int new_length = slot_index + 1;
885 *materials_ptr = static_cast<Material **>(
886 MEM_reallocN(*materials_ptr, sizeof(void *) * new_length));
887 *len_ptr = new_length;
888 for (int i = old_length; i < new_length; i++) {
889 (*materials_ptr)[i] = nullptr;
890 }
891 }
892
893 (*materials_ptr)[slot_index] = material;
894}
895
897{
898 short *len_ptr = BKE_id_material_len_p(id);
899 if (len_ptr == nullptr) {
900 return;
901 }
902 if (*len_ptr == 0) {
903 BKE_id_material_eval_assign(id, 1, nullptr);
904 }
905}
906
908{
909 short *totcol = BKE_object_material_len_p(ob);
910 Material *read_ma = nullptr;
911 for (short i = 0; i < *totcol; i++) {
912 read_ma = BKE_object_material_get(ob, i + 1);
913 if (ma == read_ma) {
914 return i;
915 }
916 }
917 return -1;
918}
919
920int BKE_object_material_index_get_with_hint(Object *ob, const Material *ma, const int hint_index)
921{
922 short *totcol = BKE_object_material_len_p(ob);
923 if ((hint_index >= 0) && (hint_index < *totcol)) {
924 if (ma == BKE_object_material_get(ob, hint_index + 1)) {
925 return hint_index;
926 }
927 }
928 return BKE_object_material_index_get(ob, ma);
929}
930
932{
933 if (!material) {
934 return -1;
935 }
936 int index = BKE_object_material_index_get(ob, material);
937 if (index < 0) {
940 return ob->totcol - 1;
941 }
942 return index;
943}
944
946{
947 Material *ma = BKE_object_material_get(ob, act);
948 if (ma != nullptr) {
949 return ma;
950 }
951
952 /* XXX FIXME This is critical abuse of the 'default material' feature, these IDs should never be
953 * used/returned as 'regular' data. */
955}
956
958{
959 Material *ma = BKE_object_material_get(ob, act);
960 if (ma != nullptr) {
961 if (ma->gp_style == nullptr) {
963 }
964
965 return ma->gp_style;
966 }
967
969}
970
977{
978 if (ob->totcol && ob->actcol == 0) {
979 ob->actcol = 1;
980 }
981 ob->actcol = std::min(ob->actcol, ob->totcol);
982}
983
984void BKE_object_material_resize(Main *bmain, Object *ob, const short totcol, bool do_id_user)
985{
986 if (totcol == ob->totcol) {
987 /* Prevent depsgraph update and relations tag when nothing changed. */
988 return;
989 }
990
991 Material **newmatar;
992 char *newmatbits;
993
994 if (do_id_user && totcol < ob->totcol) {
995 for (int i = totcol; i < ob->totcol; i++) {
996 id_us_min((ID *)ob->mat[i]);
997 }
998 }
999
1000 if (totcol == 0) {
1001 if (ob->totcol) {
1002 MEM_freeN(ob->mat);
1003 MEM_freeN(ob->matbits);
1004 ob->mat = nullptr;
1005 ob->matbits = nullptr;
1006 }
1007 }
1008 else if (ob->totcol < totcol) {
1009 newmatar = MEM_calloc_arrayN<Material *>(totcol, "newmatar");
1010 newmatbits = MEM_calloc_arrayN<char>(totcol, "newmatbits");
1011 if (ob->totcol) {
1012 memcpy(newmatar, ob->mat, sizeof(void *) * ob->totcol);
1013 memcpy(newmatbits, ob->matbits, sizeof(char) * ob->totcol);
1014 MEM_freeN(ob->mat);
1015 MEM_freeN(ob->matbits);
1016 }
1017 ob->mat = newmatar;
1018 ob->matbits = newmatbits;
1019 }
1020 /* XXX(@ideasman42): why not realloc on shrink? */
1021
1022 ob->totcol = totcol;
1023
1026}
1027
1029{
1030 const short *totcol;
1031
1032 if (id == nullptr || (totcol = BKE_id_material_len_p(id)) == nullptr) {
1033 return;
1034 }
1035
1036 if ((ob->id.tag & ID_TAG_MISSING) == 0 && (id->tag & ID_TAG_MISSING) != 0) {
1037 /* Exception: In case the object is a valid data, but its obdata is an empty place-holder,
1038 * use object's material slots amount as reference.
1039 * This avoids losing materials in a local object when its linked obdata goes missing.
1040 * See #92780. */
1041 BKE_id_material_resize(bmain, id, short(ob->totcol), false);
1042 }
1043 else {
1044 /* Normal case: the use the obdata amount of materials slots to update the object's one. */
1045 BKE_object_material_resize(bmain, ob, *totcol, false);
1047 }
1048}
1049
1051{
1052 Object *ob;
1053 const short *totcol;
1054
1055 if (id == nullptr || (totcol = BKE_id_material_len_p(id)) == nullptr) {
1056 return;
1057 }
1058
1059 BKE_main_lock(bmain);
1060 int processed_objects = 0;
1061 for (ob = static_cast<Object *>(bmain->objects.first); ob;
1062 ob = static_cast<Object *>(ob->id.next))
1063 {
1064 if (ob->data == id) {
1065 BKE_object_material_resize(bmain, ob, *totcol, false);
1067 processed_objects++;
1068 BLI_assert(processed_objects <= id->us && processed_objects > 0);
1069 if (processed_objects == id->us) {
1070 break;
1071 }
1072 }
1073 }
1074 BKE_main_unlock(bmain);
1075}
1076
1077void BKE_id_material_assign(Main *bmain, ID *id, Material *ma, short act)
1078{
1079 Material *mao, **matar, ***matarar;
1080 short *totcolp;
1081
1082 if (act > MAXMAT) {
1083 return;
1084 }
1085 act = std::max<int>(act, 1);
1086
1087 /* test arraylens */
1088
1089 totcolp = BKE_id_material_len_p(id);
1090 matarar = BKE_id_material_array_p(id);
1091
1092 if (totcolp == nullptr || matarar == nullptr) {
1093 return;
1094 }
1095
1096 if (act > *totcolp) {
1097 matar = MEM_calloc_arrayN<Material *>(act, "matarray1");
1098
1099 if (*totcolp) {
1100 memcpy(matar, *matarar, sizeof(void *) * (*totcolp));
1101 MEM_freeN(*matarar);
1102 }
1103
1104 *matarar = matar;
1105 *totcolp = act;
1106 }
1107
1108 /* in data */
1109 mao = (*matarar)[act - 1];
1110 if (mao) {
1111 id_us_min(&mao->id);
1112 }
1113 (*matarar)[act - 1] = ma;
1114
1115 if (ma) {
1116 id_us_plus(&ma->id);
1117 }
1118
1122}
1123
1125 Main *bmain, Object *ob, Material *ma, short act, int assign_type, bool do_test_all)
1126{
1127 Material *mao, **matar, ***matarar;
1128 short *totcolp;
1129 char bit = 0;
1130
1131 if (act > MAXMAT) {
1132 return;
1133 }
1134 act = std::max<int>(act, 1);
1135
1136 /* test arraylens */
1137
1138 totcolp = BKE_object_material_len_p(ob);
1139 matarar = BKE_object_material_array_p(ob);
1140
1141 if (totcolp == nullptr || matarar == nullptr) {
1142 return;
1143 }
1144
1145 if (act > *totcolp) {
1146 matar = MEM_calloc_arrayN<Material *>(act, "matarray1");
1147
1148 if (*totcolp) {
1149 memcpy(matar, *matarar, sizeof(void *) * (*totcolp));
1150 MEM_freeN(*matarar);
1151 }
1152
1153 *matarar = matar;
1154 *totcolp = act;
1155 }
1156
1157 if (act > ob->totcol) {
1158 /* Need more space in the material arrays */
1159 ob->mat = static_cast<Material **>(
1160 MEM_recallocN_id(ob->mat, sizeof(void *) * act, "matarray2"));
1161 ob->matbits = static_cast<char *>(
1162 MEM_recallocN_id(ob->matbits, sizeof(char) * act, "matbits1"));
1163 ob->totcol = act;
1164 }
1165
1166 /* Determine the object/mesh linking */
1167 if (assign_type == BKE_MAT_ASSIGN_EXISTING) {
1168 /* keep existing option (avoid confusion in scripts),
1169 * intentionally ignore userpref (default to obdata). */
1170 bit = ob->matbits[act - 1];
1171 }
1172 else if (assign_type == BKE_MAT_ASSIGN_USERPREF && ob->totcol && ob->actcol) {
1173 /* copy from previous material */
1174 bit = ob->matbits[ob->actcol - 1];
1175 }
1176 else {
1177 switch (assign_type) {
1179 bit = 0;
1180 break;
1182 bit = 1;
1183 break;
1185 default:
1186 bit = (U.flag & USER_MAT_ON_OB) ? 1 : 0;
1187 break;
1188 }
1189 }
1190
1191 /* do it */
1192
1193 ob->matbits[act - 1] = bit;
1194 if (bit == 1) { /* in object */
1195 mao = ob->mat[act - 1];
1196 if (mao) {
1197 id_us_min(&mao->id);
1198 }
1199 ob->mat[act - 1] = ma;
1200 BKE_object_materials_sync_length(bmain, ob, static_cast<ID *>(ob->data));
1201 }
1202 else { /* in data */
1203 mao = (*matarar)[act - 1];
1204 if (mao) {
1205 id_us_min(&mao->id);
1206 }
1207 (*matarar)[act - 1] = ma;
1208 /* Data may be used by several objects. */
1209 if (do_test_all) {
1210 BKE_objects_materials_sync_length_all(bmain, static_cast<ID *>(ob->data));
1211 }
1212 }
1213
1214 if (ma) {
1215 id_us_plus(&ma->id);
1216 }
1217
1220}
1221
1222void BKE_object_material_assign(Main *bmain, Object *ob, Material *ma, short act, int assign_type)
1223{
1224 object_material_assign(bmain, ob, ma, act, assign_type, true);
1225}
1226
1228{
1229 object_material_assign(bmain, ob, ma, act, BKE_MAT_ASSIGN_OBDATA, false);
1230}
1231
1233{
1235 const short *totcol_p = BKE_object_material_len_p(ob);
1236
1237 BLI_array_permute(ob->mat, ob->totcol, remap);
1238
1239 if (ob->matbits) {
1240 BLI_array_permute(ob->matbits, ob->totcol, remap);
1241 }
1242
1243 if (matar) {
1244 BLI_array_permute(*matar, *totcol_p, remap);
1245 }
1246
1247 if (ob->type == OB_MESH) {
1248 BKE_mesh_material_remap(static_cast<Mesh *>(ob->data), remap, ob->totcol);
1249 }
1250 else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
1251 BKE_curve_material_remap(static_cast<Curve *>(ob->data), remap, ob->totcol);
1252 }
1253 else if (ob->type == OB_GREASE_PENCIL) {
1254 BKE_grease_pencil_material_remap(static_cast<GreasePencil *>(ob->data), remap, ob->totcol);
1255 }
1256 else {
1257 /* add support for this object data! */
1258 BLI_assert(matar == nullptr);
1259 }
1260}
1261
1262void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap_src_to_dst)
1263{
1264 if (ob_src->totcol == 0) {
1265 return;
1266 }
1267
1268 GHash *gh_mat_map = BLI_ghash_ptr_new_ex(__func__, ob_src->totcol);
1269
1270 for (int i = 0; i < ob_dst->totcol; i++) {
1271 Material *ma_src = BKE_object_material_get(ob_dst, i + 1);
1272 BLI_ghash_reinsert(gh_mat_map, ma_src, POINTER_FROM_INT(i), nullptr, nullptr);
1273 }
1274
1275 /* setup default mapping (when materials don't match) */
1276 {
1277 int i = 0;
1278 if (ob_dst->totcol >= ob_src->totcol) {
1279 for (; i < ob_src->totcol; i++) {
1280 remap_src_to_dst[i] = i;
1281 }
1282 }
1283 else {
1284 for (; i < ob_dst->totcol; i++) {
1285 remap_src_to_dst[i] = i;
1286 }
1287 for (; i < ob_src->totcol; i++) {
1288 remap_src_to_dst[i] = 0;
1289 }
1290 }
1291 }
1292
1293 for (int i = 0; i < ob_src->totcol; i++) {
1294 Material *ma_src = BKE_object_material_get(ob_src, i + 1);
1295
1296 if ((i < ob_dst->totcol) && (ma_src == BKE_object_material_get(ob_dst, i + 1))) {
1297 /* when objects have exact matching materials - keep existing index */
1298 }
1299 else {
1300 void **index_src_p = BLI_ghash_lookup_p(gh_mat_map, ma_src);
1301 if (index_src_p) {
1302 remap_src_to_dst[i] = POINTER_AS_INT(*index_src_p);
1303 }
1304 }
1305 }
1306
1307 BLI_ghash_free(gh_mat_map, nullptr, nullptr);
1308}
1309
1310void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, const ID *data_eval)
1311{
1312 ID *data_orig = static_cast<ID *>(ob_orig->data);
1313
1314 short *orig_totcol = BKE_id_material_len_p(data_orig);
1315 Material ***orig_mat = BKE_id_material_array_p(data_orig);
1316
1317 /* Can cast away const, because the data is not changed. */
1318 const short *eval_totcol = BKE_id_material_len_p((ID *)data_eval);
1319 Material ***eval_mat = BKE_id_material_array_p((ID *)data_eval);
1320
1321 if (ELEM(nullptr, orig_totcol, orig_mat, eval_totcol, eval_mat)) {
1322 return;
1323 }
1324
1325 /* Remove old materials from original geometry. */
1326 for (int i = 0; i < *orig_totcol; i++) {
1327 id_us_min(&(*orig_mat)[i]->id);
1328 }
1329 MEM_SAFE_FREE(*orig_mat);
1330
1331 /* Create new material slots based on materials on evaluated geometry. */
1332 *orig_totcol = *eval_totcol;
1333 *orig_mat = *eval_totcol > 0 ? MEM_calloc_arrayN<Material *>(*eval_totcol, __func__) : nullptr;
1334 for (int i = 0; i < *eval_totcol; i++) {
1335 Material *material_eval = (*eval_mat)[i];
1336 if (material_eval != nullptr) {
1337 Material *material_orig = DEG_get_original(material_eval);
1338 (*orig_mat)[i] = material_orig;
1339 id_us_plus(&material_orig->id);
1340 }
1341 }
1342 BKE_object_materials_sync_length(bmain, ob_orig, data_orig);
1343}
1344
1346 Main *bmain, Object *ob, Material ***matar, int totcol, const bool to_object_only)
1347{
1348 int actcol_orig = ob->actcol;
1349
1350 while ((ob->totcol > totcol) && BKE_object_material_slot_remove(bmain, ob)) {
1351 /* pass */
1352 }
1353
1354 /* now we have the right number of slots */
1355 for (int i = 0; i < totcol; i++) {
1356 if (to_object_only && ob->matbits && ob->matbits[i] == 0) {
1357 /* If we only assign to object, and that slot uses obdata material, do nothing. */
1358 continue;
1359 }
1361 ob,
1362 (*matar)[i],
1363 i + 1,
1365 }
1366
1367 actcol_orig = std::min(actcol_orig, ob->totcol);
1368
1369 ob->actcol = actcol_orig;
1370}
1371
1373{
1374 Material ***matarar;
1375 short a, *totcolp;
1376
1377 if (ma == nullptr) {
1378 return 0;
1379 }
1380
1381 totcolp = BKE_object_material_len_p(ob);
1382 matarar = BKE_object_material_array_p(ob);
1383
1384 if (totcolp == nullptr || matarar == nullptr) {
1385 return 0;
1386 }
1387
1388 for (a = 0; a < *totcolp; a++) {
1389 if ((*matarar)[a] == ma) {
1390 break;
1391 }
1392 }
1393 if (a < *totcolp) {
1394 return a + 1;
1395 }
1396 return 0;
1397}
1398
1399bool BKE_object_material_slot_add(Main *bmain, Object *ob, const bool set_active)
1400{
1401 if (ob == nullptr) {
1402 return false;
1403 }
1404 if (ob->totcol >= MAXMAT) {
1405 return false;
1406 }
1407
1408 BKE_object_material_assign(bmain, ob, nullptr, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
1409 if (set_active) {
1410 ob->actcol = ob->totcol;
1411 }
1412 return true;
1413}
1414
1415/* ****************** */
1416
1418{
1419 Material *mao, ***matarar;
1420 short *totcolp;
1421
1422 if (ob == nullptr || ob->totcol == 0) {
1423 return false;
1424 }
1425
1426 /* this should never happen and used to crash */
1427 if (ob->actcol <= 0) {
1428 CLOG_ERROR(&LOG, "invalid material index %d, report a bug!", ob->actcol);
1429 return false;
1430 }
1431
1432 /* Take a mesh/curve/meta-ball as starting point, remove 1 index,
1433 * AND with all objects that share the `ob->data`.
1434 * After that check indices in mesh/curve/meta-ball! */
1435
1436 totcolp = BKE_object_material_len_p(ob);
1437 matarar = BKE_object_material_array_p(ob);
1438
1439 if (ELEM(nullptr, matarar, *matarar)) {
1440 return false;
1441 }
1442
1443 /* can happen on face selection in editmode */
1445
1446 /* we delete the actcol */
1447 mao = (*matarar)[ob->actcol - 1];
1448 if (mao) {
1449 id_us_min(&mao->id);
1450 }
1451
1452 for (int a = ob->actcol; a < ob->totcol; a++) {
1453 (*matarar)[a - 1] = (*matarar)[a];
1454 }
1455 (*totcolp)--;
1456
1457 if (*totcolp == 0) {
1458 MEM_freeN(*matarar);
1459 *matarar = nullptr;
1460 }
1461
1462 const int actcol = ob->actcol;
1463
1464 for (Object *obt = static_cast<Object *>(bmain->objects.first); obt;
1465 obt = static_cast<Object *>(obt->id.next))
1466 {
1467 if (obt->data == ob->data) {
1468 /* Can happen when object material lists are used, see: #52953 */
1469 if (actcol > obt->totcol) {
1470 continue;
1471 }
1472 /* WATCH IT: do not use actcol from ob or from obt (can become zero) */
1473 mao = obt->mat[actcol - 1];
1474 if (mao) {
1475 id_us_min(&mao->id);
1476 }
1477
1478 for (int a = actcol; a < obt->totcol; a++) {
1479 obt->mat[a - 1] = obt->mat[a];
1480 obt->matbits[a - 1] = obt->matbits[a];
1481 }
1482 obt->totcol--;
1484
1485 if (obt->totcol == 0) {
1486 MEM_freeN(obt->mat);
1487 MEM_freeN(obt->matbits);
1488 obt->mat = nullptr;
1489 obt->matbits = nullptr;
1490 }
1491 }
1492 }
1493
1494 /* check indices from mesh and grease pencil. */
1496 material_data_index_remove_id((ID *)ob->data, actcol - 1);
1497 if (ob->runtime->curve_cache) {
1498 BKE_displist_free(&ob->runtime->curve_cache->disp);
1499 }
1500 }
1501
1502 return true;
1503}
1504
1506{
1507 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
1508 if (sock->link) {
1509 bNode *inode = sock->link->fromnode;
1510 if (inode->typeinfo->nclass == NODE_CLASS_INPUT &&
1511 inode->typeinfo->type_legacy == SH_NODE_UVMAP)
1512 {
1513 return inode;
1514 }
1515
1516 return nodetree_uv_node_recursive(inode);
1517 }
1518 }
1519
1520 return nullptr;
1521}
1522
1529
1530using ForEachTexNodeCallback = bool (*)(bNode *node, void *userdata);
1532 ForEachTexNodeCallback callback,
1533 void *userdata,
1534 ePaintSlotFilter slot_filter)
1535{
1536 const bool do_image_nodes = (slot_filter & PAINT_SLOT_IMAGE) != 0;
1537 const bool do_color_attributes = (slot_filter & PAINT_SLOT_COLOR_ATTRIBUTE) != 0;
1538 for (bNode *node : nodetree->all_nodes()) {
1539 if (do_image_nodes && node->typeinfo->nclass == NODE_CLASS_TEXTURE &&
1540 node->typeinfo->type_legacy == SH_NODE_TEX_IMAGE && node->id)
1541 {
1542 if (!callback(node, userdata)) {
1543 return false;
1544 }
1545 }
1546 if (do_color_attributes && node->typeinfo->type_legacy == SH_NODE_ATTRIBUTE) {
1547 if (!callback(node, userdata)) {
1548 return false;
1549 }
1550 }
1551 else if (node->is_group() && node->id) {
1552 /* recurse into the node group and see if it contains any textures */
1553 if (!ntree_foreach_texnode_recursive((bNodeTree *)node->id, callback, userdata, slot_filter))
1554 {
1555 return false;
1556 }
1557 }
1558 }
1559 return true;
1560}
1561
1562static bool count_texture_nodes_cb(bNode * /*node*/, void *userdata)
1563{
1564 (*((int *)userdata))++;
1565 return true;
1566}
1567
1569{
1570 int tex_nodes = 0;
1571 ntree_foreach_texnode_recursive(nodetree, count_texture_nodes_cb, &tex_nodes, slot_filter);
1572
1573 return tex_nodes;
1574}
1575
1583
1584static bool fill_texpaint_slots_cb(bNode *node, void *userdata)
1585{
1586 FillTexPaintSlotsData *fill_data = static_cast<FillTexPaintSlotsData *>(userdata);
1587
1588 Material *ma = fill_data->ma;
1589 int index = fill_data->index;
1590 fill_data->index++;
1591
1592 if (fill_data->active_node == node) {
1593 ma->paint_active_slot = index;
1594 }
1595
1596 switch (node->type_legacy) {
1597 case SH_NODE_TEX_IMAGE: {
1598 TexPaintSlot *slot = &ma->texpaintslot[index];
1599 slot->ima = (Image *)node->id;
1600 NodeTexImage *storage = (NodeTexImage *)node->storage;
1601 slot->interp = storage->interpolation;
1602 slot->image_user = &storage->iuser;
1603 /* For new renderer, we need to traverse the tree back in search of a UV node. */
1604 bNode *uvnode = nodetree_uv_node_recursive(node);
1605
1606 if (uvnode) {
1607 NodeShaderUVMap *uv_storage = (NodeShaderUVMap *)uvnode->storage;
1608 slot->uvname = uv_storage->uv_map;
1609 /* set a value to index so UI knows that we have a valid pointer for the mesh */
1610 slot->valid = true;
1611 }
1612 else {
1613 /* just invalidate the index here so UV map does not get displayed on the UI */
1614 slot->valid = false;
1615 }
1616 break;
1617 }
1618
1619 case SH_NODE_ATTRIBUTE: {
1620 TexPaintSlot *slot = &ma->texpaintslot[index];
1621 NodeShaderAttribute *storage = static_cast<NodeShaderAttribute *>(node->storage);
1622 slot->attribute_name = storage->name;
1623 if (storage->type == SHD_ATTRIBUTE_GEOMETRY) {
1624 const Mesh *mesh = (const Mesh *)fill_data->ob->data;
1625 const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name);
1626 slot->valid = layer != nullptr;
1627 }
1628
1629 /* Do not show unsupported attributes. */
1630 if (!slot->valid) {
1631 slot->attribute_name = nullptr;
1632 fill_data->index--;
1633 }
1634
1635 break;
1636 }
1637 }
1638
1639 return fill_data->index != fill_data->slot_len;
1640}
1641
1643 bNode *active_node,
1644 const Object *ob,
1645 Material *ma,
1646 int slot_len,
1647 ePaintSlotFilter slot_filter)
1648{
1649 FillTexPaintSlotsData fill_data = {active_node, ob, ma, 0, slot_len};
1650 ntree_foreach_texnode_recursive(nodetree, fill_texpaint_slots_cb, &fill_data, slot_filter);
1651}
1652
1655{
1656 ePaintSlotFilter slot_filter = PAINT_SLOT_IMAGE;
1657 if (ob->mode == OB_MODE_SCULPT && USER_EXPERIMENTAL_TEST(&U, use_sculpt_texture_paint)) {
1658 slot_filter |= PAINT_SLOT_COLOR_ATTRIBUTE;
1659 }
1660 return slot_filter;
1661}
1662
1664{
1665 if (!ma) {
1666 return;
1667 }
1668
1669 const ePaintSlotFilter slot_filter = material_paint_slot_filter(ob);
1670
1671 const TexPaintSlot *prev_texpaintslot = ma->texpaintslot;
1672 const int prev_paint_active_slot = ma->paint_active_slot;
1673 const int prev_paint_clone_slot = ma->paint_clone_slot;
1674 const int prev_tot_slots = ma->tot_slots;
1675
1676 ma->texpaintslot = nullptr;
1677 ma->tot_slots = 0;
1678
1680 ma->paint_active_slot = 0;
1681 ma->paint_clone_slot = 0;
1682 }
1683 else if (!(ma->nodetree)) {
1684 ma->paint_active_slot = 0;
1685 ma->paint_clone_slot = 0;
1686 }
1687 else {
1688 int count = count_texture_nodes_recursive(ma->nodetree, slot_filter);
1689
1690 if (count == 0) {
1691 ma->paint_active_slot = 0;
1692 ma->paint_clone_slot = 0;
1693 }
1694 else {
1695 ma->texpaintslot = MEM_calloc_arrayN<TexPaintSlot>(count, "texpaint_slots");
1696
1698
1699 fill_texpaint_slots_recursive(ma->nodetree, active_node, ob, ma, count, slot_filter);
1700
1701 ma->tot_slots = count;
1702
1703 if (ma->paint_active_slot >= count) {
1704 ma->paint_active_slot = count - 1;
1705 }
1706
1707 if (ma->paint_clone_slot >= count) {
1708 ma->paint_clone_slot = count - 1;
1709 }
1710 }
1711 }
1712
1713 /* Copy-on-eval needed when adding texture slot on an object with no materials.
1714 * But do it only when slots actually change to avoid continuous depsgraph updates. */
1715 if (ma->tot_slots != prev_tot_slots || ma->paint_active_slot != prev_paint_active_slot ||
1716 ma->paint_clone_slot != prev_paint_clone_slot ||
1717 (ma->texpaintslot && prev_texpaintslot &&
1718 memcmp(ma->texpaintslot, prev_texpaintslot, sizeof(*ma->texpaintslot) * ma->tot_slots) !=
1719 0))
1720 {
1722 }
1723
1724 MEM_SAFE_FREE(prev_texpaintslot);
1725}
1726
1728{
1729 for (int i = 1; i < ob->totcol + 1; i++) {
1731 BKE_texpaint_slot_refresh_cache(scene, ma, ob);
1732 }
1733}
1734
1739
1740static bool texpaint_slot_node_find_cb(bNode *node, void *userdata)
1741{
1742 FindTexPaintNodeData *find_data = static_cast<FindTexPaintNodeData *>(userdata);
1743 if (find_data->slot->ima && node->type_legacy == SH_NODE_TEX_IMAGE) {
1744 Image *node_ima = (Image *)node->id;
1745 if (find_data->slot->ima == node_ima) {
1746 find_data->r_node = node;
1747 return false;
1748 }
1749 }
1750
1751 if (find_data->slot->attribute_name && node->type_legacy == SH_NODE_ATTRIBUTE) {
1752 NodeShaderAttribute *storage = static_cast<NodeShaderAttribute *>(node->storage);
1753 if (STREQLEN(find_data->slot->attribute_name, storage->name, sizeof(storage->name))) {
1754 find_data->r_node = node;
1755 return false;
1756 }
1757 }
1758
1759 return true;
1760}
1761
1763{
1764 if (ma->texpaintslot == nullptr) {
1765 return nullptr;
1766 }
1767
1768 if (texpaint_slot >= ma->tot_slots) {
1769 return nullptr;
1770 }
1771
1772 TexPaintSlot *slot = &ma->texpaintslot[texpaint_slot];
1773 FindTexPaintNodeData find_data = {slot, nullptr};
1776 &find_data,
1778
1779 return find_data.r_node;
1780}
1781
1782void ramp_blend(int type, float r_col[3], const float fac, const float col[3])
1783{
1784 float tmp, facm = 1.0f - fac;
1785
1786 switch (type) {
1787 case MA_RAMP_BLEND:
1788 r_col[0] = facm * (r_col[0]) + fac * col[0];
1789 r_col[1] = facm * (r_col[1]) + fac * col[1];
1790 r_col[2] = facm * (r_col[2]) + fac * col[2];
1791 break;
1792 case MA_RAMP_ADD:
1793 r_col[0] += fac * col[0];
1794 r_col[1] += fac * col[1];
1795 r_col[2] += fac * col[2];
1796 break;
1797 case MA_RAMP_MULT:
1798 r_col[0] *= (facm + fac * col[0]);
1799 r_col[1] *= (facm + fac * col[1]);
1800 r_col[2] *= (facm + fac * col[2]);
1801 break;
1802 case MA_RAMP_SCREEN:
1803 r_col[0] = 1.0f - (facm + fac * (1.0f - col[0])) * (1.0f - r_col[0]);
1804 r_col[1] = 1.0f - (facm + fac * (1.0f - col[1])) * (1.0f - r_col[1]);
1805 r_col[2] = 1.0f - (facm + fac * (1.0f - col[2])) * (1.0f - r_col[2]);
1806 break;
1807 case MA_RAMP_OVERLAY:
1808 if (r_col[0] < 0.5f) {
1809 r_col[0] *= (facm + 2.0f * fac * col[0]);
1810 }
1811 else {
1812 r_col[0] = 1.0f - (facm + 2.0f * fac * (1.0f - col[0])) * (1.0f - r_col[0]);
1813 }
1814 if (r_col[1] < 0.5f) {
1815 r_col[1] *= (facm + 2.0f * fac * col[1]);
1816 }
1817 else {
1818 r_col[1] = 1.0f - (facm + 2.0f * fac * (1.0f - col[1])) * (1.0f - r_col[1]);
1819 }
1820 if (r_col[2] < 0.5f) {
1821 r_col[2] *= (facm + 2.0f * fac * col[2]);
1822 }
1823 else {
1824 r_col[2] = 1.0f - (facm + 2.0f * fac * (1.0f - col[2])) * (1.0f - r_col[2]);
1825 }
1826 break;
1827 case MA_RAMP_SUB:
1828 r_col[0] -= fac * col[0];
1829 r_col[1] -= fac * col[1];
1830 r_col[2] -= fac * col[2];
1831 break;
1832 case MA_RAMP_DIV:
1833 if (col[0] != 0.0f) {
1834 r_col[0] = facm * (r_col[0]) + fac * (r_col[0]) / col[0];
1835 }
1836 if (col[1] != 0.0f) {
1837 r_col[1] = facm * (r_col[1]) + fac * (r_col[1]) / col[1];
1838 }
1839 if (col[2] != 0.0f) {
1840 r_col[2] = facm * (r_col[2]) + fac * (r_col[2]) / col[2];
1841 }
1842 break;
1843 case MA_RAMP_DIFF:
1844 r_col[0] = facm * (r_col[0]) + fac * fabsf(r_col[0] - col[0]);
1845 r_col[1] = facm * (r_col[1]) + fac * fabsf(r_col[1] - col[1]);
1846 r_col[2] = facm * (r_col[2]) + fac * fabsf(r_col[2] - col[2]);
1847 break;
1848 case MA_RAMP_EXCLUSION:
1849 r_col[0] = max_ff(facm * (r_col[0]) + fac * (r_col[0] + col[0] - 2.0f * r_col[0] * col[0]),
1850 0.0f);
1851 r_col[1] = max_ff(facm * (r_col[1]) + fac * (r_col[1] + col[1] - 2.0f * r_col[1] * col[1]),
1852 0.0f);
1853 r_col[2] = max_ff(facm * (r_col[2]) + fac * (r_col[2] + col[2] - 2.0f * r_col[2] * col[2]),
1854 0.0f);
1855 break;
1856 case MA_RAMP_DARK:
1857 r_col[0] = min_ff(r_col[0], col[0]) * fac + r_col[0] * facm;
1858 r_col[1] = min_ff(r_col[1], col[1]) * fac + r_col[1] * facm;
1859 r_col[2] = min_ff(r_col[2], col[2]) * fac + r_col[2] * facm;
1860 break;
1861 case MA_RAMP_LIGHT:
1862 r_col[0] = max_ff(r_col[0], col[0]) * fac + r_col[0] * facm;
1863 r_col[1] = max_ff(r_col[1], col[1]) * fac + r_col[1] * facm;
1864 r_col[2] = max_ff(r_col[2], col[2]) * fac + r_col[2] * facm;
1865 break;
1866 case MA_RAMP_DODGE:
1867 if (r_col[0] != 0.0f) {
1868 tmp = 1.0f - fac * col[0];
1869 if (tmp <= 0.0f) {
1870 r_col[0] = 1.0f;
1871 }
1872 else if ((tmp = (r_col[0]) / tmp) > 1.0f) {
1873 r_col[0] = 1.0f;
1874 }
1875 else {
1876 r_col[0] = tmp;
1877 }
1878 }
1879 if (r_col[1] != 0.0f) {
1880 tmp = 1.0f - fac * col[1];
1881 if (tmp <= 0.0f) {
1882 r_col[1] = 1.0f;
1883 }
1884 else if ((tmp = (r_col[1]) / tmp) > 1.0f) {
1885 r_col[1] = 1.0f;
1886 }
1887 else {
1888 r_col[1] = tmp;
1889 }
1890 }
1891 if (r_col[2] != 0.0f) {
1892 tmp = 1.0f - fac * col[2];
1893 if (tmp <= 0.0f) {
1894 r_col[2] = 1.0f;
1895 }
1896 else if ((tmp = (r_col[2]) / tmp) > 1.0f) {
1897 r_col[2] = 1.0f;
1898 }
1899 else {
1900 r_col[2] = tmp;
1901 }
1902 }
1903 break;
1904 case MA_RAMP_BURN:
1905 tmp = facm + fac * col[0];
1906
1907 if (tmp <= 0.0f) {
1908 r_col[0] = 0.0f;
1909 }
1910 else if ((tmp = (1.0f - (1.0f - (r_col[0])) / tmp)) < 0.0f) {
1911 r_col[0] = 0.0f;
1912 }
1913 else if (tmp > 1.0f) {
1914 r_col[0] = 1.0f;
1915 }
1916 else {
1917 r_col[0] = tmp;
1918 }
1919
1920 tmp = facm + fac * col[1];
1921 if (tmp <= 0.0f) {
1922 r_col[1] = 0.0f;
1923 }
1924 else if ((tmp = (1.0f - (1.0f - (r_col[1])) / tmp)) < 0.0f) {
1925 r_col[1] = 0.0f;
1926 }
1927 else if (tmp > 1.0f) {
1928 r_col[1] = 1.0f;
1929 }
1930 else {
1931 r_col[1] = tmp;
1932 }
1933
1934 tmp = facm + fac * col[2];
1935 if (tmp <= 0.0f) {
1936 r_col[2] = 0.0f;
1937 }
1938 else if ((tmp = (1.0f - (1.0f - (r_col[2])) / tmp)) < 0.0f) {
1939 r_col[2] = 0.0f;
1940 }
1941 else if (tmp > 1.0f) {
1942 r_col[2] = 1.0f;
1943 }
1944 else {
1945 r_col[2] = tmp;
1946 }
1947 break;
1948 case MA_RAMP_HUE: {
1949 float rH, rS, rV;
1950 float colH, colS, colV;
1951 float tmpr, tmpg, tmpb;
1952 rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
1953 if (colS != 0) {
1954 rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
1955 hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb);
1956 r_col[0] = facm * (r_col[0]) + fac * tmpr;
1957 r_col[1] = facm * (r_col[1]) + fac * tmpg;
1958 r_col[2] = facm * (r_col[2]) + fac * tmpb;
1959 }
1960 break;
1961 }
1962 case MA_RAMP_SAT: {
1963 float rH, rS, rV;
1964 float colH, colS, colV;
1965 rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
1966 if (rS != 0) {
1967 rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
1968 hsv_to_rgb(rH, (facm * rS + fac * colS), rV, r_col + 0, r_col + 1, r_col + 2);
1969 }
1970 break;
1971 }
1972 case MA_RAMP_VAL: {
1973 float rH, rS, rV;
1974 float colH, colS, colV;
1975 rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
1976 rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
1977 hsv_to_rgb(rH, rS, (facm * rV + fac * colV), r_col + 0, r_col + 1, r_col + 2);
1978 break;
1979 }
1980 case MA_RAMP_COLOR: {
1981 float rH, rS, rV;
1982 float colH, colS, colV;
1983 float tmpr, tmpg, tmpb;
1984 rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
1985 if (colS != 0) {
1986 rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
1987 hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb);
1988 r_col[0] = facm * (r_col[0]) + fac * tmpr;
1989 r_col[1] = facm * (r_col[1]) + fac * tmpg;
1990 r_col[2] = facm * (r_col[2]) + fac * tmpb;
1991 }
1992 break;
1993 }
1994 case MA_RAMP_SOFT: {
1995 float scr, scg, scb;
1996
1997 /* first calculate non-fac based Screen mix */
1998 scr = 1.0f - (1.0f - col[0]) * (1.0f - r_col[0]);
1999 scg = 1.0f - (1.0f - col[1]) * (1.0f - r_col[1]);
2000 scb = 1.0f - (1.0f - col[2]) * (1.0f - r_col[2]);
2001
2002 r_col[0] = facm * (r_col[0]) +
2003 fac * (((1.0f - r_col[0]) * col[0] * (r_col[0])) + (r_col[0] * scr));
2004 r_col[1] = facm * (r_col[1]) +
2005 fac * (((1.0f - r_col[1]) * col[1] * (r_col[1])) + (r_col[1] * scg));
2006 r_col[2] = facm * (r_col[2]) +
2007 fac * (((1.0f - r_col[2]) * col[2] * (r_col[2])) + (r_col[2] * scb));
2008 break;
2009 }
2010 case MA_RAMP_LINEAR:
2011 if (col[0] > 0.5f) {
2012 r_col[0] = r_col[0] + fac * (2.0f * (col[0] - 0.5f));
2013 }
2014 else {
2015 r_col[0] = r_col[0] + fac * (2.0f * (col[0]) - 1.0f);
2016 }
2017 if (col[1] > 0.5f) {
2018 r_col[1] = r_col[1] + fac * (2.0f * (col[1] - 0.5f));
2019 }
2020 else {
2021 r_col[1] = r_col[1] + fac * (2.0f * (col[1]) - 1.0f);
2022 }
2023 if (col[2] > 0.5f) {
2024 r_col[2] = r_col[2] + fac * (2.0f * (col[2] - 0.5f));
2025 }
2026 else {
2027 r_col[2] = r_col[2] + fac * (2.0f * (col[2]) - 1.0f);
2028 }
2029 break;
2030 }
2031}
2032
2033void BKE_material_eval(Depsgraph *depsgraph, Material *material)
2034{
2035 DEG_debug_print_eval(depsgraph, __func__, material->id.name, material);
2036 GPU_material_free(&material->gpumaterial);
2037}
2038
2039/* Default Materials
2040 *
2041 * Used for rendering when objects have no materials assigned, and initializing
2042 * default shader nodes. */
2043
2049
2056
2057static Material *material_default_create(Material **ma_p, const char *name)
2058{
2060 return *ma_p;
2061}
2062
2064{
2065 Material *ma = material_default_create(ma_p, "Default GPencil");
2066
2068 add_v3_fl(&ma->gp_style->stroke_rgba[0], 0.6f);
2069}
2070
2072{
2073 Material *ma = material_default_create(ma_p, "Default Surface");
2074
2076 nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
2077
2079 bNodeSocket *base_color = blender::bke::node_find_socket(*principled, SOCK_IN, "Base Color");
2080 copy_v3_v3(((bNodeSocketValueRGBA *)base_color->default_value)->value, &ma->r);
2081
2083
2085 *principled,
2086 *blender::bke::node_find_socket(*principled, SOCK_OUT, "BSDF"),
2087 *output,
2089
2090 principled->location[0] = -200.0f;
2091 principled->location[1] = 100.0f;
2092 output->location[0] = 200.0f;
2093 output->location[1] = 100.0f;
2094
2096}
2097
2099{
2100 Material *ma = material_default_create(ma_p, "Default Volume");
2101
2103 nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
2104
2106 nullptr, *ntree, SH_NODE_VOLUME_PRINCIPLED);
2108
2110 *principled,
2111 *blender::bke::node_find_socket(*principled, SOCK_OUT, "Volume"),
2112 *output,
2114
2115 principled->location[0] = -200.0f;
2116 principled->location[1] = 100.0f;
2117 output->location[0] = 200.0f;
2118 output->location[1] = 100.0f;
2119
2121}
2122
2124{
2125 Material *ma = material_default_create(ma_p, "Default Holdout");
2126
2128 nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
2129
2130 bNode *holdout = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_HOLDOUT);
2132
2134 *holdout,
2135 *blender::bke::node_find_socket(*holdout, SOCK_OUT, "Holdout"),
2136 *output,
2138
2139 holdout->location[0] = 10.0f;
2140 holdout->location[1] = 300.0f;
2141 output->location[0] = 300.0f;
2142 output->location[1] = 300.0f;
2143
2145}
2146
2151
2156
2161
2166
2171
2173{
2174 for (int i = 0; default_materials[i]; i++) {
2176 if (ma && ma->gpumaterial.first) {
2178 }
2179 }
2180}
2181
2182/* Module functions called on startup and exit. */
2183
2185{
2186 for (int i = 0; default_materials[i]; i++) {
2187 BLI_assert_msg(*default_materials[i] == nullptr,
2188 "Default material pointers should always be null when initializing them, maybe "
2189 "missing a call to `BKE_materials_exit` first?");
2190 }
2191
2197}
2198
2200{
2201 for (int i = 0; default_materials[i]; i++) {
2203 *default_materials[i] = nullptr;
2204 if (ma) {
2205 BKE_id_free(nullptr, &ma->id);
2206 }
2207 }
2208}
const struct CustomDataLayer * BKE_id_attributes_color_find(const struct ID *id, blender::StringRef name)
void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int remap_len)
Definition curve.cc:5365
void BKE_curve_material_index_remove(Curve *cu, int index)
Definition curve.cc:5278
bool BKE_curve_material_index_used(const Curve *cu, int index)
Definition curve.cc:5297
void BKE_curve_material_index_clear(Curve *cu)
Definition curve.cc:5318
Low-level operations for curves.
display list (or rather multi purpose list) stuff.
void BKE_displist_free(struct ListBase *lb)
Definition displist.cc:64
Low-level operations for grease pencil.
void BKE_grease_pencil_material_remap(GreasePencil *grease_pencil, const uint *remap, int totcol)
void BKE_grease_pencil_material_index_remove(GreasePencil *grease_pencil, int index)
bool BKE_grease_pencil_material_index_used(GreasePencil *grease_pencil, int index)
void BKE_icon_id_delete(struct ID *id)
Definition icons.cc:437
IDTypeInfo IDType_ID_MA
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:47
struct ID * BKE_id_copy_in_lib(Main *bmain, std::optional< Library * > owner_library, const ID *id, std::optional< const ID * > new_owner_id, ID **new_id_p, int flag)
Definition lib_id.cc:675
void BKE_id_free(Main *bmain, void *idv)
void id_us_plus(ID *id)
Definition lib_id.cc:358
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1514
@ LIB_ID_CREATE_NO_ALLOCATE
@ LIB_ID_COPY_NO_PREVIEW
@ LIB_ID_CREATE_LOCAL
@ LIB_ID_CREATE_NO_USER_REFCOUNT
void id_us_min(ID *id)
Definition lib_id.cc:366
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1519
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2631
#define BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data_, func_call_)
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
void BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
Definition lib_query.cc:172
@ IDWALK_CB_USER
@ IDWALK_CB_NOP
void BKE_main_lock(Main *bmain)
Definition main.cc:486
void BKE_main_unlock(Main *bmain)
Definition main.cc:491
General operations, lookup, etc. for materials.
@ BKE_MAT_ASSIGN_OBDATA
@ BKE_MAT_ASSIGN_USERPREF
@ BKE_MAT_ASSIGN_OBJECT
@ BKE_MAT_ASSIGN_EXISTING
bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
void BKE_mesh_material_remap(Mesh *mesh, const unsigned int *remap, unsigned int remap_len)
bool BKE_mesh_material_index_used(Mesh *mesh, short index)
void BKE_mesh_material_index_clear(Mesh *mesh)
void BKE_mesh_material_index_remove(Mesh *mesh, short index)
#define NODE_CLASS_INPUT
Definition BKE_node.hh:447
#define SH_NODE_HOLDOUT
#define SH_NODE_UVMAP
#define SH_NODE_TEX_IMAGE
#define SH_NODE_BSDF_PRINCIPLED
#define SH_NODE_OUTPUT_MATERIAL
#define SH_NODE_VOLUME_PRINCIPLED
#define SH_NODE_ATTRIBUTE
General operations, lookup, etc. for blender objects.
bool BKE_object_supports_material_slots(Object *ob)
const Mesh * BKE_object_get_editmesh_eval_final(const Object *object)
void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
void BKE_previewimg_free(PreviewImage **prv)
void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
Generic array manipulation API.
#define BLI_array_permute(arr, arr_len, order)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:712
void ** BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:745
GHash * BLI_ghash_ptr_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE int clamp_i(int value, int min, int max)
void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v)
void hsv_to_rgb(float h, float s, float v, float *r_r, float *r_g, float *r_b)
Definition math_color.cc:21
MINLINE void add_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
unsigned int uint
#define ARRAY_SET_ITEMS(...)
#define STREQLEN(a, b, n)
#define ENUM_OPERATORS(_type, _max)
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_read_struct(reader, struct_name, ptr_p)
#define BLO_write_struct_at_address(writer, struct_name, address, data_ptr)
#define BLT_I18NCONTEXT_ID_MATERIAL
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_debug_print_eval(Depsgraph *depsgraph, const char *function_name, const char *object_name, const void *object_address)
void DEG_relations_tag_update(Main *bmain)
bool DEG_is_evaluated(const T *id)
T * DEG_get_original(T *id)
ID and Library types, which are fundamental for SDNA.
@ ID_TAG_MISSING
Definition DNA_ID.h:867
@ ID_RECALC_SHADING
Definition DNA_ID.h:1094
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define FILTER_ID_MA
Definition DNA_ID.h:1208
#define FILTER_ID_GR
Definition DNA_ID.h:1203
#define FILTER_ID_TE
Definition DNA_ID.h:1220
@ INDEX_ID_MA
Definition DNA_ID.h:1312
@ ID_VO
@ ID_CV
@ ID_CU_LEGACY
@ ID_GD_LEGACY
@ ID_ME
@ ID_MB
@ ID_GP
@ ID_PT
#define DNA_struct_default_get(struct_name)
@ GP_MATERIAL_STROKE_SHOW
#define MAXMAT
@ MA_RAMP_LIGHT
@ MA_RAMP_COLOR
@ MA_RAMP_SAT
@ MA_RAMP_HUE
@ MA_RAMP_LINEAR
@ MA_RAMP_DIV
@ MA_RAMP_EXCLUSION
@ MA_RAMP_ADD
@ MA_RAMP_DODGE
@ MA_RAMP_SUB
@ MA_RAMP_SCREEN
@ MA_RAMP_SOFT
@ MA_RAMP_DARK
@ MA_RAMP_BURN
@ MA_RAMP_BLEND
@ MA_RAMP_VAL
@ MA_RAMP_OVERLAY
@ MA_RAMP_MULT
@ MA_RAMP_DIFF
@ SOCK_OUT
@ SOCK_IN
@ SHD_ATTRIBUTE_GEOMETRY
@ OB_MODE_EDIT
@ OB_MODE_SCULPT
Object is a sort of wrapper for general info.
#define OB_DATA_SUPPORT_ID(_id_type)
@ OB_MBALL
@ OB_EMPTY
@ OB_SURF
@ OB_FONT
@ OB_GREASE_PENCIL
@ OB_MESH
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES_LEGACY
@ OB_CURVES
#define IMAGEPAINT_MODE_IMAGE
@ USER_MAT_ON_OB
#define USER_EXPERIMENTAL_TEST(userdef, member)
void GPU_material_free(ListBase *gpumaterial)
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
struct blender::bke::bNodeTreeType * ntreeType_Shader
#define U
void BKE_objects_materials_sync_length_all(Main *bmain, ID *id)
static Material * default_material_empty
int BKE_object_material_index_get_with_hint(Object *ob, const Material *ma, const int hint_index)
void BKE_texpaint_slots_refresh_object(Scene *scene, Object *ob)
short * BKE_object_material_len_p(Object *ob)
static void material_copy_data(Main *bmain, std::optional< Library * > owner_library, ID *id_dst, const ID *id_src, const int flag)
static void material_default_holdout_init(Material **ma_p)
static void material_data_index_clear_id(ID *id)
static void material_default_volume_init(Material **ma_p)
static void nodetree_mark_previews_dirty_reccursive(bNodeTree *tree)
static void fill_texpaint_slots_recursive(bNodeTree *nodetree, bNode *active_node, const Object *ob, Material *ma, int slot_len, ePaintSlotFilter slot_filter)
int BKE_object_material_count_eval(const Object *ob)
void BKE_object_material_array_assign(Main *bmain, Object *ob, Material ***matar, int totcol, const bool to_object_only)
void BKE_id_material_eval_ensure_default_slot(ID *id)
MaterialGPencilStyle * BKE_gpencil_material_settings(Object *ob, short act)
static Material * default_material_volume
void BKE_gpencil_material_attr_init(Material *ma)
void BKE_object_material_assign_single_obdata(Main *bmain, Object *ob, Material *ma, short act)
void BKE_id_material_clear(Main *bmain, ID *id)
Material ** BKE_object_material_get_p(Object *ob, short act)
static const ID * get_evaluated_object_data_with_materials(const Object *ob)
void BKE_id_material_assign(Main *bmain, ID *id, Material *ma, short act)
short * BKE_id_material_len_p(ID *id)
static bool ntree_foreach_texnode_recursive(bNodeTree *nodetree, ForEachTexNodeCallback callback, void *userdata, ePaintSlotFilter slot_filter)
Material * BKE_material_default_surface()
static Material * default_material_gpencil
static void material_foreach_id(ID *id, LibraryForeachIDData *data)
Material *** BKE_id_material_array_p(ID *id)
short BKE_object_material_slot_find_index(Object *ob, Material *ma)
Material * BKE_material_default_volume()
Material * BKE_gpencil_material(Object *ob, short act)
void BKE_material_eval(Depsgraph *depsgraph, Material *material)
void BKE_material_defaults_free_gpu()
void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, const ID *data_eval)
Material * BKE_gpencil_material_add(Main *bmain, const char *name)
static void material_data_index_remove_id(ID *id, short index)
void BKE_object_materials_sync_length(Main *bmain, Object *ob, ID *id)
static void material_blend_write(BlendWriter *writer, ID *id, const void *id_address)
Material * BKE_id_material_pop(Main *bmain, ID *id, int index_i)
static void material_default_surface_init(Material **ma_p)
static bool texpaint_slot_node_find_cb(bNode *node, void *userdata)
static void object_material_active_index_sanitize(Object *ob)
static ePaintSlotFilter material_paint_slot_filter(const Object *ob)
bool(*)(bNode *node, void *userdata) ForEachTexNodeCallback
static Material * default_material_surface
void BKE_id_materials_copy(Main *bmain, ID *id_src, ID *id_dst)
static Material * material_default_create(Material **ma_p, const char *name)
void BKE_object_material_remap(Object *ob, const uint *remap)
static Material * default_material_holdout
Material * BKE_material_default_holdout()
static void material_free_data(ID *id)
void BKE_materials_init()
void BKE_id_material_resize(Main *bmain, ID *id, short totcol, bool do_id_user)
void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma, const Object *ob)
static bNode * nodetree_uv_node_recursive(bNode *node)
Material * BKE_material_default_gpencil()
void BKE_id_material_eval_assign(ID *id, int slot, Material *material)
static Material ** default_materials[]
Material * BKE_material_add(Main *bmain, const char *name)
void BKE_id_material_append(Main *bmain, ID *id, Material *ma)
bool BKE_object_material_slot_add(Main *bmain, Object *ob, const bool set_active)
bool BKE_object_material_slot_used(Object *object, short actcol)
int BKE_object_material_ensure(Main *bmain, Object *ob, Material *material)
static void object_material_assign(Main *bmain, Object *ob, Material *ma, short act, int assign_type, bool do_test_all)
Material * BKE_material_default_empty()
void BKE_object_material_resize(Main *bmain, Object *ob, const short totcol, bool do_id_user)
int BKE_id_material_used_with_fallback_eval(const ID &id)
static void material_default_gpencil_init(Material **ma_p)
Material * BKE_object_material_get(Object *ob, short act)
void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap_src_to_dst)
static void material_blend_read_data(BlendDataReader *reader, ID *id)
static bool count_texture_nodes_cb(bNode *, void *userdata)
static int count_texture_nodes_recursive(bNodeTree *nodetree, ePaintSlotFilter slot_filter)
static void material_init_data(ID *id)
Material * BKE_object_material_get_eval(Object *ob, short act)
std::optional< int > BKE_id_material_index_max_eval(const ID &id)
void BKE_object_material_assign(Main *bmain, Object *ob, Material *ma, short act, int assign_type)
void BKE_materials_exit()
bNode * BKE_texpaint_slot_material_find_node(Material *ma, short texpaint_slot)
static bool fill_texpaint_slots_cb(bNode *node, void *userdata)
int BKE_object_material_used_with_fallback_eval(const Object &ob)
int BKE_object_material_index_get(Object *ob, const Material *ma)
int BKE_id_material_used_eval(const ID &id)
static void material_foreach_working_space_color(ID *id, const IDTypeForeachColorFunctionCallback &fn)
void BKE_material_make_node_previews_dirty(Material *ma)
Material *** BKE_object_material_array_p(Object *ob)
bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
void ramp_blend(int type, float r_col[3], const float fac, const float col[3])
BMesh const char void * data
BPy_StructRNA * depsgraph
KDTree_3d * tree
#define GS(x)
uint col
#define output
int count
#define LOG(level)
Definition log.h:97
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void *(* MEM_recallocN_id)(void *vmemh, size_t len, const char *str)
Definition mallocn.cc:41
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
bNodeTree * node_tree_add_tree_embedded(Main *bmain, ID *owner_id, StringRefNull name, StringRefNull idname)
Definition node.cc:4098
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
void node_tree_blend_write(BlendWriter *writer, bNodeTree *ntree)
Definition node.cc:1140
bNodeTree * node_tree_localize(bNodeTree *ntree, std::optional< ID * > new_owner_id)
Definition node.cc:4586
bNode * node_get_active_paint_canvas(bNodeTree &ntree)
bNode * node_add_static_node(const bContext *C, bNodeTree &ntree, int type)
Definition node.cc:3500
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:3810
void node_set_active(bNodeTree &ntree, bNode &node)
Definition node.cc:4724
void node_tree_free_embedded_tree(bNodeTree *ntree)
Definition node.cc:4462
const char * name
return ret
#define fabsf
struct Material ** mat
short totcol
struct Material ** mat
struct Material ** material_array
const blender::FunctionRef< void(float rgb[3])> single
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
char name[258]
Definition DNA_ID.h:432
int us
Definition DNA_ID.h:443
void * next
Definition DNA_ID.h:417
void * first
ListBase objects
Definition BKE_main.hh:280
float line_col[4]
struct bNodeTree * nodetree
short paint_active_slot
struct PreviewImage * preview
struct MaterialGPencilStyle * gp_style
ListBase gpumaterial
struct TexPaintSlot * texpaintslot
MeshRuntimeHandle * runtime
struct Material ** mat
short totcol
struct Material ** mat
ListBase particlesystem
ObjectRuntimeHandle * runtime
struct Material ** mat
char * matbits
struct Material ** mat
struct ToolSettings * toolsettings
struct Image * ima
struct ImageUser * image_user
struct ImagePaintSettings imapaint
struct Material ** mat
void * default_value
float location[2]
bNodeTypeHandle * typeinfo
ListBase inputs
struct ID * id
int16_t type_legacy
void * storage
i
Definition text_draw.cc:230
#define N_(msgid)
uint8_t flag
Definition wm_window.cc:145