Blender V4.5
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_gpencil_legacy.h"
54#include "BKE_grease_pencil.hh"
55#include "BKE_icons.h"
56#include "BKE_idtype.hh"
57#include "BKE_image.hh"
58#include "BKE_lib_id.hh"
59#include "BKE_lib_query.hh"
60#include "BKE_main.hh"
61#include "BKE_material.hh"
62#include "BKE_mesh.hh"
63#include "BKE_node.hh"
65#include "BKE_node_runtime.hh"
66#include "BKE_object.hh"
67#include "BKE_object_types.hh"
68#include "BKE_preview_image.hh"
69#include "BKE_scene.hh"
70#include "BKE_vfont.hh"
71
72#include "DEG_depsgraph.hh"
75
76#include "GPU_material.hh"
77
78#include "NOD_shader.h"
79
80#include "BLO_read_write.hh"
81
82static CLG_LogRef LOG = {"bke.material"};
83
84static void material_init_data(ID *id)
85{
86 Material *material = (Material *)id;
87
89
91}
92
93static void material_copy_data(Main *bmain,
94 std::optional<Library *> owner_library,
95 ID *id_dst,
96 const ID *id_src,
97 const int flag)
98{
99 Material *material_dst = (Material *)id_dst;
100 const Material *material_src = (const Material *)id_src;
101
102 const bool is_localized = (flag & LIB_ID_CREATE_LOCAL) != 0;
103 /* Never handle user-count here for own sub-data. */
104 const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
105 /* Always need allocation of the embedded ID data. */
106 const int flag_embedded_id_data = flag_subdata & ~LIB_ID_CREATE_NO_ALLOCATE;
107
108 if (material_src->nodetree != nullptr) {
109 if (is_localized) {
110 material_dst->nodetree = blender::bke::node_tree_localize(material_src->nodetree,
111 &material_dst->id);
112 }
113 else {
114 BKE_id_copy_in_lib(bmain,
115 owner_library,
116 &material_src->nodetree->id,
117 &material_dst->id,
118 reinterpret_cast<ID **>(&material_dst->nodetree),
119 flag_embedded_id_data);
120 }
121 }
122
123 if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
124 BKE_previewimg_id_copy(&material_dst->id, &material_src->id);
125 }
126 else {
127 material_dst->preview = nullptr;
128 }
129
130 if (material_src->texpaintslot != nullptr) {
131 /* TODO: Think we can also skip copying this data in the more generic `NO_MAIN` case? */
132 material_dst->texpaintslot = is_localized ? nullptr :
133 static_cast<TexPaintSlot *>(
134 MEM_dupallocN(material_src->texpaintslot));
135 }
136
137 if (material_src->gp_style != nullptr) {
138 material_dst->gp_style = static_cast<MaterialGPencilStyle *>(
139 MEM_dupallocN(material_src->gp_style));
140 }
141
142 BLI_listbase_clear(&material_dst->gpumaterial);
143
144 /* TODO: Duplicate Engine Settings and set runtime to nullptr. */
145}
146
147static void material_free_data(ID *id)
148{
149 Material *material = (Material *)id;
150
151 /* Free gpu material before the ntree */
152 GPU_material_free(&material->gpumaterial);
153
154 /* is no lib link block, but material extension */
155 if (material->nodetree) {
157 MEM_freeN(material->nodetree);
158 material->nodetree = nullptr;
159 }
160
161 MEM_SAFE_FREE(material->texpaintslot);
162
163 MEM_SAFE_FREE(material->gp_style);
164
165 BKE_previewimg_free(&material->preview);
166
167 BKE_icon_id_delete((ID *)material);
168}
169
171{
172 Material *material = reinterpret_cast<Material *>(id);
174
175 /* Node-trees **are owned by IDs**, treat them as mere sub-data and not real ID! */
178 if (material->texpaintslot != nullptr) {
180 }
181 if (material->gp_style != nullptr) {
184 }
185
188 }
189}
190
191static void material_blend_write(BlendWriter *writer, ID *id, const void *id_address)
192{
193 Material *ma = (Material *)id;
194
195 /* Clean up, important in undo case to reduce false detection of changed datablocks. */
196 ma->texpaintslot = nullptr;
198
199 /* write LibData */
200 BLO_write_id_struct(writer, Material, id_address, &ma->id);
201 BKE_id_blend_write(writer, &ma->id);
202
203 /* nodetree is integral part of material, no libdata */
204 if (ma->nodetree) {
205 BLO_Write_IDBuffer temp_embedded_id_buffer{ma->nodetree->id, writer};
206 BLO_write_struct_at_address(writer, bNodeTree, ma->nodetree, temp_embedded_id_buffer.get());
208 writer, reinterpret_cast<bNodeTree *>(temp_embedded_id_buffer.get()));
209 }
210
212
213 /* grease pencil settings */
214 if (ma->gp_style) {
216 }
217}
218
220{
221 Material *ma = (Material *)id;
222
223 ma->texpaintslot = nullptr;
224
225 BLO_read_struct(reader, PreviewImage, &ma->preview);
227
229
231}
232
234 /*id_code*/ Material::id_type,
235 /*id_filter*/ FILTER_ID_MA,
236 /*dependencies_id_types*/ FILTER_ID_TE | FILTER_ID_GR,
237 /*main_listbase_index*/ INDEX_ID_MA,
238 /*struct_size*/ sizeof(Material),
239 /*name*/ "Material",
240 /*name_plural*/ N_("materials"),
241 /*translation_context*/ BLT_I18NCONTEXT_ID_MATERIAL,
243 /*asset_type_info*/ nullptr,
244
245 /*init_data*/ material_init_data,
246 /*copy_data*/ material_copy_data,
247 /*free_data*/ material_free_data,
248 /*make_local*/ nullptr,
249 /*foreach_id*/ material_foreach_id,
250 /*foreach_cache*/ nullptr,
251 /*foreach_path*/ nullptr,
252 /*owner_pointer_get*/ nullptr,
253
254 /*blend_write*/ material_blend_write,
255 /*blend_read_data*/ material_blend_read_data,
256 /*blend_read_after_liblink*/ nullptr,
257
258 /*blend_read_undo_preserve*/ nullptr,
259
260 /*lib_override_apply_post*/ nullptr,
261};
262
264{
265 if ((ma) && (ma->gp_style == nullptr)) {
266 ma->gp_style = MEM_callocN<MaterialGPencilStyle>("Grease Pencil Material Settings");
267
268 MaterialGPencilStyle *gp_style = ma->gp_style;
269 /* set basic settings */
270 gp_style->stroke_rgba[3] = 1.0f;
271 gp_style->fill_rgba[3] = 1.0f;
272 ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 1.0f);
273 ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
274 gp_style->texture_offset[0] = -0.5f;
275 gp_style->texture_pixsize = 100.0f;
276 gp_style->mix_factor = 0.5f;
277
278 gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
279 }
280}
281
283{
284 if (tree == nullptr) {
285 return;
286 }
287 tree->runtime->previews_refresh_state++;
288 for (bNode *node : tree->all_nodes()) {
289 if (node->is_group()) {
290 bNodeTree *nested_tree = reinterpret_cast<bNodeTree *>(node->id);
292 }
293 }
294}
295
302
303Material *BKE_material_add(Main *bmain, const char *name)
304{
305 Material *ma;
306
307 ma = BKE_id_new<Material>(bmain, name);
308
309 return ma;
310}
311
312Material *BKE_gpencil_material_add(Main *bmain, const char *name)
313{
314 Material *ma;
315
316 ma = BKE_material_add(bmain, name);
317
318 /* grease pencil settings */
319 if (ma != nullptr) {
321 }
322 return ma;
323}
324
326{
327 if (ob->type == OB_MESH) {
328 Mesh *mesh = static_cast<Mesh *>(ob->data);
329 return &(mesh->mat);
330 }
332 Curve *cu = static_cast<Curve *>(ob->data);
333 return &(cu->mat);
334 }
335 if (ob->type == OB_MBALL) {
336 MetaBall *mb = static_cast<MetaBall *>(ob->data);
337 return &(mb->mat);
338 }
339 if (ob->type == OB_CURVES) {
340 Curves *curves = static_cast<Curves *>(ob->data);
341 return &(curves->mat);
342 }
343 if (ob->type == OB_POINTCLOUD) {
344 PointCloud *pointcloud = static_cast<PointCloud *>(ob->data);
345 return &(pointcloud->mat);
346 }
347 if (ob->type == OB_VOLUME) {
348 Volume *volume = static_cast<Volume *>(ob->data);
349 return &(volume->mat);
350 }
351 if (ob->type == OB_GREASE_PENCIL) {
352 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
353 return &(grease_pencil->material_array);
354 }
355 return nullptr;
356}
357
359{
360 if (ob->type == OB_MESH) {
361 Mesh *mesh = static_cast<Mesh *>(ob->data);
362 return &(mesh->totcol);
363 }
365 Curve *cu = static_cast<Curve *>(ob->data);
366 return &(cu->totcol);
367 }
368 if (ob->type == OB_MBALL) {
369 MetaBall *mb = static_cast<MetaBall *>(ob->data);
370 return &(mb->totcol);
371 }
372 if (ob->type == OB_CURVES) {
373 Curves *curves = static_cast<Curves *>(ob->data);
374 return &(curves->totcol);
375 }
376 if (ob->type == OB_POINTCLOUD) {
377 PointCloud *pointcloud = static_cast<PointCloud *>(ob->data);
378 return &(pointcloud->totcol);
379 }
380 if (ob->type == OB_VOLUME) {
381 Volume *volume = static_cast<Volume *>(ob->data);
382 return &(volume->totcol);
383 }
384 if (ob->type == OB_GREASE_PENCIL) {
385 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
386 return &(grease_pencil->material_array_num);
387 }
388 return nullptr;
389}
390
392{
393 /* ensure we don't try get materials from non-obdata */
395
396 switch (GS(id->name)) {
397 case ID_ME:
398 return &(((Mesh *)id)->mat);
399 case ID_CU_LEGACY:
400 return &(((Curve *)id)->mat);
401 case ID_MB:
402 return &(((MetaBall *)id)->mat);
403 case ID_GD_LEGACY:
404 return &(((bGPdata *)id)->mat);
405 case ID_CV:
406 return &(((Curves *)id)->mat);
407 case ID_PT:
408 return &(((PointCloud *)id)->mat);
409 case ID_VO:
410 return &(((Volume *)id)->mat);
411 case ID_GP:
412 return &(((GreasePencil *)id)->material_array);
413 default:
414 break;
415 }
416 return nullptr;
417}
418
420{
421 /* ensure we don't try get materials from non-obdata */
423
424 switch (GS(id->name)) {
425 case ID_ME:
426 return &(((Mesh *)id)->totcol);
427 case ID_CU_LEGACY:
428 return &(((Curve *)id)->totcol);
429 case ID_MB:
430 return &(((MetaBall *)id)->totcol);
431 case ID_GD_LEGACY:
432 return &(((bGPdata *)id)->totcol);
433 case ID_CV:
434 return &(((Curves *)id)->totcol);
435 case ID_PT:
436 return &(((PointCloud *)id)->totcol);
437 case ID_VO:
438 return &(((Volume *)id)->totcol);
439 case ID_GP:
440 return &(((GreasePencil *)id)->material_array_num);
441 default:
442 break;
443 }
444 return nullptr;
445}
446
447static void material_data_index_remove_id(ID *id, short index)
448{
449 /* ensure we don't try get materials from non-obdata */
451
452 switch (GS(id->name)) {
453 case ID_ME:
455 break;
456 case ID_CU_LEGACY:
458 break;
459 case ID_GP:
460 BKE_grease_pencil_material_index_remove(reinterpret_cast<GreasePencil *>(id), index);
461 break;
462 case ID_MB:
463 case ID_CV:
464 case ID_PT:
465 case ID_VO:
466 /* No material indices for these object data types. */
467 break;
468 default:
469 break;
470 }
471}
472
473bool BKE_object_material_slot_used(Object *object, short actcol)
474{
476 return false;
477 }
478
480 if (psys->part->omat == actcol) {
481 return true;
482 }
483 }
484
485 ID *ob_data = static_cast<ID *>(object->data);
486 if (ob_data == nullptr || !OB_DATA_SUPPORT_ID(GS(ob_data->name))) {
487 return false;
488 }
489
490 switch (GS(ob_data->name)) {
491 case ID_ME:
492 return BKE_mesh_material_index_used((Mesh *)ob_data, actcol - 1);
493 case ID_CU_LEGACY:
494 return BKE_curve_material_index_used((Curve *)ob_data, actcol - 1);
495 case ID_MB:
496 /* Meta-elements don't support materials at the moment. */
497 return false;
498 case ID_GP:
499 return BKE_grease_pencil_material_index_used(reinterpret_cast<GreasePencil *>(ob_data),
500 actcol - 1);
501 default:
502 return false;
503 }
504}
505
507{
508 /* ensure we don't try get materials from non-obdata */
510
511 switch (GS(id->name)) {
512 case ID_ME:
514 break;
515 case ID_CU_LEGACY:
517 break;
518 case ID_MB:
519 case ID_CV:
520 case ID_PT:
521 case ID_VO:
522 /* No material indices for these object data types. */
523 break;
524 default:
525 break;
526 }
527}
528
529void BKE_id_materials_copy(Main *bmain, ID *id_src, ID *id_dst)
530{
531 Material ***matar_src = BKE_id_material_array_p(id_src);
532 const short *materials_len_p_src = BKE_id_material_len_p(id_src);
533
534 Material ***matar_dst = BKE_id_material_array_p(id_dst);
535 short *materials_len_p_dst = BKE_id_material_len_p(id_dst);
536
537 *materials_len_p_dst = *materials_len_p_src;
538 if (*materials_len_p_src != 0) {
539 (*matar_dst) = static_cast<Material **>(MEM_dupallocN(*matar_src));
540
541 for (int a = 0; a < *materials_len_p_src; a++) {
542 id_us_plus((ID *)(*matar_dst)[a]);
543 }
544
547 }
548}
549
550void BKE_id_material_resize(Main *bmain, ID *id, short totcol, bool do_id_user)
551{
552 Material ***matar = BKE_id_material_array_p(id);
553 short *totcolp = BKE_id_material_len_p(id);
554
555 if (matar == nullptr) {
556 return;
557 }
558 if (totcol == *totcolp) {
559 /* Prevent depsgraph update and relations tag when nothing changed. */
560 return;
561 }
562
563 if (do_id_user && totcol < (*totcolp)) {
564 short i;
565 for (i = totcol; i < (*totcolp); i++) {
566 id_us_min((ID *)(*matar)[i]);
567 }
568 }
569
570 if (totcol == 0) {
571 if (*totcolp) {
572 MEM_freeN(*matar);
573 *matar = nullptr;
574 }
575 }
576 else {
577 *matar = static_cast<Material **>(MEM_recallocN(*matar, sizeof(void *) * totcol));
578 }
579 *totcolp = totcol;
580
583}
584
586{
587 Material ***matar = BKE_id_material_array_p(id);
588 if (matar) {
589 short *totcol = BKE_id_material_len_p(id);
590 Material **mat = MEM_calloc_arrayN<Material *>((*totcol) + 1, "newmatar");
591 if (*totcol) {
592 memcpy(mat, *matar, sizeof(void *) * (*totcol));
593 }
594 if (*matar) {
595 MEM_freeN(*matar);
596 }
597
598 *matar = mat;
599 (*matar)[(*totcol)++] = ma;
600
601 id_us_plus((ID *)ma);
603
606 }
607}
608
609Material *BKE_id_material_pop(Main *bmain, ID *id, int index_i)
610{
611 short index = short(index_i);
612 Material *ret = nullptr;
613 Material ***matar = BKE_id_material_array_p(id);
614 if (matar) {
615 short *totcol = BKE_id_material_len_p(id);
616 if (index >= 0 && index < (*totcol)) {
617 ret = (*matar)[index];
618 id_us_min((ID *)ret);
619
620 if (*totcol <= 1) {
621 *totcol = 0;
622 MEM_freeN(*matar);
623 *matar = nullptr;
624 }
625 else {
626 if (index + 1 != (*totcol)) {
627 memmove((*matar) + index,
628 (*matar) + (index + 1),
629 sizeof(void *) * ((*totcol) - (index + 1)));
630 }
631
632 (*totcol)--;
633 *matar = static_cast<Material **>(MEM_reallocN(*matar, sizeof(void *) * (*totcol)));
635 }
636
638
641 }
642 }
643
644 return ret;
645}
646
648{
649 Material ***matar = BKE_id_material_array_p(id);
650 if (matar) {
651 short *totcol = BKE_id_material_len_p(id);
652
653 while ((*totcol)--) {
654 id_us_min((ID *)((*matar)[*totcol]));
655 }
656 *totcol = 0;
657 if (*matar) {
658 MEM_freeN(*matar);
659 *matar = nullptr;
660 }
661
664
667 }
668}
669
671{
672 Material ***matarar, **ma_p;
673 const short *totcolp;
674
675 if (ob == nullptr) {
676 return nullptr;
677 }
678
679 /* if object cannot have material, (totcolp == nullptr) */
680 totcolp = BKE_object_material_len_p(ob);
681 if (totcolp == nullptr || *totcolp == 0) {
682 return nullptr;
683 }
684
685 /* Clamp to number of slots if index is out of range, same convention as used for rendering. */
686 const int slot_index = clamp_i(act - 1, 0, *totcolp - 1);
687
688 /* Fix inconsistency which may happen when library linked data reduces the number of
689 * slots but object was not updated. Ideally should be fixed elsewhere. */
690 ob->totcol = std::min<int>(*totcolp, ob->totcol);
691
692 if (slot_index < ob->totcol && ob->matbits && ob->matbits[slot_index]) {
693 /* Use object material slot. */
694 ma_p = &ob->mat[slot_index];
695 }
696 else {
697 /* Use data material slot. */
698 matarar = BKE_object_material_array_p(ob);
699
700 if (matarar && *matarar) {
701 ma_p = &(*matarar)[slot_index];
702 }
703 else {
704 ma_p = nullptr;
705 }
706 }
707
708 return ma_p;
709}
710
712{
713 Material **ma_p = BKE_object_material_get_p(ob, act);
714 /* Grease Pencil objects currently make the assumption that the returned material has Grease
715 * Pencil settings. Ensure that this is the case otherwise return `nullptr`. */
716 if (ob->type == OB_GREASE_PENCIL && ma_p != nullptr) {
717 Material *ma = *ma_p;
718 if (ma != nullptr) {
719 return ma->gp_style != nullptr ? ma : nullptr;
720 }
721 }
722 return ma_p ? *ma_p : nullptr;
723}
724
726{
727 const ID *data = static_cast<ID *>(ob->data);
728 /* Meshes in edit mode need special handling. */
729 if (ob->type == OB_MESH && ob->mode == OB_MODE_EDIT) {
730 const Mesh *mesh = static_cast<const Mesh *>(ob->data);
731 const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
732 if (mesh->runtime->edit_mesh && editmesh_eval_final) {
733 data = &editmesh_eval_final->id;
734 }
735 }
736 return data;
737}
738
740{
742 return const_cast<Material *>(BKE_object_material_get_eval(*ob, *data, act));
743}
744
745const Material *BKE_object_material_get_eval(const Object &ob, const ID &data, const short act)
746{
748
749 const int slots_num = BKE_object_material_count_eval(ob, data);
750
751 if (slots_num == 0) {
752 return nullptr;
753 }
754
755 /* Clamp to number of slots if index is out of range, same convention as used for rendering. */
756 const int slot_index = clamp_i(act - 1, 0, slots_num - 1);
757 const int tot_slots_object = ob.totcol;
758
759 /* Check if slot is overwritten by object. */
760 if (slot_index < tot_slots_object) {
761 if (ob.matbits) {
762 if (ob.matbits[slot_index]) {
763 Material *material = ob.mat[slot_index];
764 if (material != nullptr) {
765 return material;
766 }
767 }
768 }
769 }
770
771 /* Otherwise use data from object-data. */
772 const short *data_slots_num_ptr = BKE_id_material_len_p(const_cast<ID *>(&data));
773 if (!data_slots_num_ptr) {
774 return nullptr;
775 }
776 const int data_slots_num = *data_slots_num_ptr;
777 Material **data_materials = *BKE_id_material_array_p(const_cast<ID *>(&data));
778 if (slot_index < data_slots_num) {
779 Material *material = data_materials[slot_index];
780 return material;
781 }
782 return nullptr;
783}
784
786{
788 if (ob->type == OB_EMPTY) {
789 return 0;
790 }
791 BLI_assert(ob->data != nullptr);
792 const ID *id = get_evaluated_object_data_with_materials(const_cast<Object *>(ob));
793 const short *len_p = BKE_id_material_len_p(const_cast<ID *>(id));
794 return std::max(ob->totcol, len_p ? *len_p : 0);
795}
796
798{
800 if (ob.type == OB_EMPTY) {
801 return 0;
802 }
803 BLI_assert(ob.data != nullptr);
804 const short *len_p = BKE_id_material_len_p(const_cast<ID *>(&data));
805 return std::max(ob.totcol, len_p ? *len_p : 0);
806}
807
808std::optional<int> BKE_id_material_index_max_eval(const ID &id)
809{
810 switch (GS(id.name)) {
811 case ID_ME:
812 return reinterpret_cast<const Mesh &>(id).material_index_max();
813 case ID_CU_LEGACY:
814 return reinterpret_cast<const Curve &>(id).material_index_max();
815 case ID_CV:
816 return reinterpret_cast<const Curves &>(id).geometry.wrap().material_index_max();
817 case ID_PT:
818 return reinterpret_cast<const PointCloud &>(id).material_index_max();
819 case ID_GP:
820 return reinterpret_cast<const GreasePencil &>(id).material_index_max();
821 case ID_VO:
822 case ID_MB:
823 /* Always use the first material. */
824 return 0;
825 case ID_GD_LEGACY:
826 /* Is not rendered anymore. */
828 return 0;
829 default:
830 break;
831 }
832 return 0;
833}
834
836{
837 if (std::optional<int> max_index = BKE_id_material_index_max_eval(id)) {
838 return *max_index + 1;
839 }
840 return 0;
841}
842
844{
845 const int max_material_index = std::max(0, BKE_id_material_index_max_eval(id).value_or(0));
846 return max_material_index + 1;
847}
848
854
855void BKE_id_material_eval_assign(ID *id, int slot, Material *material)
856{
857 BLI_assert(slot >= 1);
858 Material ***materials_ptr = BKE_id_material_array_p(id);
859 short *len_ptr = BKE_id_material_len_p(id);
860 if (ELEM(nullptr, materials_ptr, len_ptr)) {
862 return;
863 }
864
865 const int slot_index = slot - 1;
866 const int old_length = *len_ptr;
867
868 if (slot_index >= old_length) {
869 /* Need to grow slots array. */
870 const int new_length = slot_index + 1;
871 *materials_ptr = static_cast<Material **>(
872 MEM_reallocN(*materials_ptr, sizeof(void *) * new_length));
873 *len_ptr = new_length;
874 for (int i = old_length; i < new_length; i++) {
875 (*materials_ptr)[i] = nullptr;
876 }
877 }
878
879 (*materials_ptr)[slot_index] = material;
880}
881
883{
884 short *len_ptr = BKE_id_material_len_p(id);
885 if (len_ptr == nullptr) {
886 return;
887 }
888 if (*len_ptr == 0) {
889 BKE_id_material_eval_assign(id, 1, nullptr);
890 }
891}
892
894{
895 short *totcol = BKE_object_material_len_p(ob);
896 Material *read_ma = nullptr;
897 for (short i = 0; i < *totcol; i++) {
898 read_ma = BKE_object_material_get(ob, i + 1);
899 if (ma == read_ma) {
900 return i;
901 }
902 }
903 return -1;
904}
905
906int BKE_object_material_index_get_with_hint(Object *ob, const Material *ma, const int hint_index)
907{
908 short *totcol = BKE_object_material_len_p(ob);
909 if ((hint_index >= 0) && (hint_index < *totcol)) {
910 if (ma == BKE_object_material_get(ob, hint_index + 1)) {
911 return hint_index;
912 }
913 }
914 return BKE_object_material_index_get(ob, ma);
915}
916
918{
919 if (!material) {
920 return -1;
921 }
922 int index = BKE_object_material_index_get(ob, material);
923 if (index < 0) {
926 return ob->totcol - 1;
927 }
928 return index;
929}
930
932{
933 Material *ma = BKE_object_material_get(ob, act);
934 if (ma != nullptr) {
935 return ma;
936 }
937
938 /* XXX FIXME This is critical abuse of the 'default material' feature, these IDs should never be
939 * used/returned as 'regular' data. */
941}
942
944{
945 Material *ma = BKE_object_material_get(ob, act);
946 if (ma != nullptr) {
947 if (ma->gp_style == nullptr) {
949 }
950
951 return ma->gp_style;
952 }
953
955}
956
963{
964 if (ob->totcol && ob->actcol == 0) {
965 ob->actcol = 1;
966 }
967 ob->actcol = std::min(ob->actcol, ob->totcol);
968}
969
970void BKE_object_material_resize(Main *bmain, Object *ob, const short totcol, bool do_id_user)
971{
972 if (totcol == ob->totcol) {
973 /* Prevent depsgraph update and relations tag when nothing changed. */
974 return;
975 }
976
977 Material **newmatar;
978 char *newmatbits;
979
980 if (do_id_user && totcol < ob->totcol) {
981 for (int i = totcol; i < ob->totcol; i++) {
982 id_us_min((ID *)ob->mat[i]);
983 }
984 }
985
986 if (totcol == 0) {
987 if (ob->totcol) {
988 MEM_freeN(ob->mat);
989 MEM_freeN(ob->matbits);
990 ob->mat = nullptr;
991 ob->matbits = nullptr;
992 }
993 }
994 else if (ob->totcol < totcol) {
995 newmatar = MEM_calloc_arrayN<Material *>(totcol, "newmatar");
996 newmatbits = MEM_calloc_arrayN<char>(totcol, "newmatbits");
997 if (ob->totcol) {
998 memcpy(newmatar, ob->mat, sizeof(void *) * ob->totcol);
999 memcpy(newmatbits, ob->matbits, sizeof(char) * ob->totcol);
1000 MEM_freeN(ob->mat);
1001 MEM_freeN(ob->matbits);
1002 }
1003 ob->mat = newmatar;
1004 ob->matbits = newmatbits;
1005 }
1006 /* XXX(@ideasman42): why not realloc on shrink? */
1007
1008 ob->totcol = totcol;
1009
1012}
1013
1015{
1016 const short *totcol;
1017
1018 if (id == nullptr || (totcol = BKE_id_material_len_p(id)) == nullptr) {
1019 return;
1020 }
1021
1022 if ((ob->id.tag & ID_TAG_MISSING) == 0 && (id->tag & ID_TAG_MISSING) != 0) {
1023 /* Exception: In case the object is a valid data, but its obdata is an empty place-holder,
1024 * use object's material slots amount as reference.
1025 * This avoids losing materials in a local object when its linked obdata goes missing.
1026 * See #92780. */
1027 BKE_id_material_resize(bmain, id, short(ob->totcol), false);
1028 }
1029 else {
1030 /* Normal case: the use the obdata amount of materials slots to update the object's one. */
1031 BKE_object_material_resize(bmain, ob, *totcol, false);
1033 }
1034}
1035
1037{
1038 Object *ob;
1039 const short *totcol;
1040
1041 if (id == nullptr || (totcol = BKE_id_material_len_p(id)) == nullptr) {
1042 return;
1043 }
1044
1045 BKE_main_lock(bmain);
1046 int processed_objects = 0;
1047 for (ob = static_cast<Object *>(bmain->objects.first); ob;
1048 ob = static_cast<Object *>(ob->id.next))
1049 {
1050 if (ob->data == id) {
1051 BKE_object_material_resize(bmain, ob, *totcol, false);
1053 processed_objects++;
1054 BLI_assert(processed_objects <= id->us && processed_objects > 0);
1055 if (processed_objects == id->us) {
1056 break;
1057 }
1058 }
1059 }
1060 BKE_main_unlock(bmain);
1061}
1062
1063void BKE_id_material_assign(Main *bmain, ID *id, Material *ma, short act)
1064{
1065 Material *mao, **matar, ***matarar;
1066 short *totcolp;
1067
1068 if (act > MAXMAT) {
1069 return;
1070 }
1071 act = std::max<int>(act, 1);
1072
1073 /* test arraylens */
1074
1075 totcolp = BKE_id_material_len_p(id);
1076 matarar = BKE_id_material_array_p(id);
1077
1078 if (totcolp == nullptr || matarar == nullptr) {
1079 return;
1080 }
1081
1082 if (act > *totcolp) {
1083 matar = MEM_calloc_arrayN<Material *>(act, "matarray1");
1084
1085 if (*totcolp) {
1086 memcpy(matar, *matarar, sizeof(void *) * (*totcolp));
1087 MEM_freeN(*matarar);
1088 }
1089
1090 *matarar = matar;
1091 *totcolp = act;
1092 }
1093
1094 /* in data */
1095 mao = (*matarar)[act - 1];
1096 if (mao) {
1097 id_us_min(&mao->id);
1098 }
1099 (*matarar)[act - 1] = ma;
1100
1101 if (ma) {
1102 id_us_plus(&ma->id);
1103 }
1104
1108}
1109
1111 Main *bmain, Object *ob, Material *ma, short act, int assign_type, bool do_test_all)
1112{
1113 Material *mao, **matar, ***matarar;
1114 short *totcolp;
1115 char bit = 0;
1116
1117 if (act > MAXMAT) {
1118 return;
1119 }
1120 act = std::max<int>(act, 1);
1121
1122 /* test arraylens */
1123
1124 totcolp = BKE_object_material_len_p(ob);
1125 matarar = BKE_object_material_array_p(ob);
1126
1127 if (totcolp == nullptr || matarar == nullptr) {
1128 return;
1129 }
1130
1131 if (act > *totcolp) {
1132 matar = MEM_calloc_arrayN<Material *>(act, "matarray1");
1133
1134 if (*totcolp) {
1135 memcpy(matar, *matarar, sizeof(void *) * (*totcolp));
1136 MEM_freeN(*matarar);
1137 }
1138
1139 *matarar = matar;
1140 *totcolp = act;
1141 }
1142
1143 if (act > ob->totcol) {
1144 /* Need more space in the material arrays */
1145 ob->mat = static_cast<Material **>(
1146 MEM_recallocN_id(ob->mat, sizeof(void *) * act, "matarray2"));
1147 ob->matbits = static_cast<char *>(
1148 MEM_recallocN_id(ob->matbits, sizeof(char) * act, "matbits1"));
1149 ob->totcol = act;
1150 }
1151
1152 /* Determine the object/mesh linking */
1153 if (assign_type == BKE_MAT_ASSIGN_EXISTING) {
1154 /* keep existing option (avoid confusion in scripts),
1155 * intentionally ignore userpref (default to obdata). */
1156 bit = ob->matbits[act - 1];
1157 }
1158 else if (assign_type == BKE_MAT_ASSIGN_USERPREF && ob->totcol && ob->actcol) {
1159 /* copy from previous material */
1160 bit = ob->matbits[ob->actcol - 1];
1161 }
1162 else {
1163 switch (assign_type) {
1165 bit = 0;
1166 break;
1168 bit = 1;
1169 break;
1171 default:
1172 bit = (U.flag & USER_MAT_ON_OB) ? 1 : 0;
1173 break;
1174 }
1175 }
1176
1177 /* do it */
1178
1179 ob->matbits[act - 1] = bit;
1180 if (bit == 1) { /* in object */
1181 mao = ob->mat[act - 1];
1182 if (mao) {
1183 id_us_min(&mao->id);
1184 }
1185 ob->mat[act - 1] = ma;
1186 BKE_object_materials_sync_length(bmain, ob, static_cast<ID *>(ob->data));
1187 }
1188 else { /* in data */
1189 mao = (*matarar)[act - 1];
1190 if (mao) {
1191 id_us_min(&mao->id);
1192 }
1193 (*matarar)[act - 1] = ma;
1194 /* Data may be used by several objects. */
1195 if (do_test_all) {
1196 BKE_objects_materials_sync_length_all(bmain, static_cast<ID *>(ob->data));
1197 }
1198 }
1199
1200 if (ma) {
1201 id_us_plus(&ma->id);
1202 }
1203
1206}
1207
1208void BKE_object_material_assign(Main *bmain, Object *ob, Material *ma, short act, int assign_type)
1209{
1210 object_material_assign(bmain, ob, ma, act, assign_type, true);
1211}
1212
1214{
1215 object_material_assign(bmain, ob, ma, act, BKE_MAT_ASSIGN_OBDATA, false);
1216}
1217
1219{
1221 const short *totcol_p = BKE_object_material_len_p(ob);
1222
1223 BLI_array_permute(ob->mat, ob->totcol, remap);
1224
1225 if (ob->matbits) {
1226 BLI_array_permute(ob->matbits, ob->totcol, remap);
1227 }
1228
1229 if (matar) {
1230 BLI_array_permute(*matar, *totcol_p, remap);
1231 }
1232
1233 if (ob->type == OB_MESH) {
1234 BKE_mesh_material_remap(static_cast<Mesh *>(ob->data), remap, ob->totcol);
1235 }
1236 else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
1237 BKE_curve_material_remap(static_cast<Curve *>(ob->data), remap, ob->totcol);
1238 }
1239 else if (ob->type == OB_GREASE_PENCIL) {
1240 BKE_grease_pencil_material_remap(static_cast<GreasePencil *>(ob->data), remap, ob->totcol);
1241 }
1242 else {
1243 /* add support for this object data! */
1244 BLI_assert(matar == nullptr);
1245 }
1246}
1247
1248void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap_src_to_dst)
1249{
1250 if (ob_src->totcol == 0) {
1251 return;
1252 }
1253
1254 GHash *gh_mat_map = BLI_ghash_ptr_new_ex(__func__, ob_src->totcol);
1255
1256 for (int i = 0; i < ob_dst->totcol; i++) {
1257 Material *ma_src = BKE_object_material_get(ob_dst, i + 1);
1258 BLI_ghash_reinsert(gh_mat_map, ma_src, POINTER_FROM_INT(i), nullptr, nullptr);
1259 }
1260
1261 /* setup default mapping (when materials don't match) */
1262 {
1263 int i = 0;
1264 if (ob_dst->totcol >= ob_src->totcol) {
1265 for (; i < ob_src->totcol; i++) {
1266 remap_src_to_dst[i] = i;
1267 }
1268 }
1269 else {
1270 for (; i < ob_dst->totcol; i++) {
1271 remap_src_to_dst[i] = i;
1272 }
1273 for (; i < ob_src->totcol; i++) {
1274 remap_src_to_dst[i] = 0;
1275 }
1276 }
1277 }
1278
1279 for (int i = 0; i < ob_src->totcol; i++) {
1280 Material *ma_src = BKE_object_material_get(ob_src, i + 1);
1281
1282 if ((i < ob_dst->totcol) && (ma_src == BKE_object_material_get(ob_dst, i + 1))) {
1283 /* when objects have exact matching materials - keep existing index */
1284 }
1285 else {
1286 void **index_src_p = BLI_ghash_lookup_p(gh_mat_map, ma_src);
1287 if (index_src_p) {
1288 remap_src_to_dst[i] = POINTER_AS_INT(*index_src_p);
1289 }
1290 }
1291 }
1292
1293 BLI_ghash_free(gh_mat_map, nullptr, nullptr);
1294}
1295
1296void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, const ID *data_eval)
1297{
1298 ID *data_orig = static_cast<ID *>(ob_orig->data);
1299
1300 short *orig_totcol = BKE_id_material_len_p(data_orig);
1301 Material ***orig_mat = BKE_id_material_array_p(data_orig);
1302
1303 /* Can cast away const, because the data is not changed. */
1304 const short *eval_totcol = BKE_id_material_len_p((ID *)data_eval);
1305 Material ***eval_mat = BKE_id_material_array_p((ID *)data_eval);
1306
1307 if (ELEM(nullptr, orig_totcol, orig_mat, eval_totcol, eval_mat)) {
1308 return;
1309 }
1310
1311 /* Remove old materials from original geometry. */
1312 for (int i = 0; i < *orig_totcol; i++) {
1313 id_us_min(&(*orig_mat)[i]->id);
1314 }
1315 MEM_SAFE_FREE(*orig_mat);
1316
1317 /* Create new material slots based on materials on evaluated geometry. */
1318 *orig_totcol = *eval_totcol;
1319 *orig_mat = *eval_totcol > 0 ? MEM_calloc_arrayN<Material *>(*eval_totcol, __func__) : nullptr;
1320 for (int i = 0; i < *eval_totcol; i++) {
1321 Material *material_eval = (*eval_mat)[i];
1322 if (material_eval != nullptr) {
1323 Material *material_orig = DEG_get_original(material_eval);
1324 (*orig_mat)[i] = material_orig;
1325 id_us_plus(&material_orig->id);
1326 }
1327 }
1328 BKE_object_materials_sync_length(bmain, ob_orig, data_orig);
1329}
1330
1332 Main *bmain, Object *ob, Material ***matar, int totcol, const bool to_object_only)
1333{
1334 int actcol_orig = ob->actcol;
1335
1336 while ((ob->totcol > totcol) && BKE_object_material_slot_remove(bmain, ob)) {
1337 /* pass */
1338 }
1339
1340 /* now we have the right number of slots */
1341 for (int i = 0; i < totcol; i++) {
1342 if (to_object_only && ob->matbits && ob->matbits[i] == 0) {
1343 /* If we only assign to object, and that slot uses obdata material, do nothing. */
1344 continue;
1345 }
1347 ob,
1348 (*matar)[i],
1349 i + 1,
1351 }
1352
1353 actcol_orig = std::min(actcol_orig, ob->totcol);
1354
1355 ob->actcol = actcol_orig;
1356}
1357
1359{
1360 Material ***matarar;
1361 short a, *totcolp;
1362
1363 if (ma == nullptr) {
1364 return 0;
1365 }
1366
1367 totcolp = BKE_object_material_len_p(ob);
1368 matarar = BKE_object_material_array_p(ob);
1369
1370 if (totcolp == nullptr || matarar == nullptr) {
1371 return 0;
1372 }
1373
1374 for (a = 0; a < *totcolp; a++) {
1375 if ((*matarar)[a] == ma) {
1376 break;
1377 }
1378 }
1379 if (a < *totcolp) {
1380 return a + 1;
1381 }
1382 return 0;
1383}
1384
1385bool BKE_object_material_slot_add(Main *bmain, Object *ob, const bool set_active)
1386{
1387 if (ob == nullptr) {
1388 return false;
1389 }
1390 if (ob->totcol >= MAXMAT) {
1391 return false;
1392 }
1393
1394 BKE_object_material_assign(bmain, ob, nullptr, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
1395 if (set_active) {
1396 ob->actcol = ob->totcol;
1397 }
1398 return true;
1399}
1400
1401/* ****************** */
1402
1404{
1405 Material *mao, ***matarar;
1406 short *totcolp;
1407
1408 if (ob == nullptr || ob->totcol == 0) {
1409 return false;
1410 }
1411
1412 /* this should never happen and used to crash */
1413 if (ob->actcol <= 0) {
1414 CLOG_ERROR(&LOG, "invalid material index %d, report a bug!", ob->actcol);
1415 return false;
1416 }
1417
1418 /* Take a mesh/curve/meta-ball as starting point, remove 1 index,
1419 * AND with all objects that share the `ob->data`.
1420 * After that check indices in mesh/curve/meta-ball! */
1421
1422 totcolp = BKE_object_material_len_p(ob);
1423 matarar = BKE_object_material_array_p(ob);
1424
1425 if (ELEM(nullptr, matarar, *matarar)) {
1426 return false;
1427 }
1428
1429 /* can happen on face selection in editmode */
1431
1432 /* we delete the actcol */
1433 mao = (*matarar)[ob->actcol - 1];
1434 if (mao) {
1435 id_us_min(&mao->id);
1436 }
1437
1438 for (int a = ob->actcol; a < ob->totcol; a++) {
1439 (*matarar)[a - 1] = (*matarar)[a];
1440 }
1441 (*totcolp)--;
1442
1443 if (*totcolp == 0) {
1444 MEM_freeN(*matarar);
1445 *matarar = nullptr;
1446 }
1447
1448 const int actcol = ob->actcol;
1449
1450 for (Object *obt = static_cast<Object *>(bmain->objects.first); obt;
1451 obt = static_cast<Object *>(obt->id.next))
1452 {
1453 if (obt->data == ob->data) {
1454 /* Can happen when object material lists are used, see: #52953 */
1455 if (actcol > obt->totcol) {
1456 continue;
1457 }
1458 /* WATCH IT: do not use actcol from ob or from obt (can become zero) */
1459 mao = obt->mat[actcol - 1];
1460 if (mao) {
1461 id_us_min(&mao->id);
1462 }
1463
1464 for (int a = actcol; a < obt->totcol; a++) {
1465 obt->mat[a - 1] = obt->mat[a];
1466 obt->matbits[a - 1] = obt->matbits[a];
1467 }
1468 obt->totcol--;
1470
1471 if (obt->totcol == 0) {
1472 MEM_freeN(obt->mat);
1473 MEM_freeN(obt->matbits);
1474 obt->mat = nullptr;
1475 obt->matbits = nullptr;
1476 }
1477 }
1478 }
1479
1480 /* check indices from mesh and grease pencil. */
1482 material_data_index_remove_id((ID *)ob->data, actcol - 1);
1483 if (ob->runtime->curve_cache) {
1484 BKE_displist_free(&ob->runtime->curve_cache->disp);
1485 }
1486 }
1487
1488 return true;
1489}
1490
1492{
1493 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
1494 if (sock->link) {
1495 bNode *inode = sock->link->fromnode;
1496 if (inode->typeinfo->nclass == NODE_CLASS_INPUT &&
1497 inode->typeinfo->type_legacy == SH_NODE_UVMAP)
1498 {
1499 return inode;
1500 }
1501
1502 return nodetree_uv_node_recursive(inode);
1503 }
1504 }
1505
1506 return nullptr;
1507}
1508
1515
1516using ForEachTexNodeCallback = bool (*)(bNode *node, void *userdata);
1518 ForEachTexNodeCallback callback,
1519 void *userdata,
1520 ePaintSlotFilter slot_filter)
1521{
1522 const bool do_image_nodes = (slot_filter & PAINT_SLOT_IMAGE) != 0;
1523 const bool do_color_attributes = (slot_filter & PAINT_SLOT_COLOR_ATTRIBUTE) != 0;
1524 for (bNode *node : nodetree->all_nodes()) {
1525 if (do_image_nodes && node->typeinfo->nclass == NODE_CLASS_TEXTURE &&
1526 node->typeinfo->type_legacy == SH_NODE_TEX_IMAGE && node->id)
1527 {
1528 if (!callback(node, userdata)) {
1529 return false;
1530 }
1531 }
1532 if (do_color_attributes && node->typeinfo->type_legacy == SH_NODE_ATTRIBUTE) {
1533 if (!callback(node, userdata)) {
1534 return false;
1535 }
1536 }
1537 else if (node->is_group() && node->id) {
1538 /* recurse into the node group and see if it contains any textures */
1539 if (!ntree_foreach_texnode_recursive((bNodeTree *)node->id, callback, userdata, slot_filter))
1540 {
1541 return false;
1542 }
1543 }
1544 }
1545 return true;
1546}
1547
1548static bool count_texture_nodes_cb(bNode * /*node*/, void *userdata)
1549{
1550 (*((int *)userdata))++;
1551 return true;
1552}
1553
1555{
1556 int tex_nodes = 0;
1557 ntree_foreach_texnode_recursive(nodetree, count_texture_nodes_cb, &tex_nodes, slot_filter);
1558
1559 return tex_nodes;
1560}
1561
1569
1570static bool fill_texpaint_slots_cb(bNode *node, void *userdata)
1571{
1572 FillTexPaintSlotsData *fill_data = static_cast<FillTexPaintSlotsData *>(userdata);
1573
1574 Material *ma = fill_data->ma;
1575 int index = fill_data->index;
1576 fill_data->index++;
1577
1578 if (fill_data->active_node == node) {
1579 ma->paint_active_slot = index;
1580 }
1581
1582 switch (node->type_legacy) {
1583 case SH_NODE_TEX_IMAGE: {
1584 TexPaintSlot *slot = &ma->texpaintslot[index];
1585 slot->ima = (Image *)node->id;
1586 NodeTexImage *storage = (NodeTexImage *)node->storage;
1587 slot->interp = storage->interpolation;
1588 slot->image_user = &storage->iuser;
1589 /* For new renderer, we need to traverse the tree back in search of a UV node. */
1590 bNode *uvnode = nodetree_uv_node_recursive(node);
1591
1592 if (uvnode) {
1593 NodeShaderUVMap *uv_storage = (NodeShaderUVMap *)uvnode->storage;
1594 slot->uvname = uv_storage->uv_map;
1595 /* set a value to index so UI knows that we have a valid pointer for the mesh */
1596 slot->valid = true;
1597 }
1598 else {
1599 /* just invalidate the index here so UV map does not get displayed on the UI */
1600 slot->valid = false;
1601 }
1602 break;
1603 }
1604
1605 case SH_NODE_ATTRIBUTE: {
1606 TexPaintSlot *slot = &ma->texpaintslot[index];
1607 NodeShaderAttribute *storage = static_cast<NodeShaderAttribute *>(node->storage);
1608 slot->attribute_name = storage->name;
1609 if (storage->type == SHD_ATTRIBUTE_GEOMETRY) {
1610 const Mesh *mesh = (const Mesh *)fill_data->ob->data;
1611 const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name);
1612 slot->valid = layer != nullptr;
1613 }
1614
1615 /* Do not show unsupported attributes. */
1616 if (!slot->valid) {
1617 slot->attribute_name = nullptr;
1618 fill_data->index--;
1619 }
1620
1621 break;
1622 }
1623 }
1624
1625 return fill_data->index != fill_data->slot_len;
1626}
1627
1629 bNode *active_node,
1630 const Object *ob,
1631 Material *ma,
1632 int slot_len,
1633 ePaintSlotFilter slot_filter)
1634{
1635 FillTexPaintSlotsData fill_data = {active_node, ob, ma, 0, slot_len};
1636 ntree_foreach_texnode_recursive(nodetree, fill_texpaint_slots_cb, &fill_data, slot_filter);
1637}
1638
1641{
1642 ePaintSlotFilter slot_filter = PAINT_SLOT_IMAGE;
1643 if (ob->mode == OB_MODE_SCULPT && USER_EXPERIMENTAL_TEST(&U, use_sculpt_texture_paint)) {
1644 slot_filter |= PAINT_SLOT_COLOR_ATTRIBUTE;
1645 }
1646 return slot_filter;
1647}
1648
1650{
1651 if (!ma) {
1652 return;
1653 }
1654
1655 const ePaintSlotFilter slot_filter = material_paint_slot_filter(ob);
1656
1657 const TexPaintSlot *prev_texpaintslot = ma->texpaintslot;
1658 const int prev_paint_active_slot = ma->paint_active_slot;
1659 const int prev_paint_clone_slot = ma->paint_clone_slot;
1660 const int prev_tot_slots = ma->tot_slots;
1661
1662 ma->texpaintslot = nullptr;
1663 ma->tot_slots = 0;
1664
1666 ma->paint_active_slot = 0;
1667 ma->paint_clone_slot = 0;
1668 }
1669 else if (!(ma->nodetree)) {
1670 ma->paint_active_slot = 0;
1671 ma->paint_clone_slot = 0;
1672 }
1673 else {
1674 int count = count_texture_nodes_recursive(ma->nodetree, slot_filter);
1675
1676 if (count == 0) {
1677 ma->paint_active_slot = 0;
1678 ma->paint_clone_slot = 0;
1679 }
1680 else {
1681 ma->texpaintslot = MEM_calloc_arrayN<TexPaintSlot>(count, "texpaint_slots");
1682
1684
1685 fill_texpaint_slots_recursive(ma->nodetree, active_node, ob, ma, count, slot_filter);
1686
1687 ma->tot_slots = count;
1688
1689 if (ma->paint_active_slot >= count) {
1690 ma->paint_active_slot = count - 1;
1691 }
1692
1693 if (ma->paint_clone_slot >= count) {
1694 ma->paint_clone_slot = count - 1;
1695 }
1696 }
1697 }
1698
1699 /* Copy-on-eval needed when adding texture slot on an object with no materials.
1700 * But do it only when slots actually change to avoid continuous depsgraph updates. */
1701 if (ma->tot_slots != prev_tot_slots || ma->paint_active_slot != prev_paint_active_slot ||
1702 ma->paint_clone_slot != prev_paint_clone_slot ||
1703 (ma->texpaintslot && prev_texpaintslot &&
1704 memcmp(ma->texpaintslot, prev_texpaintslot, sizeof(*ma->texpaintslot) * ma->tot_slots) !=
1705 0))
1706 {
1708 }
1709
1710 MEM_SAFE_FREE(prev_texpaintslot);
1711}
1712
1714{
1715 for (int i = 1; i < ob->totcol + 1; i++) {
1717 BKE_texpaint_slot_refresh_cache(scene, ma, ob);
1718 }
1719}
1720
1725
1726static bool texpaint_slot_node_find_cb(bNode *node, void *userdata)
1727{
1728 FindTexPaintNodeData *find_data = static_cast<FindTexPaintNodeData *>(userdata);
1729 if (find_data->slot->ima && node->type_legacy == SH_NODE_TEX_IMAGE) {
1730 Image *node_ima = (Image *)node->id;
1731 if (find_data->slot->ima == node_ima) {
1732 find_data->r_node = node;
1733 return false;
1734 }
1735 }
1736
1737 if (find_data->slot->attribute_name && node->type_legacy == SH_NODE_ATTRIBUTE) {
1738 NodeShaderAttribute *storage = static_cast<NodeShaderAttribute *>(node->storage);
1739 if (STREQLEN(find_data->slot->attribute_name, storage->name, sizeof(storage->name))) {
1740 find_data->r_node = node;
1741 return false;
1742 }
1743 }
1744
1745 return true;
1746}
1747
1749{
1750 if (ma->texpaintslot == nullptr) {
1751 return nullptr;
1752 }
1753
1754 if (texpaint_slot >= ma->tot_slots) {
1755 return nullptr;
1756 }
1757
1758 TexPaintSlot *slot = &ma->texpaintslot[texpaint_slot];
1759 FindTexPaintNodeData find_data = {slot, nullptr};
1762 &find_data,
1764
1765 return find_data.r_node;
1766}
1767
1768void ramp_blend(int type, float r_col[3], const float fac, const float col[3])
1769{
1770 float tmp, facm = 1.0f - fac;
1771
1772 switch (type) {
1773 case MA_RAMP_BLEND:
1774 r_col[0] = facm * (r_col[0]) + fac * col[0];
1775 r_col[1] = facm * (r_col[1]) + fac * col[1];
1776 r_col[2] = facm * (r_col[2]) + fac * col[2];
1777 break;
1778 case MA_RAMP_ADD:
1779 r_col[0] += fac * col[0];
1780 r_col[1] += fac * col[1];
1781 r_col[2] += fac * col[2];
1782 break;
1783 case MA_RAMP_MULT:
1784 r_col[0] *= (facm + fac * col[0]);
1785 r_col[1] *= (facm + fac * col[1]);
1786 r_col[2] *= (facm + fac * col[2]);
1787 break;
1788 case MA_RAMP_SCREEN:
1789 r_col[0] = 1.0f - (facm + fac * (1.0f - col[0])) * (1.0f - r_col[0]);
1790 r_col[1] = 1.0f - (facm + fac * (1.0f - col[1])) * (1.0f - r_col[1]);
1791 r_col[2] = 1.0f - (facm + fac * (1.0f - col[2])) * (1.0f - r_col[2]);
1792 break;
1793 case MA_RAMP_OVERLAY:
1794 if (r_col[0] < 0.5f) {
1795 r_col[0] *= (facm + 2.0f * fac * col[0]);
1796 }
1797 else {
1798 r_col[0] = 1.0f - (facm + 2.0f * fac * (1.0f - col[0])) * (1.0f - r_col[0]);
1799 }
1800 if (r_col[1] < 0.5f) {
1801 r_col[1] *= (facm + 2.0f * fac * col[1]);
1802 }
1803 else {
1804 r_col[1] = 1.0f - (facm + 2.0f * fac * (1.0f - col[1])) * (1.0f - r_col[1]);
1805 }
1806 if (r_col[2] < 0.5f) {
1807 r_col[2] *= (facm + 2.0f * fac * col[2]);
1808 }
1809 else {
1810 r_col[2] = 1.0f - (facm + 2.0f * fac * (1.0f - col[2])) * (1.0f - r_col[2]);
1811 }
1812 break;
1813 case MA_RAMP_SUB:
1814 r_col[0] -= fac * col[0];
1815 r_col[1] -= fac * col[1];
1816 r_col[2] -= fac * col[2];
1817 break;
1818 case MA_RAMP_DIV:
1819 if (col[0] != 0.0f) {
1820 r_col[0] = facm * (r_col[0]) + fac * (r_col[0]) / col[0];
1821 }
1822 if (col[1] != 0.0f) {
1823 r_col[1] = facm * (r_col[1]) + fac * (r_col[1]) / col[1];
1824 }
1825 if (col[2] != 0.0f) {
1826 r_col[2] = facm * (r_col[2]) + fac * (r_col[2]) / col[2];
1827 }
1828 break;
1829 case MA_RAMP_DIFF:
1830 r_col[0] = facm * (r_col[0]) + fac * fabsf(r_col[0] - col[0]);
1831 r_col[1] = facm * (r_col[1]) + fac * fabsf(r_col[1] - col[1]);
1832 r_col[2] = facm * (r_col[2]) + fac * fabsf(r_col[2] - col[2]);
1833 break;
1834 case MA_RAMP_EXCLUSION:
1835 r_col[0] = max_ff(facm * (r_col[0]) + fac * (r_col[0] + col[0] - 2.0f * r_col[0] * col[0]),
1836 0.0f);
1837 r_col[1] = max_ff(facm * (r_col[1]) + fac * (r_col[1] + col[1] - 2.0f * r_col[1] * col[1]),
1838 0.0f);
1839 r_col[2] = max_ff(facm * (r_col[2]) + fac * (r_col[2] + col[2] - 2.0f * r_col[2] * col[2]),
1840 0.0f);
1841 break;
1842 case MA_RAMP_DARK:
1843 r_col[0] = min_ff(r_col[0], col[0]) * fac + r_col[0] * facm;
1844 r_col[1] = min_ff(r_col[1], col[1]) * fac + r_col[1] * facm;
1845 r_col[2] = min_ff(r_col[2], col[2]) * fac + r_col[2] * facm;
1846 break;
1847 case MA_RAMP_LIGHT:
1848 r_col[0] = max_ff(r_col[0], col[0]) * fac + r_col[0] * facm;
1849 r_col[1] = max_ff(r_col[1], col[1]) * fac + r_col[1] * facm;
1850 r_col[2] = max_ff(r_col[2], col[2]) * fac + r_col[2] * facm;
1851 break;
1852 case MA_RAMP_DODGE:
1853 if (r_col[0] != 0.0f) {
1854 tmp = 1.0f - fac * col[0];
1855 if (tmp <= 0.0f) {
1856 r_col[0] = 1.0f;
1857 }
1858 else if ((tmp = (r_col[0]) / tmp) > 1.0f) {
1859 r_col[0] = 1.0f;
1860 }
1861 else {
1862 r_col[0] = tmp;
1863 }
1864 }
1865 if (r_col[1] != 0.0f) {
1866 tmp = 1.0f - fac * col[1];
1867 if (tmp <= 0.0f) {
1868 r_col[1] = 1.0f;
1869 }
1870 else if ((tmp = (r_col[1]) / tmp) > 1.0f) {
1871 r_col[1] = 1.0f;
1872 }
1873 else {
1874 r_col[1] = tmp;
1875 }
1876 }
1877 if (r_col[2] != 0.0f) {
1878 tmp = 1.0f - fac * col[2];
1879 if (tmp <= 0.0f) {
1880 r_col[2] = 1.0f;
1881 }
1882 else if ((tmp = (r_col[2]) / tmp) > 1.0f) {
1883 r_col[2] = 1.0f;
1884 }
1885 else {
1886 r_col[2] = tmp;
1887 }
1888 }
1889 break;
1890 case MA_RAMP_BURN:
1891 tmp = facm + fac * col[0];
1892
1893 if (tmp <= 0.0f) {
1894 r_col[0] = 0.0f;
1895 }
1896 else if ((tmp = (1.0f - (1.0f - (r_col[0])) / tmp)) < 0.0f) {
1897 r_col[0] = 0.0f;
1898 }
1899 else if (tmp > 1.0f) {
1900 r_col[0] = 1.0f;
1901 }
1902 else {
1903 r_col[0] = tmp;
1904 }
1905
1906 tmp = facm + fac * col[1];
1907 if (tmp <= 0.0f) {
1908 r_col[1] = 0.0f;
1909 }
1910 else if ((tmp = (1.0f - (1.0f - (r_col[1])) / tmp)) < 0.0f) {
1911 r_col[1] = 0.0f;
1912 }
1913 else if (tmp > 1.0f) {
1914 r_col[1] = 1.0f;
1915 }
1916 else {
1917 r_col[1] = tmp;
1918 }
1919
1920 tmp = facm + fac * col[2];
1921 if (tmp <= 0.0f) {
1922 r_col[2] = 0.0f;
1923 }
1924 else if ((tmp = (1.0f - (1.0f - (r_col[2])) / tmp)) < 0.0f) {
1925 r_col[2] = 0.0f;
1926 }
1927 else if (tmp > 1.0f) {
1928 r_col[2] = 1.0f;
1929 }
1930 else {
1931 r_col[2] = tmp;
1932 }
1933 break;
1934 case MA_RAMP_HUE: {
1935 float rH, rS, rV;
1936 float colH, colS, colV;
1937 float tmpr, tmpg, tmpb;
1938 rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
1939 if (colS != 0) {
1940 rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
1941 hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb);
1942 r_col[0] = facm * (r_col[0]) + fac * tmpr;
1943 r_col[1] = facm * (r_col[1]) + fac * tmpg;
1944 r_col[2] = facm * (r_col[2]) + fac * tmpb;
1945 }
1946 break;
1947 }
1948 case MA_RAMP_SAT: {
1949 float rH, rS, rV;
1950 float colH, colS, colV;
1951 rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
1952 if (rS != 0) {
1953 rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
1954 hsv_to_rgb(rH, (facm * rS + fac * colS), rV, r_col + 0, r_col + 1, r_col + 2);
1955 }
1956 break;
1957 }
1958 case MA_RAMP_VAL: {
1959 float rH, rS, rV;
1960 float colH, colS, colV;
1961 rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
1962 rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
1963 hsv_to_rgb(rH, rS, (facm * rV + fac * colV), r_col + 0, r_col + 1, r_col + 2);
1964 break;
1965 }
1966 case MA_RAMP_COLOR: {
1967 float rH, rS, rV;
1968 float colH, colS, colV;
1969 float tmpr, tmpg, tmpb;
1970 rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
1971 if (colS != 0) {
1972 rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
1973 hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb);
1974 r_col[0] = facm * (r_col[0]) + fac * tmpr;
1975 r_col[1] = facm * (r_col[1]) + fac * tmpg;
1976 r_col[2] = facm * (r_col[2]) + fac * tmpb;
1977 }
1978 break;
1979 }
1980 case MA_RAMP_SOFT: {
1981 float scr, scg, scb;
1982
1983 /* first calculate non-fac based Screen mix */
1984 scr = 1.0f - (1.0f - col[0]) * (1.0f - r_col[0]);
1985 scg = 1.0f - (1.0f - col[1]) * (1.0f - r_col[1]);
1986 scb = 1.0f - (1.0f - col[2]) * (1.0f - r_col[2]);
1987
1988 r_col[0] = facm * (r_col[0]) +
1989 fac * (((1.0f - r_col[0]) * col[0] * (r_col[0])) + (r_col[0] * scr));
1990 r_col[1] = facm * (r_col[1]) +
1991 fac * (((1.0f - r_col[1]) * col[1] * (r_col[1])) + (r_col[1] * scg));
1992 r_col[2] = facm * (r_col[2]) +
1993 fac * (((1.0f - r_col[2]) * col[2] * (r_col[2])) + (r_col[2] * scb));
1994 break;
1995 }
1996 case MA_RAMP_LINEAR:
1997 if (col[0] > 0.5f) {
1998 r_col[0] = r_col[0] + fac * (2.0f * (col[0] - 0.5f));
1999 }
2000 else {
2001 r_col[0] = r_col[0] + fac * (2.0f * (col[0]) - 1.0f);
2002 }
2003 if (col[1] > 0.5f) {
2004 r_col[1] = r_col[1] + fac * (2.0f * (col[1] - 0.5f));
2005 }
2006 else {
2007 r_col[1] = r_col[1] + fac * (2.0f * (col[1]) - 1.0f);
2008 }
2009 if (col[2] > 0.5f) {
2010 r_col[2] = r_col[2] + fac * (2.0f * (col[2] - 0.5f));
2011 }
2012 else {
2013 r_col[2] = r_col[2] + fac * (2.0f * (col[2]) - 1.0f);
2014 }
2015 break;
2016 }
2017}
2018
2019void BKE_material_eval(Depsgraph *depsgraph, Material *material)
2020{
2021 DEG_debug_print_eval(depsgraph, __func__, material->id.name, material);
2022 GPU_material_free(&material->gpumaterial);
2023}
2024
2025/* Default Materials
2026 *
2027 * Used for rendering when objects have no materials assigned, and initializing
2028 * default shader nodes. */
2029
2035
2042
2043static Material *material_default_create(Material **ma_p, const char *name)
2044{
2045 *ma_p = BKE_id_new_nomain<Material>(name);
2046 return *ma_p;
2047}
2048
2050{
2051 Material *ma = material_default_create(ma_p, "Default GPencil");
2052
2054 add_v3_fl(&ma->gp_style->stroke_rgba[0], 0.6f);
2055}
2056
2058{
2059 Material *ma = material_default_create(ma_p, "Default Surface");
2060
2062 nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
2063 ma->use_nodes = true;
2064
2066 bNodeSocket *base_color = blender::bke::node_find_socket(*principled, SOCK_IN, "Base Color");
2067 copy_v3_v3(((bNodeSocketValueRGBA *)base_color->default_value)->value, &ma->r);
2068
2070
2072 *principled,
2073 *blender::bke::node_find_socket(*principled, SOCK_OUT, "BSDF"),
2074 *output,
2076
2077 principled->location[0] = -200.0f;
2078 principled->location[1] = 100.0f;
2079 output->location[0] = 200.0f;
2080 output->location[1] = 100.0f;
2081
2083}
2084
2086{
2087 Material *ma = material_default_create(ma_p, "Default Volume");
2088
2090 nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
2091 ma->use_nodes = true;
2092
2094 nullptr, *ntree, SH_NODE_VOLUME_PRINCIPLED);
2096
2098 *principled,
2099 *blender::bke::node_find_socket(*principled, SOCK_OUT, "Volume"),
2100 *output,
2102
2103 principled->location[0] = -200.0f;
2104 principled->location[1] = 100.0f;
2105 output->location[0] = 200.0f;
2106 output->location[1] = 100.0f;
2107
2109}
2110
2112{
2113 Material *ma = material_default_create(ma_p, "Default Holdout");
2114
2116 nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
2117 ma->use_nodes = true;
2118
2119 bNode *holdout = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_HOLDOUT);
2121
2123 *holdout,
2124 *blender::bke::node_find_socket(*holdout, SOCK_OUT, "Holdout"),
2125 *output,
2127
2128 holdout->location[0] = 10.0f;
2129 holdout->location[1] = 300.0f;
2130 output->location[0] = 300.0f;
2131 output->location[1] = 300.0f;
2132
2134}
2135
2140
2145
2150
2155
2160
2162{
2163 for (int i = 0; default_materials[i]; i++) {
2165 if (ma && ma->gpumaterial.first) {
2167 }
2168 }
2169}
2170
2171/* Module functions called on startup and exit. */
2172
2174{
2175 for (int i = 0; default_materials[i]; i++) {
2176 BLI_assert_msg(*default_materials[i] == nullptr,
2177 "Default material pointers should always be null when initializing them, maybe "
2178 "missing a call to `BKE_materials_exit` first?");
2179 }
2180
2186}
2187
2189{
2190 for (int i = 0; default_materials[i]; i++) {
2192 *default_materials[i] = nullptr;
2193 if (ma) {
2194 BKE_id_free(nullptr, &ma->id);
2195 }
2196 }
2197}
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:5376
void BKE_curve_material_index_remove(Curve *cu, int index)
Definition curve.cc:5289
bool BKE_curve_material_index_used(const Curve *cu, int index)
Definition curve.cc:5308
void BKE_curve_material_index_clear(Curve *cu)
Definition curve.cc:5329
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:44
@ LIB_ID_CREATE_NO_ALLOCATE
@ LIB_ID_COPY_NO_PREVIEW
@ LIB_ID_CREATE_LOCAL
@ LIB_ID_CREATE_NO_USER_REFCOUNT
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:663
void BKE_id_free(Main *bmain, void *idv)
void id_us_plus(ID *id)
Definition lib_id.cc:353
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1495
void id_us_min(ID *id)
Definition lib_id.cc:361
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1500
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2611
#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
LibraryForeachIDFlag BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
Definition lib_query.cc:129
@ IDWALK_DO_DEPRECATED_POINTERS
#define BKE_LIB_FOREACHID_PROCESS_ID_NOCHECK(data_, id_, cb_flag_)
void BKE_main_lock(Main *bmain)
Definition main.cc:484
void BKE_main_unlock(Main *bmain)
Definition main.cc:489
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:433
#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:182
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_RECALC_SHADING
Definition DNA_ID.h:1002
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ ID_TAG_MISSING
Definition DNA_ID.h:775
@ INDEX_ID_MA
Definition DNA_ID.h:1221
@ 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
@ 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
#define MAXMAT
@ SHD_ATTRIBUTE_GEOMETRY
@ SOCK_OUT
@ SOCK_IN
@ 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.
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)
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
#define fabsf(x)
KDTree_3d * tree
uint col
#define output
#define MEM_recallocN(vmemh, len)
#define FILTER_ID_MA
#define MEM_SAFE_FREE(v)
#define FILTER_ID_GR
#define FILTER_ID_TE
#define MEM_reallocN(vmemh, len)
#define GS(a)
int count
#define LOG(severity)
Definition log.h:32
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:4375
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2864
void node_tree_blend_write(BlendWriter *writer, bNodeTree *ntree)
Definition node.cc:1464
bNodeTree * node_tree_localize(bNodeTree *ntree, std::optional< ID * > new_owner_id)
Definition node.cc:4858
bNode * node_get_active_paint_canvas(bNodeTree &ntree)
bNode * node_add_static_node(const bContext *C, bNodeTree &ntree, int type)
Definition node.cc:3804
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:4087
void node_set_active(bNodeTree &ntree, bNode &node)
Definition node.cc:4996
void node_tree_free_embedded_tree(bNodeTree *ntree)
Definition node.cc:4724
return ret
struct Material ** mat
short totcol
struct Material ** mat
struct Material ** material_array
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
int us
Definition DNA_ID.h:425
void * next
Definition DNA_ID.h:407
char name[66]
Definition DNA_ID.h:415
void * first
ListBase objects
Definition BKE_main.hh:247
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:139