diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index 43f767fa2f9..7d19373e566 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -37,6 +37,7 @@ #include "BLI_assert.h" #include "BLI_listbase.h" #include "BLI_map.hh" +#include "BLI_math_base_safe.h" #include "BLI_math_vector.h" #include "BLI_set.hh" #include "BLI_string.h" @@ -1059,6 +1060,165 @@ static void enable_geometry_nodes_is_modifier(Main &bmain) } } +static void versioning_convert_combined_noise_texture_node(bNodeTree *ntree) +{ + /* Convert future combined Noise Texture back to Musgrave and Noise Texture nodes. */ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type != SH_NODE_TEX_NOISE) { + continue; + } + + const NodeTexNoise *noise_data = static_cast(node->storage); + if (!noise_data || noise_data->type == SHD_NOISE_FBM) { + continue; + } + + /* Does the node have the expected new sockets? */ + bNodeSocket *height_socket = nodeFindSocket(node, SOCK_OUT, "Fac"); + bNodeSocket *roughness_socket = nodeFindSocket(node, SOCK_IN, "Roughness"); + bNodeSocket *detail_socket = nodeFindSocket(node, SOCK_IN, "Detail"); + bNodeSocket *lacunarity_socket = nodeFindSocket(node, SOCK_IN, "Lacunarity"); + + if (!(height_socket && roughness_socket && detail_socket && lacunarity_socket)) { + continue; + } + + /* Delete links to sockets that don't exist in Blender 4.0. */ + LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) { + if (((link->tonode == node) && STREQ(link->tosock->identifier, "Distortion")) || + ((link->fromnode == node) && STREQ(link->fromsock->identifier, "Color"))) + { + nodeRemLink(ntree, link); + } + } + + /* Change node idname and storage to Musgrave. */ + STRNCPY(node->idname, "ShaderNodeTexMusgrave"); + node->type = SH_NODE_TEX_MUSGRAVE; + NodeTexMusgrave *data = MEM_cnew(__func__); + data->base = noise_data->base; + data->musgrave_type = noise_data->type; + data->dimensions = noise_data->dimensions; + MEM_freeN(node->storage); + node->storage = data; + + /* Convert socket names and labels. */ + bNodeSocket *dimension_socket = roughness_socket; + STRNCPY(dimension_socket->identifier, "Dimension"); + STRNCPY(dimension_socket->name, "Dimension"); + + STRNCPY(height_socket->label, "Height"); + + /* Find links to convert. */ + bNodeLink *detail_link = nullptr; + bNode *detail_from_node = nullptr; + bNodeSocket *detail_from_socket = nullptr; + float *detail = version_cycles_node_socket_float_value(detail_socket); + + bNodeLink *dimension_link = nullptr; + bNode *dimension_from_node = nullptr; + bNodeSocket *dimension_from_socket = nullptr; + float *dimension = version_cycles_node_socket_float_value(dimension_socket); + + bNodeLink *lacunarity_link = nullptr; + bNode *lacunarity_from_node = nullptr; + bNodeSocket *lacunarity_from_socket = nullptr; + float *lacunarity = version_cycles_node_socket_float_value(lacunarity_socket); + + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { + /* Find links, nodes and sockets. */ + if (link->tonode == node) { + if (link->tosock == detail_socket) { + detail_link = link; + detail_from_node = link->fromnode; + detail_from_socket = link->fromsock; + } + if (link->tosock == dimension_socket) { + dimension_link = link; + dimension_from_node = link->fromnode; + dimension_from_socket = link->fromsock; + } + if (link->tosock == lacunarity_socket) { + lacunarity_link = link; + lacunarity_from_node = link->fromnode; + lacunarity_from_socket = link->fromsock; + } + } + } + + float locy_offset = 0.0f; + + if (detail_link != nullptr) { + locy_offset -= 40.0f; + + /* Add Add Math node before Detail input. */ + + bNode *add_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_MATH); + add_node->parent = node->parent; + add_node->custom1 = NODE_MATH_ADD; + add_node->locx = node->locx; + add_node->locy = node->locy - 280.0f; + add_node->flag |= NODE_HIDDEN; + bNodeSocket *add_socket_A = static_cast(BLI_findlink(&add_node->inputs, 0)); + bNodeSocket *add_socket_B = static_cast(BLI_findlink(&add_node->inputs, 1)); + bNodeSocket *add_socket_out = nodeFindSocket(add_node, SOCK_OUT, "Value"); + + *version_cycles_node_socket_float_value(add_socket_B) = 1.0f; + + nodeRemLink(ntree, detail_link); + nodeAddLink(ntree, detail_from_node, detail_from_socket, add_node, add_socket_A); + nodeAddLink(ntree, add_node, add_socket_out, node, detail_socket); + } + else { + *detail = std::clamp(*detail + 1.0f, 0.0f, 15.0f); + } + + if ((dimension_link != nullptr) || (lacunarity_link != nullptr)) { + /* Add Logarithm Math node and Multiply Math node before Roughness input. */ + + bNode *log_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_MATH); + log_node->parent = node->parent; + log_node->custom1 = NODE_MATH_LOGARITHM; + log_node->locx = node->locx; + log_node->locy = node->locy - 320.0f + locy_offset; + log_node->flag |= NODE_HIDDEN; + bNodeSocket *log_socket_A = static_cast(BLI_findlink(&log_node->inputs, 0)); + bNodeSocket *log_socket_B = static_cast(BLI_findlink(&log_node->inputs, 1)); + bNodeSocket *log_socket_out = nodeFindSocket(log_node, SOCK_OUT, "Value"); + + bNode *mul_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_MATH); + mul_node->parent = node->parent; + mul_node->custom1 = NODE_MATH_MULTIPLY; + mul_node->locx = node->locx; + mul_node->locy = node->locy - 280.0f + locy_offset; + mul_node->flag |= NODE_HIDDEN; + bNodeSocket *mul_socket_A = static_cast(BLI_findlink(&mul_node->inputs, 0)); + bNodeSocket *mul_socket_B = static_cast(BLI_findlink(&mul_node->inputs, 1)); + bNodeSocket *mul_socket_out = nodeFindSocket(mul_node, SOCK_OUT, "Value"); + + *version_cycles_node_socket_float_value(log_socket_A) = *dimension; + *version_cycles_node_socket_float_value(log_socket_B) = *lacunarity; + *version_cycles_node_socket_float_value(mul_socket_B) = -1.0f; + + if (dimension_link) { + nodeRemLink(ntree, dimension_link); + nodeAddLink(ntree, dimension_from_node, dimension_from_socket, log_node, log_socket_A); + } + nodeAddLink(ntree, log_node, log_socket_out, mul_node, mul_socket_A); + nodeAddLink(ntree, mul_node, mul_socket_out, node, dimension_socket); + + if (lacunarity_link != nullptr) { + nodeAddLink(ntree, lacunarity_from_node, lacunarity_from_socket, log_node, log_socket_B); + } + } + else { + *dimension = -safe_logf(*dimension, *lacunarity); + } + } + + version_socket_update_is_used(ntree); +} + void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) { if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 1)) { @@ -1692,6 +1852,15 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) } } + if (MAIN_VERSION_FILE_ATLEAST(bmain, 401, 4)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type != NTREE_CUSTOM) { + versioning_convert_combined_noise_texture_node(ntree); + } + } + FOREACH_NODETREE_END; + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 4c224057f0a..6623e0f2f81 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1264,8 +1264,10 @@ typedef struct NodeTexGradient { typedef struct NodeTexNoise { NodeTexBase base; int dimensions; + /* uint8_t type only used for versioning. */ + uint8_t type; uint8_t normalize; - char _pad[3]; + char _pad[2]; } NodeTexNoise; typedef struct NodeTexVoronoi { @@ -2037,6 +2039,15 @@ enum { SHD_MUSGRAVE_HETERO_TERRAIN = 4, }; +/* Noise Texture enum only used for versioning. */ +enum { + SHD_NOISE_MULTIFRACTAL = 0, + SHD_NOISE_FBM = 1, + SHD_NOISE_HYBRID_MULTIFRACTAL = 2, + SHD_NOISE_RIDGED_MULTIFRACTAL = 3, + SHD_NOISE_HETERO_TERRAIN = 4, +}; + /* wave texture */ enum { SHD_WAVE_BANDS = 0,