1
1

Compare commits

...

44 Commits

Author SHA1 Message Date
4a7d8f378d Geometry Nodes: Add operation enum to boolean node 2020-10-26 13:56:54 -05:00
5288298cfa Merge branch 'geometry-nodes' into geometry-nodes-boolean-node 2020-10-26 10:41:51 -05:00
e04491073d Geometry Nodes: support evaluation with more than one group input
Group inputs are not yet exposed in the modifier. For now I just added
a simple float setting that will be passed to every float input of the group.
Inputs of other types have some default value.
2020-10-26 14:16:26 +01:00
a5dda5996e Geometry Nodes: connect group input and output by default 2020-10-26 13:29:03 +01:00
c48e4b7a44 Geometry Nodes: improve node tree evaluation
This change reduces the number of unnecessary copies of data
and avoids computing the same value more than once.
2020-10-26 13:27:02 +01:00
4ae2d6206a Geometry Nodes: initial Transform node
Most of this code has been written by @HooglyBoogly.
I just changed the exec funtion so that it does not have to make
a copy of the mesh.
2020-10-26 12:27:51 +01:00
47f5a635da Geometry Nodes: add utility method to check if a geometry has a mesh 2020-10-26 12:25:46 +01:00
eb8574bc8b Merge branch 'master' into geometry-nodes 2020-10-26 12:10:12 +01:00
3c02fdb2c8 Merge branch 'geometry-nodes-transform-node' into geometry-nodes-boolean-node 2020-10-24 12:50:20 -05:00
fe45f56515 Geometry nodes: Initial boolean node implementation
This is fairly hacky and crashy and should not be the final implementation
of this node, but it's nice to know that the basics are there to support
this kind of functionality. Ideally the boolean code would not need the
conversion to bmesh.
2020-10-24 12:48:21 -05:00
bf4b31468e Merge branch 'geometry-nodes' into geometry-nodes-transform-node 2020-10-24 12:42:24 -05:00
f5de32562e Cleanup: Remove unused variable 2020-10-24 12:42:04 -05:00
bc4e31afb6 Merge branch 'master' into geometry-nodes 2020-10-24 14:38:00 +02:00
23f17a9acd Remove unused variable 2020-10-23 16:05:57 -05:00
065dfdc529 Geometry Nodes: Add transform geometry node 2020-10-23 15:25:38 -05:00
9d7672be71 Merge branch 'master' into geometry-nodes 2020-10-23 15:18:20 +02:00
994e7178bb Geometry Nodes: make some function nodes available
We might not want to have all those nodes in a final version.
Some of them have been added with particle nodes in mind.
However, to test the evaluation system it is useful to have a
couple of nodes available.

Those nodes should "just" work, because their implementation
is reused from the particle nodes project.
2020-10-23 15:13:19 +02:00
1719743066 Geometry Nodes: improve node group evaluation
This adds support for nodes that have a multi-function implementation.
That includes various function nodes like Math, Combine Vector, ...

Furthermore, there is support for implicit conversions now. So it should
work when one connects e.g. a float to an integer and vice versa.
2020-10-23 15:09:55 +02:00
8910033f57 Nodes: add utility methods 2020-10-23 15:05:01 +02:00
2a4c6c612a Functions: add utility method 2020-10-23 15:01:07 +02:00
b062b922f9 Geometry Nodes: Resolve some missing 3D viewport updates
These two functions "snode_notify" and "ED_node_tag_update_id" appear to
be mostly duplicates. However, there is already a case for each type of
built-in node tree, so it makes sense to add one for the geometry node
tree as well. This doesn't solve the update issues for changing number
in buttons, that must be handled somewhere else.
2020-10-22 22:59:40 -05:00
895f4620a0 Merge branch 'master' into geometry-nodes 2020-10-22 22:03:28 -05:00
fafed6234b Geometry Nodes: Add edge split node functionality 2020-10-22 13:48:56 -05:00
7ff8094a8b Geometry Nodes: expose minimum vertices input of Triangulate node 2020-10-22 18:24:05 +02:00
5aabf67a9c Fix error in previous commit
That should not have happened -.-
2020-10-22 18:23:39 +02:00
ab8c7fe946 Fix previous comment 2020-10-22 18:20:17 +02:00
a05012d500 Geometry Nodes: simplify and deduplicate callbacks on sockets
This adds a layer of abstraction between the code calling callbacks
on sockets and the implementation of those callbacks.
This abstraction layer allows some sockets to not implement all
callbacks when those can be derived from some other callback.
2020-10-22 18:08:27 +02:00
97a93566e9 Geometry Nodes: change "Node Tree" to "Node Group" 2020-10-22 15:52:15 +02:00
da4d697772 Geometry Nodes: initial support for evaluating geometry node groups
This is still very basic and does quite a few unnecessary computations.
Also the error handling is quite weak currently, so when invalid things are
connected, it will probably just crash.

Also the interface that individual nodes have to implement will have to change,
but the current solution is a good starting point.

Only the triangulate node is implemented for now.
2020-10-22 15:05:41 +02:00
87218899be Geometry Nodes: add an initial geometry class 2020-10-22 15:02:27 +02:00
ffa0a6df9d Functions: add generic pointer class
This class represents a pointer whose type is only known at runtime.
2020-10-22 15:01:31 +02:00
706fa5ad76 Functions: add move operations to CPPType 2020-10-22 15:00:07 +02:00
b7f6de490d Geometry Nodes: Add initial node definition for edge split
This is just based on rBa7dba81aab22, and contains no funcionality at all.
2020-10-21 16:11:09 -05:00
7e485b4620 Merge branch 'master' into geometry-nodes 2020-10-21 08:54:39 -05:00
a7dba81aab Nodes: add initial UI for Triangulate node 2020-10-21 14:14:09 +02:00
4606e83a75 Merge branch 'master' into geometry-nodes 2020-10-21 14:00:32 +02:00
1d28de57a4 Nodes: improve dependency between modifier and node group 2020-10-21 13:16:19 +02:00
3cfcfb938d Nodes: support creating geometry node groups 2020-10-21 12:32:02 +02:00
bcdc6910a0 Nodes: show header in geometry node editor 2020-10-21 12:16:57 +02:00
7793e8c884 Modifiers: add node_tree to NodesModifierData 2020-10-21 12:13:13 +02:00
05d9bd7c4a Modifiers: rename Simulation to Nodes modifier 2020-10-21 12:03:06 +02:00
9255ce9247 Nodes: rename Simulation to Geometry node tree 2020-10-21 11:39:42 +02:00
a0ce0154e7 Merge branch 'master' into geometry-nodes 2020-10-21 11:11:16 +02:00
0cd7f7ddd1 Nodes: add geometry socket type
We still have to pick a color for this socket.

Ref T81848.
2020-10-20 15:31:59 +02:00
62 changed files with 2336 additions and 493 deletions

View File

@@ -31,6 +31,7 @@ _modules = [
"console",
"constraint",
"file",
"geometry_nodes",
"image",
"mesh",
"node",
@@ -42,7 +43,6 @@ _modules = [
"rigidbody",
"screen_play_rendered_anim",
"sequencer",
"simulation",
"userpref",
"uvcalc_follow_active",
"uvcalc_lightmap",

View File

@@ -19,23 +19,33 @@
import bpy
class NewSimulation(bpy.types.Operator):
"""Create a new simulation data block and edit it in the opened simulation editor"""
class NewGeometryNodeTree(bpy.types.Operator):
"""Create a new geometry node tree"""
bl_idname = "simulation.new"
bl_label = "New Simulation"
bl_idname = "node.new_geometry_node_tree"
bl_label = "New Geometry Node Tree"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return context.area.type == 'NODE_EDITOR' and context.space_data.tree_type == 'SimulationNodeTree'
return context.area.type == 'NODE_EDITOR' and context.space_data.tree_type == 'GeometryNodeTree'
def execute(self, context):
simulation = bpy.data.simulations.new("Simulation")
context.space_data.simulation = simulation
group = bpy.data.node_groups.new("Geometry Node Group", 'GeometryNodeTree')
group.inputs.new('NodeSocketGeometry', "Geometry")
group.outputs.new('NodeSocketGeometry', "Geometry")
input_node = group.nodes.new('NodeGroupInput')
output_node = group.nodes.new('NodeGroupOutput')
input_node.location.x = -200 - input_node.width
output_node.location.x = 200
group.links.new(output_node.inputs[0], input_node.outputs[0])
context.space_data.node_tree = group
return {'FINISHED'}
classes = (
NewSimulation,
NewGeometryNodeTree,
)

View File

@@ -151,13 +151,10 @@ class NODE_HT_header(Header):
if snode_id:
layout.prop(snode_id, "use_nodes")
elif snode.tree_type == 'SimulationNodeTree':
row = layout.row(align=True)
row.prop(snode, "simulation", text="")
row.operator("simulation.new", text="", icon='ADD')
simulation = snode.simulation
if simulation:
row.prop(snode.simulation, "use_fake_user", text="")
elif snode.tree_type == 'GeometryNodeTree':
NODE_MT_editor_menus.draw_collapsible(context, layout)
layout.separator_spacer()
layout.template_ID(snode, "node_tree", new="node.new_geometry_node_tree")
else:
# Custom node tree is edited as independent ID block

View File

@@ -58,11 +58,11 @@ class TextureNodeCategory(SortedNodeCategory):
context.space_data.tree_type == 'TextureNodeTree')
class SimulationNodeCategory(SortedNodeCategory):
class GeometryNodeCategory(SortedNodeCategory):
@classmethod
def poll(cls, context):
return (context.space_data.type == 'NODE_EDITOR' and
context.space_data.tree_type == 'SimulationNodeTree')
context.space_data.tree_type == 'GeometryNodeTree')
# menu entry for node group tools
@@ -77,11 +77,11 @@ node_tree_group_type = {
'CompositorNodeTree': 'CompositorNodeGroup',
'ShaderNodeTree': 'ShaderNodeGroup',
'TextureNodeTree': 'TextureNodeGroup',
'SimulationNodeTree': 'SimulationNodeGroup',
'GeometryNodeTree': 'GeometryNodeGroup',
}
# generic node group items generator for shader, compositor, simulation and texture node groups
# generic node group items generator for shader, compositor, geometry and texture node groups
def node_group_items(context):
if context is None:
return
@@ -483,10 +483,33 @@ def not_implemented_node(idname):
return NodeItem(idname, label=label)
simulation_node_categories = [
# Simulation Nodes
SimulationNodeCategory("SIM_GROUP", "Group", items=node_group_items),
SimulationNodeCategory("SIM_LAYOUT", "Layout", items=[
geometry_node_categories = [
# Geometry Nodes
GeometryNodeCategory("GEO_MESH", "Mesh", items=[
NodeItem("GeometryNodeTriangulate"),
NodeItem("GeometryNodeEdgeSplit"),
NodeItem("GeometryNodeTransform"),
NodeItem("GeometryNodeBoolean"),
]),
GeometryNodeCategory("GEO_MATH", "Misc", items=[
NodeItem("ShaderNodeMapRange"),
NodeItem("ShaderNodeClamp"),
NodeItem("ShaderNodeMath"),
NodeItem("ShaderNodeValToRGB"),
NodeItem("ShaderNodeVectorMath"),
NodeItem("ShaderNodeSeparateRGB"),
NodeItem("ShaderNodeCombineRGB"),
NodeItem("ShaderNodeSeparateXYZ"),
NodeItem("ShaderNodeCombineXYZ"),
NodeItem("FunctionNodeBooleanMath"),
NodeItem("FunctionNodeFloatCompare"),
NodeItem("FunctionNodeCombineStrings"),
NodeItem("FunctionNodeRandomFloat"),
NodeItem("ShaderNodeValue"),
NodeItem("FunctionNodeGroupInstanceID"),
]),
GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
GeometryNodeCategory("GEO_LAYOUT", "Layout", items=[
NodeItem("NodeFrame"),
NodeItem("NodeReroute"),
]),
@@ -497,14 +520,14 @@ def register():
nodeitems_utils.register_node_categories('SHADER', shader_node_categories)
nodeitems_utils.register_node_categories('COMPOSITING', compositor_node_categories)
nodeitems_utils.register_node_categories('TEXTURE', texture_node_categories)
nodeitems_utils.register_node_categories('SIMULATION', simulation_node_categories)
nodeitems_utils.register_node_categories('GEOMETRY', geometry_node_categories)
def unregister():
nodeitems_utils.unregister_node_categories('SHADER')
nodeitems_utils.unregister_node_categories('COMPOSITING')
nodeitems_utils.unregister_node_categories('TEXTURE')
nodeitems_utils.unregister_node_categories('SIMULATION')
nodeitems_utils.unregister_node_categories('GEOMETRY')
if __name__ == "__main__":

View File

@@ -0,0 +1,205 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
/** \file
* \ingroup bke
*/
#include <atomic>
#include <iostream>
#include "BLI_hash.hh"
struct Mesh;
namespace blender::bke {
/**
* Geometry can contain geometry of different types, such as meshes and curves (although currently
* only meshes are supported).
*
* Geometries are reference counted. This allows them to be shared without making unnecessary
* copies. A geometry that is shared is immutable. If some code wants to change it,
* #make_geometry_mutable should be called first.
*/
class Geometry {
private:
/* Number of users of this geometry. If this number goes to zero, the geometry is freed. If it is
* above 1, the geometry is immutable. */
std::atomic<int> users_ = 1;
/* Only contains a mesh for now. */
Mesh *mesh_ = nullptr;
/* Determines if the mesh is freed when the geometry does not want to reference it anymore. */
bool mesh_owned_ = false;
public:
Geometry() = default;
Geometry(const Geometry &other);
Geometry(Geometry &&other) = delete;
~Geometry();
/* Disable copy and move assignment operators. */
Geometry &operator=(const Geometry &other) = delete;
Geometry &operator=(Geometry &&other) = delete;
void user_add();
void user_remove();
bool is_mutable() const;
bool mesh_available() const;
void mesh_set_and_keep_ownership(Mesh *mesh);
void mesh_set_and_transfer_ownership(Mesh *mesh);
void mesh_reset();
Mesh *mesh_get_for_read();
Mesh *mesh_get_for_write();
Mesh *mesh_release();
};
/**
* A simple automatic reference counter. This should probably be moved to another file eventually.
* It is similar to std::shared_ptr, but expects that the reference count is inside the object.
*/
template<typename T> class UserCounter {
private:
T *data_ = nullptr;
public:
UserCounter() = default;
UserCounter(T *data) : data_(data)
{
}
UserCounter(const UserCounter &other) : data_(other.data_)
{
this->user_add(data_);
}
UserCounter(UserCounter &&other) : data_(other.data_)
{
other.data_ = nullptr;
}
~UserCounter()
{
this->user_remove(data_);
}
UserCounter &operator=(const UserCounter &other)
{
if (this == &other) {
return *this;
}
this->user_remove(data_);
data_ = other.data_;
this->user_add(data_);
return *this;
}
UserCounter &operator=(UserCounter &&other)
{
if (this == &other) {
return *this;
}
this->user_remove(data_);
data_ = other.data_;
other.data_ = nullptr;
return *this;
}
T *operator->()
{
BLI_assert(data_ != nullptr);
return data_;
}
T &operator*()
{
BLI_assert(data_ != nullptr);
return *data_;
}
operator bool() const
{
return data_ != nullptr;
}
T *get()
{
return data_;
}
T *release()
{
T *data = data_;
data_ = nullptr;
return data;
}
void reset()
{
this->user_remove(data_);
data_ = nullptr;
}
bool has_value() const
{
return data_ != nullptr;
}
uint64_t hash() const
{
return DefaultHash<T *>{}(data_);
}
friend bool operator==(const UserCounter &a, const UserCounter &b)
{
return a.data_ == b.data_;
}
friend std::ostream &operator<<(std::ostream &stream, const UserCounter &value)
{
stream << value.data_;
return stream;
}
private:
static void user_add(T *data)
{
if (data != nullptr) {
data->user_add();
}
}
static void user_remove(T *data)
{
if (data != nullptr) {
data->user_remove();
}
}
};
/* An automatically reference counted geometry. */
using GeometryPtr = UserCounter<class Geometry>;
void make_geometry_mutable(GeometryPtr &geometry);
} // namespace blender::bke

View File

@@ -112,20 +112,28 @@ namespace blender {
namespace nodes {
class SocketMFNetworkBuilder;
class NodeMFNetworkBuilder;
class GValueByName;
} // namespace nodes
namespace fn {
class CPPType;
class MFDataType;
}
} // namespace fn
} // namespace blender
using NodeExpandInMFNetworkFunction = void (*)(blender::nodes::NodeMFNetworkBuilder &builder);
using SocketGetMFDataTypeFunction = blender::fn::MFDataType (*)();
using NodeGeometryExecFunction = void (*)(struct bNode *node,
blender::nodes::GValueByName &inputs,
blender::nodes::GValueByName &outputs);
using SocketGetCPPTypeFunction = const blender::fn::CPPType *(*)();
using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value);
using SocketExpandInMFNetworkFunction = void (*)(blender::nodes::SocketMFNetworkBuilder &builder);
#else
typedef void *NodeExpandInMFNetworkFunction;
typedef void *SocketGetMFDataTypeFunction;
typedef void *SocketExpandInMFNetworkFunction;
typedef void *NodeGeometryExecFunction;
typedef void *SocketGetCPPTypeFunction;
typedef void *SocketGetCPPValueFunction;
#endif
/**
@@ -181,10 +189,12 @@ typedef struct bNodeSocketType {
/* Callback to free the socket type. */
void (*free_self)(struct bNodeSocketType *stype);
/* Returns the multi-function data type of this socket type. */
SocketGetMFDataTypeFunction get_mf_data_type;
/* Expands the socket into a multi-function node that outputs the socket value. */
SocketExpandInMFNetworkFunction expand_in_mf_network;
/* Return the CPPType of this socket. */
SocketGetCPPTypeFunction get_cpp_type;
/* Get the value of this socket in a generic way. */
SocketGetCPPValueFunction get_cpp_value;
} bNodeSocketType;
typedef void *(*NodeInitExecFunction)(struct bNodeExecContext *context,
@@ -302,6 +312,9 @@ typedef struct bNodeType {
/* Expands the bNode into nodes in a multi-function network, which will be evaluated later on. */
NodeExpandInMFNetworkFunction expand_in_mf_network;
/* Execute a geometry node. */
NodeGeometryExecFunction geometry_node_execute;
/* RNA integration */
ExtensionRNA rna_ext;
} bNodeType;
@@ -1323,6 +1336,17 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
struct MTex *mtex);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Geometry Nodes
* \{ */
#define GEO_NODE_TRIANGULATE 1000
#define GEO_NODE_EDGE_SPLIT 1001
#define GEO_NODE_TRANSFORM 1002
#define GEO_NODE_BOOLEAN 1003
/** \} */
/* -------------------------------------------------------------------- */
/** \name Function Nodes
* \{ */

View File

@@ -124,6 +124,7 @@ set(SRC
intern/fmodifier.c
intern/font.c
intern/freestyle.c
intern/geometry.cc
intern/gpencil.c
intern/gpencil_curve.c
intern/gpencil_geom.c
@@ -310,6 +311,7 @@ set(SRC
BKE_fluid.h
BKE_font.h
BKE_freestyle.h
BKE_geometry.hh
BKE_global.h
BKE_gpencil.h
BKE_gpencil_curve.h

View File

@@ -0,0 +1,160 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BKE_geometry.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "MEM_guardedalloc.h"
namespace blender::bke {
/* Make a copy of the geometry. */
Geometry::Geometry(const Geometry &other)
{
if (other.mesh_ != nullptr) {
mesh_ = BKE_mesh_copy_for_eval(other.mesh_, false);
/* Own the new mesh, regardless of whether the original mesh was owned. */
mesh_owned_ = true;
}
}
Geometry::~Geometry()
{
this->mesh_reset();
}
void Geometry::user_add()
{
users_.fetch_add(1);
}
void Geometry::user_remove()
{
const int new_users = users_.fetch_sub(1) - 1;
if (new_users == 0) {
delete this;
}
}
bool Geometry::is_mutable() const
{
/* If the geometry is shared, it is read-only. */
/* The user count can be 0, when this is called from the destructor. */
return users_ <= 1;
}
/**
* Returns true when this geometry has a mesh component.
*/
bool Geometry::mesh_available() const
{
return mesh_ != nullptr;
}
/**
* Replace the mesh in the geometry. The caller remains the owner of the given mesh and is
* responsible for freeing it eventually.
*/
void Geometry::mesh_set_and_keep_ownership(Mesh *mesh)
{
BLI_assert(this->is_mutable());
this->mesh_reset();
mesh_ = mesh;
mesh_owned_ = false;
}
/**
* Replace the mesh in the geometry. The geometry becomes responsible for freeing the mesh.
*/
void Geometry::mesh_set_and_transfer_ownership(Mesh *mesh)
{
BLI_assert(this->is_mutable());
this->mesh_reset();
mesh_ = mesh;
mesh_owned_ = true;
}
/**
* Clear any mesh data the geometry might have.
*/
void Geometry::mesh_reset()
{
BLI_assert(this->is_mutable());
if (mesh_ != nullptr) {
if (mesh_owned_) {
BKE_id_free(nullptr, mesh_);
}
mesh_ = nullptr;
}
}
/**
* Get the mesh from the geometry. This mesh should only be read and not modified. This can be used
* on shared geometries.
* Might return null.
*/
Mesh *Geometry::mesh_get_for_read()
{
return mesh_;
}
/**
* Get the mesh from the geometry. The caller is allowed to modify the mesh. This method can only
* be used on mutable geometries.
* Might return null.
*/
Mesh *Geometry::mesh_get_for_write()
{
BLI_assert(this->is_mutable());
return mesh_;
}
/**
* Return the mesh in the geometry and remove it. This only works on mutable geometries.
* Might return null;
*/
Mesh *Geometry::mesh_release()
{
BLI_assert(this->is_mutable());
Mesh *mesh = mesh_;
mesh_ = nullptr;
return mesh;
}
/**
* Changes the given pointer so that it points to a mutable geometry. This might do nothing, create
* a new empty geometry or copy the entire geometry.
*/
void make_geometry_mutable(GeometryPtr &geometry)
{
if (!geometry) {
/* If the pointer is null, create a new instance. */
geometry = GeometryPtr{new Geometry()};
}
else if (geometry->is_mutable()) {
/* If the instance is mutable already, do nothing. */
}
else {
/* This geometry is shared, make a copy that is independent of the other users. */
Geometry *shared_geometry = geometry.release();
Geometry *new_geometry = new Geometry(*shared_geometry);
shared_geometry->user_remove();
geometry = GeometryPtr{new_geometry};
}
}
} // namespace blender::bke

View File

@@ -65,7 +65,6 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_simulation.h"
#include "BLI_ghash.h"
#include "BLI_threads.h"
@@ -75,8 +74,8 @@
#include "NOD_common.h"
#include "NOD_composite.h"
#include "NOD_function.h"
#include "NOD_geometry.h"
#include "NOD_shader.h"
#include "NOD_simulation.h"
#include "NOD_socket.h"
#include "NOD_texture.h"
@@ -281,6 +280,7 @@ static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_GEOMETRY:
break;
}
}
@@ -373,6 +373,7 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_GEOMETRY:
BLI_assert(false);
break;
}
@@ -715,6 +716,7 @@ static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSock
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_GEOMETRY:
break;
}
}
@@ -793,6 +795,7 @@ static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock)
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_GEOMETRY:
break;
}
}
@@ -1345,6 +1348,7 @@ static void socket_id_user_increment(bNodeSocket *sock)
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_GEOMETRY:
break;
}
}
@@ -1371,6 +1375,7 @@ static void socket_id_user_decrement(bNodeSocket *sock)
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_GEOMETRY:
break;
}
}
@@ -1498,6 +1503,8 @@ const char *nodeStaticSocketType(int type, int subtype)
return "NodeSocketObject";
case SOCK_IMAGE:
return "NodeSocketImage";
case SOCK_GEOMETRY:
return "NodeSocketGeometry";
}
return NULL;
}
@@ -1563,6 +1570,8 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype)
return "NodeSocketInterfaceObject";
case SOCK_IMAGE:
return "NodeSocketInterfaceImage";
case SOCK_GEOMETRY:
return "NodeSocketInterfaceGeometry";
}
return NULL;
}
@@ -4646,9 +4655,14 @@ static void registerTextureNodes(void)
register_node_type_tex_proc_distnoise();
}
static void registerSimulationNodes(void)
static void registerGeometryNodes(void)
{
register_node_type_sim_group();
register_node_type_geo_group();
register_node_type_geo_triangulate();
register_node_type_geo_edge_split();
register_node_type_geo_transform();
register_node_type_geo_boolean();
}
static void registerFunctionNodes(void)
@@ -4675,7 +4689,7 @@ void init_nodesystem(void)
register_node_tree_type_cmp();
register_node_tree_type_sh();
register_node_tree_type_tex();
register_node_tree_type_sim();
register_node_tree_type_geo();
register_node_type_frame();
register_node_type_reroute();
@@ -4685,7 +4699,7 @@ void init_nodesystem(void)
registerCompositNodes();
registerShaderNodes();
registerTextureNodes();
registerSimulationNodes();
registerGeometryNodes();
registerFunctionNodes();
}

View File

@@ -1196,9 +1196,6 @@ static bool foreach_object_modifier_ptcache(Object *object,
}
}
}
else if (md->type == eModifierType_Simulation) {
/* TODO(jacques): */
}
}
return true;
}

View File

@@ -48,8 +48,8 @@
#include "BKE_pointcache.h"
#include "BKE_simulation.h"
#include "NOD_geometry.h"
#include "NOD_node_tree_multi_function.hh"
#include "NOD_simulation.h"
#include "BLI_map.hh"
#include "BLT_translation.h"
@@ -70,7 +70,7 @@ static void simulation_init_data(ID *id)
MEMCPY_STRUCT_AFTER(simulation, DNA_struct_default_get(Simulation), id);
bNodeTree *ntree = ntreeAddTree(nullptr, "Simulation Nodetree", ntreeType_Simulation->idname);
bNodeTree *ntree = ntreeAddTree(nullptr, "Geometry Nodetree", ntreeType_Geometry->idname);
simulation->nodetree = ntree;
}

View File

@@ -158,7 +158,6 @@
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_shader_fx.h"
#include "BKE_simulation.h"
#include "BKE_sound.h"
#include "BKE_volume.h"
#include "BKE_workspace.h"

View File

@@ -141,6 +141,9 @@ void DEG_add_object_relation(struct DepsNodeHandle *node_handle,
void DEG_add_simulation_relation(struct DepsNodeHandle *node_handle,
struct Simulation *simulation,
const char *description);
void DEG_add_node_tree_relation(struct DepsNodeHandle *node_handle,
struct bNodeTree *node_tree,
const char *description);
void DEG_add_bone_relation(struct DepsNodeHandle *handle,
struct Object *object,
const char *bone_name,

View File

@@ -32,6 +32,7 @@
#include "PIL_time_utildefines.h"
#include "DNA_cachefile_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_simulation_types.h"
@@ -116,6 +117,17 @@ void DEG_add_simulation_relation(DepsNodeHandle *node_handle,
deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description);
}
void DEG_add_node_tree_relation(DepsNodeHandle *node_handle,
bNodeTree *node_tree,
const char *description)
{
/* Using shading key, because that's the one that exists right now. Should use something else in
* the future. */
deg::ComponentKey shading_key(&node_tree->id, deg::NodeType::SHADING);
deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
deg_node_handle->builder->add_node_handle_relation(shading_key, deg_node_handle, description);
}
void DEG_add_object_cache_relation(DepsNodeHandle *node_handle,
CacheFile *cache_file,
eDepsObjectComponentType component,

View File

@@ -96,7 +96,7 @@ void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typein
bool ED_node_is_compositor(struct SpaceNode *snode);
bool ED_node_is_shader(struct SpaceNode *snode);
bool ED_node_is_texture(struct SpaceNode *snode);
bool ED_node_is_simulation(struct SpaceNode *snode);
bool ED_node_is_geometry(struct SpaceNode *snode);
void ED_node_shader_default(const struct bContext *C, struct ID *id);
void ED_node_composit_default(const struct bContext *C, struct Scene *scene);

View File

@@ -68,8 +68,8 @@
#include "IMB_imbuf_types.h"
#include "NOD_composite.h"
#include "NOD_geometry.h"
#include "NOD_shader.h"
#include "NOD_simulation.h"
#include "NOD_texture.h"
#include "node_intern.h" /* own include */
@@ -3138,10 +3138,20 @@ static void node_texture_set_butfunc(bNodeType *ntype)
}
}
/* ****************** BUTTON CALLBACKS FOR SIMULATION NODES ***************** */
/* ****************** BUTTON CALLBACKS FOR GEOMETRY NODES ***************** */
static void node_simulation_set_butfunc(bNodeType *UNUSED(ntype))
static void node_geometry_buts_boolean_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_geometry_set_butfunc(bNodeType *ntype)
{
switch (ntype->type) {
case GEO_NODE_BOOLEAN:
ntype->draw_buttons = node_geometry_buts_boolean_math;
break;
}
}
/* ****************** BUTTON CALLBACKS FOR FUNCTION NODES ***************** */
@@ -3286,7 +3296,7 @@ void ED_node_init_butfuncs(void)
node_composit_set_butfunc(ntype);
node_shader_set_butfunc(ntype);
node_texture_set_butfunc(ntype);
node_simulation_set_butfunc(ntype);
node_geometry_set_butfunc(ntype);
node_function_set_butfunc(ntype);
/* define update callbacks for socket properties */
@@ -3298,7 +3308,7 @@ void ED_node_init_butfuncs(void)
ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING;
ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL;
ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE;
ntreeType_Simulation->ui_icon = ICON_PHYSICS; /* TODO: Use correct icon. */
ntreeType_Geometry->ui_icon = ICON_PHYSICS; /* TODO: Use correct icon. */
}
void ED_init_custom_node_type(bNodeType *ntype)
@@ -3329,6 +3339,7 @@ static const float std_node_socket_colors[][4] = {
{0.39, 0.39, 0.39, 1.0}, /* SOCK_STRING */
{0.40, 0.10, 0.10, 1.0}, /* SOCK_OBJECT */
{0.10, 0.40, 0.10, 1.0}, /* SOCK_IMAGE */
{0.00, 0.00, 0.00, 1.0}, /* SOCK_GEOMETRY, TODO: Choose color. */
};
/* common color callbacks for standard types */

View File

@@ -138,6 +138,9 @@ void ED_node_tag_update_id(ID *id)
DEG_id_tag_update(id, 0);
WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
}
else if (ntree->type == NTREE_GEOMETRY) {
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
}
else if (id == &ntree->id) {
/* node groups */
DEG_id_tag_update(id, 0);

View File

@@ -68,8 +68,8 @@
#include "IMB_imbuf_types.h"
#include "NOD_composite.h"
#include "NOD_geometry.h"
#include "NOD_shader.h"
#include "NOD_simulation.h"
#include "NOD_texture.h"
#include "node_intern.h" /* own include */
@@ -391,6 +391,7 @@ void snode_dag_update(bContext *C, SpaceNode *snode)
}
DEG_id_tag_update(snode->id, 0);
DEG_id_tag_update(&snode->nodetree->id, 0);
}
void snode_notify(bContext *C, SpaceNode *snode)
@@ -416,6 +417,9 @@ void snode_notify(bContext *C, SpaceNode *snode)
else if (ED_node_is_texture(snode)) {
WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, id);
}
else if (ED_node_is_geometry(snode)) {
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
}
}
void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
@@ -443,9 +447,9 @@ bool ED_node_is_texture(struct SpaceNode *snode)
return STREQ(snode->tree_idname, ntreeType_Texture->idname);
}
bool ED_node_is_simulation(struct SpaceNode *snode)
bool ED_node_is_geometry(struct SpaceNode *snode)
{
return STREQ(snode->tree_idname, ntreeType_Simulation->idname);
return STREQ(snode->tree_idname, ntreeType_Geometry->idname);
}
/* assumes nothing being done in ntree yet, sets the default in/out node */
@@ -1696,7 +1700,7 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
}
}
do_tag_update |= ED_node_is_simulation(snode);
do_tag_update |= ED_node_is_geometry(snode);
snode_notify(C, snode);
if (do_tag_update) {
@@ -1740,7 +1744,7 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
}
do_tag_update |= ED_node_is_simulation(snode);
do_tag_update |= ED_node_is_geometry(snode);
ntreeUpdateTree(CTX_data_main(C), snode->edittree);

View File

@@ -71,7 +71,7 @@ static bool node_group_operator_active(bContext *C)
if (STREQ(snode->tree_idname, "ShaderNodeTree") ||
STREQ(snode->tree_idname, "CompositorNodeTree") ||
STREQ(snode->tree_idname, "TextureNodeTree") ||
STREQ(snode->tree_idname, "SimulationNodeTree")) {
STREQ(snode->tree_idname, "GeometryNodeTree")) {
return true;
}
}
@@ -88,7 +88,7 @@ static bool node_group_operator_editable(bContext *C)
* with same keymap.
*/
if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode) ||
ED_node_is_simulation(snode)) {
ED_node_is_geometry(snode)) {
return true;
}
}
@@ -114,8 +114,8 @@ static const char *group_node_idname(bContext *C)
if (ED_node_is_texture(snode)) {
return "TextureNodeGroup";
}
if (ED_node_is_simulation(snode)) {
return "SimulationNodeGroup";
if (ED_node_is_geometry(snode)) {
return "GeometryNodeGroup";
}
return "";

View File

@@ -655,7 +655,7 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
}
ntree->is_updating = false;
do_tag_update |= ED_node_is_simulation(snode);
do_tag_update |= ED_node_is_geometry(snode);
ntreeUpdateTree(bmain, ntree);
snode_notify(C, snode);
@@ -1052,7 +1052,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
}
}
do_tag_update |= ED_node_is_simulation(snode);
do_tag_update |= ED_node_is_geometry(snode);
if (found) {
ntreeUpdateTree(CTX_data_main(C), snode->edittree);

View File

@@ -936,7 +936,7 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
const EnumPropertyItem *item_src = RNA_enum_node_tree_types_itemf_impl(C, &free);
for (const EnumPropertyItem *item_iter = item_src; item_iter->identifier; item_iter++) {
if (!U.experimental.use_new_geometry_nodes &&
STREQ(item_iter->identifier, "SimulationNodeTree")) {
STREQ(item_iter->identifier, "GeometryNodeTree")) {
continue;
}
RNA_enum_item_add(item, totitem, item_iter);

View File

@@ -38,6 +38,7 @@ set(SRC
FN_array_spans.hh
FN_attributes_ref.hh
FN_cpp_type.hh
FN_generic_pointer.hh
FN_generic_vector_array.hh
FN_multi_function.hh
FN_multi_function_builder.hh

View File

@@ -91,6 +91,14 @@ class CPPType : NonCopyable, NonMovable {
using CopyToUninitializedNF = void (*)(const void *src, void *dst, int64_t n);
using CopyToUninitializedIndicesF = void (*)(const void *src, void *dst, IndexMask mask);
using MoveToInitializedF = void (*)(void *src, void *dst);
using MoveToInitializedNF = void (*)(void *src, void *dst, int64_t n);
using MoveToInitializedIndicesF = void (*)(void *src, void *dst, IndexMask mask);
using MoveToUninitializedF = void (*)(void *src, void *dst);
using MoveToUninitializedNF = void (*)(void *src, void *dst, int64_t n);
using MoveToUninitializedIndicesF = void (*)(void *src, void *dst, IndexMask mask);
using RelocateToInitializedF = void (*)(void *src, void *dst);
using RelocateToInitializedNF = void (*)(void *src, void *dst, int64_t n);
using RelocateToInitializedIndicesF = void (*)(void *src, void *dst, IndexMask mask);
@@ -131,6 +139,14 @@ class CPPType : NonCopyable, NonMovable {
CopyToUninitializedNF copy_to_uninitialized_n_;
CopyToUninitializedIndicesF copy_to_uninitialized_indices_;
MoveToInitializedF move_to_initialized_;
MoveToInitializedNF move_to_initialized_n_;
MoveToInitializedIndicesF move_to_initialized_indices_;
MoveToUninitializedF move_to_uninitialized_;
MoveToUninitializedNF move_to_uninitialized_n_;
MoveToUninitializedIndicesF move_to_uninitialized_indices_;
RelocateToInitializedF relocate_to_initialized_;
RelocateToInitializedNF relocate_to_initialized_n_;
RelocateToInitializedIndicesF relocate_to_initialized_indices_;
@@ -169,6 +185,12 @@ class CPPType : NonCopyable, NonMovable {
CopyToUninitializedF copy_to_uninitialized,
CopyToUninitializedNF copy_to_uninitialized_n,
CopyToUninitializedIndicesF copy_to_uninitialized_indices,
MoveToInitializedF move_to_initialized,
MoveToInitializedNF move_to_initialized_n,
MoveToInitializedIndicesF move_to_initialized_indices,
MoveToUninitializedF move_to_uninitialized,
MoveToUninitializedNF move_to_uninitialized_n,
MoveToUninitializedIndicesF move_to_uninitialized_indices,
RelocateToInitializedF relocate_to_initialized,
RelocateToInitializedNF relocate_to_initialized_n,
RelocateToInitializedIndicesF relocate_to_initialized_indices,
@@ -198,6 +220,12 @@ class CPPType : NonCopyable, NonMovable {
copy_to_uninitialized_(copy_to_uninitialized),
copy_to_uninitialized_n_(copy_to_uninitialized_n),
copy_to_uninitialized_indices_(copy_to_uninitialized_indices),
move_to_initialized_(move_to_initialized),
move_to_initialized_n_(move_to_initialized_n),
move_to_initialized_indices_(move_to_initialized_indices),
move_to_uninitialized_(move_to_uninitialized),
move_to_uninitialized_n_(move_to_uninitialized_n),
move_to_uninitialized_indices_(move_to_uninitialized_indices),
relocate_to_initialized_(relocate_to_initialized),
relocate_to_initialized_n_(relocate_to_initialized_n),
relocate_to_initialized_indices_(relocate_to_initialized_indices),
@@ -421,6 +449,76 @@ class CPPType : NonCopyable, NonMovable {
copy_to_uninitialized_indices_(src, dst, mask);
}
/**
* Move an instance of this type from src to dst.
*
* The memory pointed to by dst should be initialized.
*
* C++ equivalent:
* dst = std::move(src);
*/
void move_to_initialized(void *src, void *dst) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
move_to_initialized_(src, dst);
}
void move_to_initialized_n(void *src, void *dst, int64_t n) const
{
BLI_assert(n == 0 || src != dst);
BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
move_to_initialized_n_(src, dst, n);
}
void move_to_initialized_indices(void *src, void *dst, IndexMask mask) const
{
BLI_assert(mask.size() == 0 || src != dst);
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
move_to_initialized_indices_(src, dst, mask);
}
/**
* Move an instance of this type from src to dst.
*
* The memory pointed to by dst should be uninitialized.
*
* C++ equivalent:
* new (dst) T(std::move(src));
*/
void move_to_uninitialized(void *src, void *dst) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
move_to_uninitialized_(src, dst);
}
void move_to_uninitialized_n(void *src, void *dst, int64_t n) const
{
BLI_assert(n == 0 || src != dst);
BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
move_to_uninitialized_n_(src, dst, n);
}
void move_to_uninitialized_indices(void *src, void *dst, IndexMask mask) const
{
BLI_assert(mask.size() == 0 || src != dst);
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
move_to_uninitialized_indices_(src, dst, mask);
}
/**
* Relocates an instance of this type from src to dst. src will point to uninitialized memory
* afterwards.
@@ -644,6 +742,38 @@ void copy_to_uninitialized_indices_cb(const void *src, void *dst, IndexMask mask
mask.foreach_index([&](int64_t i) { new (dst_ + i) T(src_[i]); });
}
template<typename T> void move_to_initialized_cb(void *src, void *dst)
{
blender::initialized_move_n(static_cast<T *>(src), 1, static_cast<T *>(dst));
}
template<typename T> void move_to_initialized_n_cb(void *src, void *dst, int64_t n)
{
blender::initialized_move_n(static_cast<T *>(src), n, static_cast<T *>(dst));
}
template<typename T> void move_to_initialized_indices_cb(void *src, void *dst, IndexMask mask)
{
T *src_ = static_cast<T *>(src);
T *dst_ = static_cast<T *>(dst);
mask.foreach_index([&](int64_t i) { dst_[i] = std::move(src_[i]); });
}
template<typename T> void move_to_uninitialized_cb(void *src, void *dst)
{
blender::uninitialized_move_n(static_cast<T *>(src), 1, static_cast<T *>(dst));
}
template<typename T> void move_to_uninitialized_n_cb(void *src, void *dst, int64_t n)
{
blender::uninitialized_move_n(static_cast<T *>(src), n, static_cast<T *>(dst));
}
template<typename T> void move_to_uninitialized_indices_cb(void *src, void *dst, IndexMask mask)
{
T *src_ = static_cast<T *>(src);
T *dst_ = static_cast<T *>(dst);
mask.foreach_index([&](int64_t i) { new (dst_ + i) T(std::move(src_[i])); });
}
template<typename T> void relocate_to_initialized_cb(void *src, void *dst)
{
T *src_ = static_cast<T *>(src);
@@ -767,6 +897,12 @@ inline std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d
copy_to_uninitialized_cb<T>,
copy_to_uninitialized_n_cb<T>,
copy_to_uninitialized_indices_cb<T>,
move_to_initialized_cb<T>,
move_to_initialized_n_cb<T>,
move_to_initialized_indices_cb<T>,
move_to_uninitialized_cb<T>,
move_to_uninitialized_n_cb<T>,
move_to_uninitialized_indices_cb<T>,
relocate_to_initialized_cb<T>,
relocate_to_initialized_n_cb<T>,
relocate_to_initialized_indices_cb<T>,

View File

@@ -0,0 +1,76 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include "FN_cpp_type.hh"
namespace blender::fn {
/**
* A generic pointer whose type is only known at runtime.
*/
class GMutablePointer {
private:
const CPPType *type_ = nullptr;
void *data_ = nullptr;
public:
GMutablePointer() = default;
GMutablePointer(const CPPType *type, void *data = nullptr) : type_(type), data_(data)
{
/* If there is data, there has to be a type. */
BLI_assert(data_ == nullptr || type_ != nullptr);
}
GMutablePointer(const CPPType &type, void *data = nullptr) : GMutablePointer(&type, data)
{
}
template<typename T> GMutablePointer(T *data) : GMutablePointer(&CPPType::get<T>(), data)
{
}
void *get() const
{
return data_;
}
const CPPType *type() const
{
return type_;
}
template<typename T> T *get() const
{
BLI_assert(this->is_type<T>());
return reinterpret_cast<T *>(data_);
}
template<typename T> bool is_type() const
{
return type_ != nullptr && type_->is<T>();
}
void destruct()
{
BLI_assert(data_ != nullptr);
type_->destruct(data_);
}
};
} // namespace blender::fn

View File

@@ -574,7 +574,7 @@
.flag = 0, \
}
#define _DNA_DEFAULT_SimulationModifierData \
#define _DNA_DEFAULT_NodesModifierData \
{ 0 }
#define _DNA_DEFAULT_SkinModifierData \

View File

@@ -94,7 +94,7 @@ typedef enum ModifierType {
eModifierType_WeightedNormal = 54,
eModifierType_Weld = 55,
eModifierType_Fluid = 56,
eModifierType_Simulation = 57,
eModifierType_Nodes = 57,
eModifierType_MeshToVolume = 58,
eModifierType_VolumeDisplace = 59,
eModifierType_VolumeToMesh = 60,
@@ -2219,9 +2219,14 @@ enum {
#define MOD_MESHSEQ_READ_ALL \
(MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
typedef struct SimulationModifierData {
typedef struct NodesModifierData {
ModifierData modifier;
} SimulationModifierData;
struct bNodeTree *node_group;
/* This property exists only temporary for testing purposes. */
float test_float_input;
char _pad[4];
} NodesModifierData;
typedef struct MeshToVolumeModifierData {
ModifierData modifier;

View File

@@ -155,6 +155,7 @@ typedef enum eNodeSocketDatatype {
SOCK_STRING = 7,
SOCK_OBJECT = 8,
SOCK_IMAGE = 9,
SOCK_GEOMETRY = 10,
} eNodeSocketDatatype;
/* socket shape */
@@ -499,7 +500,7 @@ typedef struct bNodeTree {
#define NTREE_SHADER 0
#define NTREE_COMPOSIT 1
#define NTREE_TEXTURE 2
#define NTREE_SIMULATION 3
#define NTREE_GEOMETRY 3
/* ntree->init, flag */
#define NTREE_TYPE_INIT 1
@@ -1423,14 +1424,11 @@ typedef enum NodeShaderOutputTarget {
SHD_OUTPUT_CYCLES = 2,
} NodeShaderOutputTarget;
/* Particle Time Step Event node */
typedef enum NodeSimParticleTimeStepEventType {
NODE_PARTICLE_TIME_STEP_EVENT_BEGIN = 0,
NODE_PARTICLE_TIME_STEP_EVENT_END = 1,
} NodeSimParticleTimeStepEventType;
/* Geometry Nodes */
/* Simulation Time node */
typedef enum NodeSimInputTimeType {
NODE_SIM_INPUT_SIMULATION_TIME = 0,
NODE_SIM_INPUT_SCENE_TIME = 1,
} NodeSimInputTimeType;
/* Boolean Node */
typedef enum GeometryNodeBooleanOperation {
GEO_NODE_BOOLEAN_INTERSECT = 0,
GEO_NODE_BOOLEAN_UNION = 1,
GEO_NODE_BOOLEAN_DIFFERENCE = 2,
} GeometryNodeBooleanOperation;

View File

@@ -271,7 +271,7 @@ SDNA_DEFAULT_DECL_STRUCT(ScrewModifierData);
/* Shape key modifier has no items. */
SDNA_DEFAULT_DECL_STRUCT(ShrinkwrapModifierData);
SDNA_DEFAULT_DECL_STRUCT(SimpleDeformModifierData);
SDNA_DEFAULT_DECL_STRUCT(SimulationModifierData);
SDNA_DEFAULT_DECL_STRUCT(NodesModifierData);
SDNA_DEFAULT_DECL_STRUCT(SkinModifierData);
SDNA_DEFAULT_DECL_STRUCT(SmoothModifierData);
/* Softbody modifier skipped for now. */
@@ -491,7 +491,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
/* Shape key modifier has no items. */
SDNA_DEFAULT_DECL(ShrinkwrapModifierData),
SDNA_DEFAULT_DECL(SimpleDeformModifierData),
SDNA_DEFAULT_DECL(SimulationModifierData),
SDNA_DEFAULT_DECL(NodesModifierData),
SDNA_DEFAULT_DECL(SkinModifierData),
SDNA_DEFAULT_DECL(SmoothModifierData),
/* Softbody modifier skipped for now. */

View File

@@ -566,10 +566,10 @@ extern StructRNA RNA_SimpleDeformModifier;
extern StructRNA RNA_SimplifyGpencilModifier;
extern StructRNA RNA_Simulation;
#ifdef WITH_GEOMETRY_NODES
extern StructRNA RNA_SimulationModifier;
extern StructRNA RNA_NodesModifier;
#endif
extern StructRNA RNA_SimulationNode;
extern StructRNA RNA_SimulationNodeTree;
extern StructRNA RNA_GeometryNode;
extern StructRNA RNA_GeometryNodeTree;
extern StructRNA RNA_SkinModifier;
extern StructRNA RNA_SmoothGpencilModifier;
extern StructRNA RNA_SmoothModifier;

View File

@@ -29,7 +29,6 @@
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_simulation_types.h"
#include "MEM_guardedalloc.h"
@@ -161,6 +160,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_MULTIRES,
"Multiresolution",
"Subdivide the mesh in a way that allows editing the higher subdivision levels"},
{eModifierType_Nodes, "NODES", ICON_MESH_DATA, "Nodes", ""}, /* TODO: Use correct icon. */
{eModifierType_Remesh,
"REMESH",
ICON_MOD_REMESH,
@@ -305,11 +305,6 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
"Spawn particles from the shape"},
{eModifierType_Softbody, "SOFT_BODY", ICON_MOD_SOFT, "Soft Body", ""},
{eModifierType_Surface, "SURFACE", ICON_MODIFIER, "Surface", ""},
{eModifierType_Simulation,
"SIMULATION",
ICON_PHYSICS,
"Simulation",
""}, /* TODO: Use correct icon. */
{0, NULL, 0, NULL, NULL},
};
@@ -1602,6 +1597,14 @@ static int rna_MeshSequenceCacheModifier_read_velocity_get(PointerRNA *ptr)
# endif
}
static bool rna_NodesModifier_node_group_poll(PointerRNA *ptr, PointerRNA value)
{
NodesModifierData *nmd = ptr->data;
bNodeTree *ntree = value.data;
UNUSED_VARS(nmd, ntree);
return true;
}
#else
/* NOTE: *MUST* return subdivision_type property. */
@@ -6920,17 +6923,28 @@ static void rna_def_modifier_weightednormal(BlenderRNA *brna)
}
# ifdef WITH_GEOMETRY_NODES
static void rna_def_modifier_simulation(BlenderRNA *brna)
static void rna_def_modifier_nodes(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "SimulationModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Simulation Modifier", "");
RNA_def_struct_sdna(srna, "SimulationModifierData");
RNA_def_struct_ui_icon(srna, ICON_PHYSICS); /* TODO: Use correct icon. */
srna = RNA_def_struct(brna, "NodesModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Nodes Modifier", "");
RNA_def_struct_sdna(srna, "NodesModifierData");
RNA_def_struct_ui_icon(srna, ICON_MESH_DATA); /* TODO: Use correct icon. */
RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "node_group", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Node Group", "Node group that controls what this modifier does");
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_NodesModifier_node_group_poll");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "test_float_input", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Float Input", "Temporary float input for testing purposes");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
RNA_define_lib_overridable(false);
}
# endif
@@ -7290,7 +7304,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_surfacedeform(brna);
rna_def_modifier_weightednormal(brna);
# ifdef WITH_GEOMETRY_NODES
rna_def_modifier_simulation(brna);
rna_def_modifier_nodes(brna);
# endif
rna_def_modifier_mesh_to_volume(brna);
rna_def_modifier_volume_displace(brna);

View File

@@ -38,7 +38,6 @@
#include "BKE_animsys.h"
#include "BKE_image.h"
#include "BKE_node.h"
#include "BKE_simulation.h"
#include "BKE_texture.h"
#include "RNA_access.h"
@@ -84,6 +83,7 @@ static const EnumPropertyItem node_socket_type_items[] = {
{SOCK_SHADER, "SHADER", 0, "Shader", ""},
{SOCK_OBJECT, "OBJECT", 0, "Object", ""},
{SOCK_IMAGE, "IMAGE", 0, "Image", ""},
{SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -96,6 +96,7 @@ static const EnumPropertyItem node_socket_data_type_items[] = {
{SOCK_RGBA, "RGBA", 0, "Color", ""},
{SOCK_OBJECT, "OBJECT", 0, "Object", ""},
{SOCK_IMAGE, "IMAGE", 0, "Image", ""},
{SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -367,6 +368,22 @@ static const EnumPropertyItem prop_shader_output_target_items[] = {
{SHD_OUTPUT_CYCLES, "CYCLES", 0, "Cycles", "Use shaders for Cycles renderer"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem rna_node_geometry_boolean_method_items[] = {
{GEO_NODE_BOOLEAN_INTERSECT,
"INTERSECT",
0,
"Intersect",
"Keep the part of the mesh that is common between all operands"},
{GEO_NODE_BOOLEAN_UNION, "UNION", 0, "Union", "Combine meshes in an additive way"},
{GEO_NODE_BOOLEAN_DIFFERENCE,
"DIFFERENCE",
0,
"Difference",
"Combine meshes in a subtractive way"},
{0, NULL, 0, NULL, NULL},
};
#endif
#ifdef RNA_RUNTIME
@@ -725,9 +742,9 @@ static const EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C),
# undef DefNode
}
if (RNA_struct_is_a(ptr->type, &RNA_SimulationNode)) {
if (RNA_struct_is_a(ptr->type, &RNA_GeometryNode)) {
# define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
if (STREQ(#Category, "SimulationNode")) { \
if (STREQ(#Category, "GeometryNode")) { \
tmp.value = ID; \
tmp.identifier = EnumName; \
tmp.name = UIName; \
@@ -1868,16 +1885,16 @@ static StructRNA *rna_TextureNode_register(Main *bmain,
return nt->rna_ext.srna;
}
static StructRNA *rna_SimulationNode_register(Main *bmain,
ReportList *reports,
void *data,
const char *identifier,
StructValidateFunc validate,
StructCallbackFunc call,
StructFreeFunc free)
static StructRNA *rna_GeometryNode_register(Main *bmain,
ReportList *reports,
void *data,
const char *identifier,
StructValidateFunc validate,
StructCallbackFunc call,
StructFreeFunc free)
{
bNodeType *nt = rna_Node_register_base(
bmain, reports, &RNA_SimulationNode, data, identifier, validate, call, free);
bmain, reports, &RNA_GeometryNode, data, identifier, validate, call, free);
if (!nt) {
return NULL;
}
@@ -8140,6 +8157,20 @@ static void def_tex_bricks(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
/* -- Geometry Nodes --------------------------------------------------------- */
static void def_geo_boolean(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_node_geometry_boolean_method_items);
RNA_def_property_enum_default(prop, GEO_NODE_BOOLEAN_INTERSECT);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
@@ -8177,14 +8208,14 @@ static void rna_def_texture_node(BlenderRNA *brna)
RNA_def_struct_register_funcs(srna, "rna_TextureNode_register", "rna_Node_unregister", NULL);
}
static void rna_def_simulation_node(BlenderRNA *brna)
static void rna_def_geometry_node(BlenderRNA *brna)
{
StructRNA *srna;
srna = RNA_def_struct(brna, "SimulationNode", "NodeInternal");
RNA_def_struct_ui_text(srna, "Simulation Node", "");
srna = RNA_def_struct(brna, "GeometryNode", "NodeInternal");
RNA_def_struct_ui_text(srna, "Geometry Node", "");
RNA_def_struct_sdna(srna, "bNode");
RNA_def_struct_register_funcs(srna, "rna_SimulationNode_register", "rna_Node_unregister", NULL);
RNA_def_struct_register_funcs(srna, "rna_GeometryNode_register", "rna_Node_unregister", NULL);
}
static void rna_def_function_node(BlenderRNA *brna)
@@ -8831,6 +8862,21 @@ static void rna_def_node_socket_image(BlenderRNA *brna,
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
}
static void rna_def_node_socket_geometry(BlenderRNA *brna,
const char *identifier,
const char *interface_idname)
{
StructRNA *srna;
srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
RNA_def_struct_ui_text(srna, "Geometry Node Socket", "Geometry socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
RNA_def_struct_ui_text(srna, "Geometry Node Socket Interface", "Geometry socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
}
static void rna_def_node_socket_standard_types(BlenderRNA *brna)
{
/* XXX Workaround: Registered functions are not exposed in python by bpy,
@@ -8969,6 +9015,8 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
rna_def_node_socket_object(brna, "NodeSocketObject", "NodeSocketInterfaceObject");
rna_def_node_socket_image(brna, "NodeSocketImage", "NodeSocketInterfaceImage");
rna_def_node_socket_geometry(brna, "NodeSocketGeometry", "NodeSocketInterfaceGeometry");
}
static void rna_def_internal_node(BlenderRNA *brna)
@@ -9606,7 +9654,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
{NTREE_SHADER, "SHADER", ICON_MATERIAL, "Shader", "Shader nodes"},
{NTREE_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture nodes"},
{NTREE_COMPOSIT, "COMPOSITING", ICON_RENDERLAYERS, "Compositing", "Compositing nodes"},
{NTREE_SIMULATION, "SIMULATION", ICON_PHYSICS, "Simulation", "Simulation nodes"},
{NTREE_GEOMETRY, "GEOMETRY", ICON_MESH_DATA, "Geometry", "Geometry nodes"},
{0, NULL, 0, NULL, NULL},
};
@@ -9830,15 +9878,15 @@ static void rna_def_texture_nodetree(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_TEXTURE);
}
static void rna_def_simulation_nodetree(BlenderRNA *brna)
static void rna_def_geometry_nodetree(BlenderRNA *brna)
{
StructRNA *srna;
srna = RNA_def_struct(brna, "SimulationNodeTree", "NodeTree");
srna = RNA_def_struct(brna, "GeometryNodeTree", "NodeTree");
RNA_def_struct_ui_text(
srna, "Simulation Node Tree", "Node tree consisting of linked nodes used for simulations");
srna, "Geometry Node Tree", "Node tree consisting of linked nodes used for geometries");
RNA_def_struct_sdna(srna, "bNodeTree");
RNA_def_struct_ui_icon(srna, ICON_PHYSICS); /* TODO: Use correct icon. */
RNA_def_struct_ui_icon(srna, ICON_MESH_DATA); /* TODO: Use correct icon. */
}
static StructRNA *define_specific_node(BlenderRNA *brna,
@@ -9927,7 +9975,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
rna_def_shader_node(brna);
rna_def_compositor_node(brna);
rna_def_texture_node(brna);
rna_def_simulation_node(brna);
rna_def_geometry_node(brna);
rna_def_function_node(brna);
rna_def_nodetree(brna);
@@ -9937,7 +9985,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
rna_def_composite_nodetree(brna);
rna_def_shader_nodetree(brna);
rna_def_texture_nodetree(brna);
rna_def_simulation_nodetree(brna);
rna_def_geometry_nodetree(brna);
# define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
{ \
@@ -9954,13 +10002,13 @@ void RNA_def_nodetree(BlenderRNA *brna)
*/
# include "../../nodes/NOD_static_types.h"
/* Node group types need to be defined for shader, compositor, texture, simulation nodes
/* Node group types need to be defined for shader, compositor, texture, geometry nodes
* individually. Cannot use the static types header for this, since they share the same int id.
*/
define_specific_node(brna, "ShaderNodeGroup", "ShaderNode", "Group", "", def_group);
define_specific_node(brna, "CompositorNodeGroup", "CompositorNode", "Group", "", def_group);
define_specific_node(brna, "TextureNodeGroup", "TextureNode", "Group", "", def_group);
define_specific_node(brna, "SimulationNodeGroup", "SimulationNode", "Group", "", def_group);
define_specific_node(brna, "GeometryNodeGroup", "GeometryNode", "Group", "", def_group);
def_custom_group(brna,
"ShaderNodeCustomGroup",
"ShaderNode",

View File

@@ -45,7 +45,6 @@
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_sequence_types.h"
#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
@@ -2178,40 +2177,6 @@ static void rna_SpaceNodeEditor_node_tree_update(const bContext *C, PointerRNA *
ED_node_tree_update(C);
}
# ifdef WITH_GEOMETRY_NODES
static PointerRNA rna_SpaceNodeEditor_simulation_get(PointerRNA *ptr)
{
SpaceNode *snode = (SpaceNode *)ptr->data;
ID *id = snode->id;
if (id && GS(id->name) == ID_SIM) {
return rna_pointer_inherit_refine(ptr, &RNA_Simulation, snode->id);
}
else {
return PointerRNA_NULL;
}
}
static void rna_SpaceNodeEditor_simulation_set(PointerRNA *ptr,
const PointerRNA value,
struct ReportList *UNUSED(reports))
{
SpaceNode *snode = (SpaceNode *)ptr->data;
if (!STREQ(snode->tree_idname, "SimulationNodeTree")) {
return;
}
Simulation *sim = (Simulation *)value.data;
if (sim != NULL) {
bNodeTree *ntree = sim->nodetree;
ED_node_tree_start(snode, ntree, NULL, NULL);
}
else {
ED_node_tree_start(snode, NULL, NULL, NULL);
}
snode->id = &sim->id;
}
# endif
static int rna_SpaceNodeEditor_tree_type_get(PointerRNA *ptr)
{
SpaceNode *snode = (SpaceNode *)ptr->data;
@@ -6347,19 +6312,6 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "ID From", "Data-block from which the edited data-block is linked");
# ifdef WITH_GEOMETRY_NODES
prop = RNA_def_property(srna, "simulation", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "Simulation");
RNA_def_property_ui_text(prop, "Simulation", "Simulation that is being edited");
RNA_def_property_pointer_funcs(prop,
"rna_SpaceNodeEditor_simulation_get",
"rna_SpaceNodeEditor_simulation_set",
NULL,
NULL);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
# endif
prop = RNA_def_property(srna, "path", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "treepath", NULL);
RNA_def_property_struct_type(prop, "NodeTreePath");

View File

@@ -29,8 +29,10 @@ set(INC
../bmesh
../depsgraph
../editors/include
../functions
../makesdna
../makesrna
../nodes
../render/extern/include
../windowmanager
../../../intern/eigen
@@ -86,7 +88,7 @@ set(SRC
intern/MOD_shapekey.c
intern/MOD_shrinkwrap.c
intern/MOD_simpledeform.c
intern/MOD_simulation.cc
intern/MOD_nodes.cc
intern/MOD_skin.c
intern/MOD_smooth.c
intern/MOD_softbody.c

View File

@@ -85,7 +85,7 @@ extern ModifierTypeInfo modifierType_CorrectiveSmooth;
extern ModifierTypeInfo modifierType_MeshSequenceCache;
extern ModifierTypeInfo modifierType_SurfaceDeform;
extern ModifierTypeInfo modifierType_WeightedNormal;
extern ModifierTypeInfo modifierType_Simulation;
extern ModifierTypeInfo modifierType_Nodes;
extern ModifierTypeInfo modifierType_MeshToVolume;
extern ModifierTypeInfo modifierType_VolumeDisplace;
extern ModifierTypeInfo modifierType_VolumeToMesh;

View File

@@ -53,7 +53,10 @@
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
static Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd)
/* For edge split modifier node. */
Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd);
Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd)
{
Mesh *result;
BMesh *bm;

View File

@@ -0,0 +1,496 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 by the Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup modifiers
*/
#include <cstring>
#include <iostream>
#include <string>
#include "MEM_guardedalloc.h"
#include "BLI_float3.hh"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_defaults.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "BKE_customdata.h"
#include "BKE_lib_query.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
#include "BKE_simulation.h"
#include "BLO_read_write.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "RNA_access.h"
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry_exec.hh"
#include "NOD_node_tree_multi_function.hh"
#include "NOD_type_callbacks.hh"
using blender::float3;
static void initData(ModifierData *md)
{
NodesModifierData *nmd = (NodesModifierData *)md;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(nmd, modifier));
MEMCPY_STRUCT_AFTER(nmd, DNA_struct_default_get(NodesModifierData), modifier);
}
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
if (nmd->node_group != nullptr) {
DEG_add_node_tree_relation(ctx->node, nmd->node_group, "Nodes Modifier");
}
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
walk(userData, ob, (ID **)&nmd->node_group, IDWALK_CB_USER);
}
static bool isDisabled(const struct Scene *UNUSED(scene),
ModifierData *md,
bool UNUSED(useRenderParams))
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
UNUSED_VARS(nmd);
return false;
}
static PointCloud *modifyPointCloud(ModifierData *md,
const ModifierEvalContext *UNUSED(ctx),
PointCloud *pointcloud)
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
UNUSED_VARS(nmd);
std::cout << __func__ << "\n";
return pointcloud;
}
/* To be replaced soon. */
using namespace blender;
using namespace blender::nodes;
using namespace blender::fn;
using namespace blender::bke;
class GeometryNodesEvaluator {
private:
LinearAllocator<> allocator_;
Map<const DInputSocket *, GMutablePointer> value_by_input_;
Vector<const DInputSocket *> group_outputs_;
MultiFunctionByNode &mf_by_node_;
const DataTypeConversions &conversions_;
public:
GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data,
Vector<const DInputSocket *> group_outputs,
MultiFunctionByNode &mf_by_node)
: group_outputs_(std::move(group_outputs)),
mf_by_node_(mf_by_node),
conversions_(get_implicit_type_conversions())
{
for (auto item : group_input_data.items()) {
this->forward_to_inputs(*item.key, item.value);
}
}
Vector<GMutablePointer> execute()
{
Vector<GMutablePointer> results;
for (const DInputSocket *group_output : group_outputs_) {
GMutablePointer result = this->get_input_value(*group_output);
results.append(result);
}
for (GMutablePointer value : value_by_input_.values()) {
value.destruct();
}
return results;
}
private:
GMutablePointer get_input_value(const DInputSocket &socket_to_compute)
{
std::optional<GMutablePointer> value = value_by_input_.pop_try(&socket_to_compute);
if (value.has_value()) {
/* This input has been computed before, return it directly. */
return *value;
}
Span<const DOutputSocket *> from_sockets = socket_to_compute.linked_sockets();
Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs();
const int total_inputs = from_sockets.size() + from_group_inputs.size();
BLI_assert(total_inputs <= 1);
const CPPType &type = *socket_cpp_type_get(*socket_to_compute.typeinfo());
if (total_inputs == 0) {
/* The input is not connected, use the value from the socket itself. */
bNodeSocket &bsocket = *socket_to_compute.bsocket();
void *buffer = allocator_.allocate(type.size(), type.alignment());
socket_cpp_value_get(bsocket, buffer);
return GMutablePointer{type, buffer};
}
if (from_group_inputs.size() == 1) {
/* The input gets its value from the input of a group that is not further connected. */
bNodeSocket &bsocket = *from_group_inputs[0]->bsocket();
void *buffer = allocator_.allocate(type.size(), type.alignment());
socket_cpp_value_get(bsocket, buffer);
return GMutablePointer{type, buffer};
}
/* Compute the socket now. */
const DOutputSocket &from_socket = *from_sockets[0];
this->compute_output_and_forward(from_socket);
return value_by_input_.pop(&socket_to_compute);
}
void compute_output_and_forward(const DOutputSocket &socket_to_compute)
{
const DNode &node = socket_to_compute.node();
/* Prepare inputs required to execute the node. */
GValueByName node_inputs{allocator_};
for (const DInputSocket *input_socket : node.inputs()) {
if (input_socket->is_available()) {
GMutablePointer value = this->get_input_value(*input_socket);
node_inputs.transfer_ownership_in(input_socket->identifier(), value);
}
}
/* Execute the node. */
GValueByName node_outputs{allocator_};
this->execute_node(node, node_inputs, node_outputs);
/* Forward computed outputs to linked input sockets. */
for (const DOutputSocket *output_socket : node.outputs()) {
if (output_socket->is_available()) {
GMutablePointer value = node_outputs.extract(output_socket->identifier());
this->forward_to_inputs(*output_socket, value);
}
}
}
void execute_node(const DNode &node, GValueByName &node_inputs, GValueByName &node_outputs)
{
bNode *bnode = node.bnode();
if (bnode->typeinfo->geometry_node_execute != nullptr) {
bnode->typeinfo->geometry_node_execute(bnode, node_inputs, node_outputs);
return;
}
/* Use the multi-function implementation of the node. */
const MultiFunction &fn = *mf_by_node_.lookup(&node);
MFContextBuilder context;
MFParamsBuilder params{fn, 1};
Vector<GMutablePointer> input_data;
for (const DInputSocket *dsocket : node.inputs()) {
if (dsocket->is_available()) {
GMutablePointer data = node_inputs.extract(dsocket->identifier());
params.add_readonly_single_input(GSpan(*data.type(), data.get(), 1));
input_data.append(data);
}
}
Vector<GMutablePointer> output_data;
for (const DOutputSocket *dsocket : node.outputs()) {
if (dsocket->is_available()) {
const CPPType &type = *socket_cpp_type_get(*dsocket->typeinfo());
void *buffer = allocator_.allocate(type.size(), type.alignment());
params.add_uninitialized_single_output(GMutableSpan(type, buffer, 1));
output_data.append(GMutablePointer(type, buffer));
}
}
fn.call(IndexRange(1), params, context);
for (GMutablePointer value : input_data) {
value.destruct();
}
for (const int i : node.outputs().index_range()) {
GMutablePointer value = output_data[i];
node_outputs.move_in(node.output(i).identifier(), value);
value.destruct();
}
}
void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward)
{
Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets();
const CPPType &from_type = *value_to_forward.type();
Vector<const DInputSocket *> to_sockets_same_type;
for (const DInputSocket *to_socket : to_sockets_all) {
const CPPType &to_type = *socket_cpp_type_get(*to_socket->typeinfo());
if (from_type == to_type) {
to_sockets_same_type.append(to_socket);
}
else {
void *buffer = allocator_.allocate(to_type.size(), to_type.alignment());
if (conversions_.is_convertible(from_type, to_type)) {
conversions_.convert(from_type, to_type, value_to_forward.get(), buffer);
}
else {
to_type.copy_to_uninitialized(to_type.default_value(), buffer);
}
value_by_input_.add_new(to_socket, GMutablePointer{to_type, buffer});
}
}
if (to_sockets_same_type.size() == 0) {
/* This value is not further used, so destruct it. */
value_to_forward.destruct();
}
else if (to_sockets_same_type.size() == 1) {
/* This value is only used on one input socket, no need to copy it. */
const DInputSocket *to_socket = to_sockets_same_type[0];
value_by_input_.add_new(to_socket, value_to_forward);
}
else {
/* Multiple inputs use the value, make a copy for every input except for one. */
const DInputSocket *first_to_socket = to_sockets_same_type[0];
Span<const DInputSocket *> other_to_sockets = to_sockets_same_type.as_span().drop_front(1);
const CPPType &type = *value_to_forward.type();
value_by_input_.add_new(first_to_socket, value_to_forward);
for (const DInputSocket *to_socket : other_to_sockets) {
void *buffer = allocator_.allocate(type.size(), type.alignment());
type.copy_to_uninitialized(value_to_forward.get(), buffer);
value_by_input_.add_new(to_socket, GMutablePointer{type, buffer});
}
}
}
};
/**
* Evaluate a node group to compute the output geometry.
* Currently, this uses a fairly basic and inefficient algorithm that might compute things more
* often than necessary. It's going to be replaced soon.
*/
static GeometryPtr compute_geometry(const DerivedNodeTree &tree,
Span<const DOutputSocket *> group_input_sockets,
const DInputSocket &socket_to_compute,
GeometryPtr input_geometry,
NodesModifierData *nmd)
{
ResourceCollector resources;
LinearAllocator<> &allocator = resources.linear_allocator();
MultiFunctionByNode mf_by_node = get_multi_function_per_node(tree, resources);
Map<const DOutputSocket *, GMutablePointer> group_inputs;
if (group_input_sockets.size() > 0) {
Span<const DOutputSocket *> remaining_input_sockets = group_input_sockets;
/* If the group expects a geometry as first input, use the geometry that has been passed to
* modifier. */
const DOutputSocket *first_input_socket = group_input_sockets[0];
if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) {
GeometryPtr *geometry_in = allocator.construct<GeometryPtr>(std::move(input_geometry));
group_inputs.add_new(first_input_socket, geometry_in);
remaining_input_sockets = remaining_input_sockets.drop_front(1);
}
/* Initialize remaining group inputs. */
for (const DOutputSocket *socket : remaining_input_sockets) {
const CPPType &type = *socket_cpp_type_get(*socket->typeinfo());
if (type.is<float>()) {
float *value_in = allocator.construct<float>(nmd->test_float_input);
group_inputs.add_new(socket, value_in);
}
else {
void *value_in = allocator.allocate(type.size(), type.alignment());
type.copy_to_uninitialized(type.default_value(), value_in);
group_inputs.add_new(socket, {type, value_in});
}
}
}
Vector<const DInputSocket *> group_outputs;
group_outputs.append(&socket_to_compute);
GeometryNodesEvaluator evaluator{group_inputs, group_outputs, mf_by_node};
Vector<GMutablePointer> results = evaluator.execute();
BLI_assert(results.size() == 1);
GMutablePointer result = results[0];
GeometryPtr output_geometry = std::move(*(GeometryPtr *)result.get());
return output_geometry;
}
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
if (nmd->node_group == nullptr) {
return mesh;
}
NodeTreeRefMap tree_refs;
DerivedNodeTree tree{nmd->node_group, tree_refs};
ResourceCollector resources;
Span<const DNode *> input_nodes = tree.nodes_by_type("NodeGroupInput");
Span<const DNode *> output_nodes = tree.nodes_by_type("NodeGroupOutput");
if (input_nodes.size() > 1) {
return mesh;
}
if (output_nodes.size() != 1) {
return mesh;
}
Span<const DOutputSocket *> group_inputs = (input_nodes.size() == 1) ?
input_nodes[0]->outputs().drop_back(1) :
Span<const DOutputSocket *>{};
Span<const DInputSocket *> group_outputs = output_nodes[0]->inputs().drop_back(1);
if (group_outputs.size() != 1) {
return mesh;
}
const DInputSocket *group_output = group_outputs[0];
if (group_output->idname() != "NodeSocketGeometry") {
return mesh;
}
GeometryPtr input_geometry{new Geometry()};
input_geometry->mesh_set_and_keep_ownership(mesh);
GeometryPtr new_geometry = compute_geometry(
tree, group_inputs, *group_outputs[0], std::move(input_geometry), nmd);
make_geometry_mutable(new_geometry);
Mesh *new_mesh = new_geometry->mesh_release();
if (new_mesh == nullptr) {
return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
}
return new_mesh;
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "node_group", 0, NULL, ICON_MESH_DATA);
uiItemR(layout, ptr, "test_float_input", 0, NULL, ICON_NONE);
modifier_panel_end(layout, ptr);
}
static void panelRegister(ARegionType *region_type)
{
modifier_panel_register(region_type, eModifierType_Nodes, panel_draw);
}
static void blendWrite(BlendWriter *writer, const ModifierData *md)
{
const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
UNUSED_VARS(nmd, writer);
}
static void blendRead(BlendDataReader *reader, ModifierData *md)
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
UNUSED_VARS(nmd, reader);
}
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
NodesModifierData *tnmd = reinterpret_cast<NodesModifierData *>(target);
UNUSED_VARS(nmd, tnmd);
BKE_modifier_copydata_generic(md, target, flag);
}
static void freeData(ModifierData *md)
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
UNUSED_VARS(nmd);
}
ModifierTypeInfo modifierType_Nodes = {
/* name */ "Nodes",
/* structName */ "NodesModifierData",
/* structSize */ sizeof(NodesModifierData),
#ifdef WITH_GEOMETRY_NODES
/* srna */ &RNA_NodesModifier,
#else
/* srna */ &RNA_Modifier,
#endif
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh,
/* icon */ ICON_MESH_DATA, /* TODO: Use correct icon. */
/* copyData */ copyData,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* modifyMesh */ modifyMesh,
/* modifyHair */ NULL,
/* modifyPointCloud */ modifyPointCloud,
/* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
/* freeRuntimeData */ NULL,
/* panelRegister */ panelRegister,
/* blendWrite */ blendWrite,
/* blendRead */ blendRead,
};

View File

@@ -1,194 +0,0 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 by the Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup modifiers
*/
#include <cstring>
#include <iostream>
#include <string>
#include "MEM_guardedalloc.h"
#include "BLI_float3.hh"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_defaults.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_simulation_types.h"
#include "BKE_customdata.h"
#include "BKE_lib_query.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
#include "BKE_simulation.h"
#include "BLO_read_write.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "RNA_access.h"
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
using blender::float3;
static void initData(ModifierData *md)
{
SimulationModifierData *smd = (SimulationModifierData *)md;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(smd, modifier));
MEMCPY_STRUCT_AFTER(smd, DNA_struct_default_get(SimulationModifierData), modifier);
}
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *UNUSED(ctx))
{
SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
UNUSED_VARS(smd);
}
static void foreachIDLink(ModifierData *md,
Object *UNUSED(ob),
IDWalkFunc UNUSED(walk),
void *UNUSED(userData))
{
SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
UNUSED_VARS(smd);
}
static bool isDisabled(const struct Scene *UNUSED(scene),
ModifierData *md,
bool UNUSED(useRenderParams))
{
SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
UNUSED_VARS(smd);
return false;
}
static PointCloud *modifyPointCloud(ModifierData *md,
const ModifierEvalContext *UNUSED(ctx),
PointCloud *pointcloud)
{
SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
UNUSED_VARS(smd);
return pointcloud;
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemL(layout, "This modifier does nothing currently", ICON_INFO);
modifier_panel_end(layout, ptr);
}
static void panelRegister(ARegionType *region_type)
{
modifier_panel_register(region_type, eModifierType_Simulation, panel_draw);
}
static void blendWrite(BlendWriter *writer, const ModifierData *md)
{
const SimulationModifierData *smd = reinterpret_cast<const SimulationModifierData *>(md);
UNUSED_VARS(smd, writer);
}
static void blendRead(BlendDataReader *reader, ModifierData *md)
{
SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
UNUSED_VARS(smd, reader);
}
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const SimulationModifierData *smd = reinterpret_cast<const SimulationModifierData *>(md);
SimulationModifierData *tsmd = reinterpret_cast<SimulationModifierData *>(target);
UNUSED_VARS(smd, tsmd);
BKE_modifier_copydata_generic(md, target, flag);
}
static void freeData(ModifierData *md)
{
SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
UNUSED_VARS(smd);
}
ModifierTypeInfo modifierType_Simulation = {
/* name */ "Simulation",
/* structName */ "SimulationModifierData",
/* structSize */ sizeof(SimulationModifierData),
#ifdef WITH_GEOMETRY_NODES
/* srna */ &RNA_SimulationModifier,
#else
/* srna */ &RNA_Modifier,
#endif
/* type */ eModifierTypeType_None,
/* flags */ (ModifierTypeFlag)0,
/* icon */ ICON_PHYSICS, /* TODO: Use correct icon. */
/* copyData */ copyData,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* modifyMesh */ NULL,
/* modifyHair */ NULL,
/* modifyPointCloud */ modifyPointCloud,
/* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
/* freeRuntimeData */ NULL,
/* panelRegister */ panelRegister,
/* blendWrite */ blendWrite,
/* blendRead */ blendRead,
};

View File

@@ -48,11 +48,17 @@
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
static Mesh *triangulate_mesh(Mesh *mesh,
const int quad_method,
const int ngon_method,
const int min_vertices,
const int flag)
Mesh *triangulate_mesh(Mesh *mesh,
const int quad_method,
const int ngon_method,
const int min_vertices,
const int flag);
Mesh *triangulate_mesh(Mesh *mesh,
const int quad_method,
const int ngon_method,
const int min_vertices,
const int flag)
{
Mesh *result;
BMesh *bm;

View File

@@ -342,7 +342,7 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(MeshSequenceCache);
INIT_TYPE(SurfaceDeform);
INIT_TYPE(WeightedNormal);
INIT_TYPE(Simulation);
INIT_TYPE(Nodes);
INIT_TYPE(MeshToVolume);
INIT_TYPE(VolumeDisplace);
INIT_TYPE(VolumeToMesh);

View File

@@ -24,11 +24,12 @@ set(INC
function
intern
shader
simulation
geometry
texture
../blenkernel
../blenlib
../blentranslation
../bmesh
../depsgraph
../functions
../gpu
@@ -137,6 +138,15 @@ set(SRC
function/nodes/node_fn_switch.cc
function/node_function_util.cc
geometry/nodes/node_geo_common.cc
geometry/nodes/node_geo_boolean.cc
geometry/nodes/node_geo_edge_split.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc
geometry/node_geometry_exec.cc
geometry/node_geometry_tree.cc
geometry/node_geometry_util.cc
shader/nodes/node_shader_add_shader.c
shader/nodes/node_shader_ambient_occlusion.c
shader/nodes/node_shader_attribute.c
@@ -230,10 +240,6 @@ set(SRC
shader/node_shader_tree.c
shader/node_shader_util.c
simulation/nodes/node_sim_common.cc
simulation/node_simulation_tree.cc
simulation/node_simulation_util.cc
texture/nodes/node_texture_at.c
texture/nodes/node_texture_bricks.c
texture/nodes/node_texture_checker.c
@@ -268,11 +274,12 @@ set(SRC
intern/node_tree_multi_function.cc
intern/node_tree_ref.cc
intern/node_util.c
intern/type_callbacks.cc
composite/node_composite_util.h
function/node_function_util.hh
shader/node_shader_util.h
simulation/node_simulation_util.h
geometry/node_geometry_util.hh
texture/node_texture_util.h
NOD_common.h
@@ -283,10 +290,11 @@ set(SRC
NOD_node_tree_multi_function.hh
NOD_node_tree_ref.hh
NOD_shader.h
NOD_simulation.h
NOD_geometry.h
NOD_socket.h
NOD_static_types.h
NOD_texture.h
NOD_type_callbacks.hh
intern/node_common.h
intern/node_exec.h
intern/node_util.h
@@ -295,6 +303,7 @@ set(SRC
set(LIB
bf_functions
bf_intern_sky
bf_bmesh
)
if(WITH_PYTHON)

View File

@@ -65,6 +65,8 @@ class DSocket : NonCopyable, NonMovable {
PointerRNA *rna() const;
StringRefNull idname() const;
StringRefNull name() const;
StringRefNull identifier() const;
bNodeSocketType *typeinfo() const;
const SocketRef &socket_ref() const;
bNodeSocket *bsocket() const;
@@ -147,6 +149,8 @@ class DNode : NonCopyable, NonMovable {
PointerRNA *rna() const;
StringRefNull idname() const;
StringRefNull name() const;
bNode *bnode() const;
bNodeType *typeinfo() const;
private:
void destruct_with_sockets();
@@ -288,6 +292,16 @@ inline StringRefNull DSocket::name() const
return socket_ref_->name();
}
inline StringRefNull DSocket::identifier() const
{
return socket_ref_->identifier();
}
inline bNodeSocketType *DSocket::typeinfo() const
{
return socket_ref_->bsocket()->typeinfo;
}
inline const SocketRef &DSocket::socket_ref() const
{
return *socket_ref_;
@@ -445,6 +459,16 @@ inline StringRefNull DNode::name() const
return node_ref_->name();
}
inline bNode *DNode::bnode() const
{
return node_ref_->bnode();
}
inline bNodeType *DNode::typeinfo() const
{
return node_ref_->bnode()->typeinfo;
}
/* --------------------------------------------------------------------
* DParentNode inline methods.
*/

View File

@@ -0,0 +1,36 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
extern struct bNodeTreeType *ntreeType_Geometry;
void register_node_tree_type_geo(void);
void register_node_type_geo_group(void);
void register_node_type_geo_triangulate(void);
void register_node_type_geo_boolean(void);
void register_node_type_geo_edge_split(void);
void register_node_type_geo_transform(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,99 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include "FN_generic_pointer.hh"
#include "BLI_linear_allocator.hh"
#include "BLI_map.hh"
#include "BKE_geometry.hh"
namespace blender::nodes {
using bke::Geometry;
using bke::GeometryPtr;
using fn::CPPType;
using fn::GMutablePointer;
/**
* This container maps names to values of arbitrary type. It is used to represent the input and
* output values of geometry nodes.
*
* The string keys are only referenced, but the values are owned.
*/
class GValueByName {
private:
/* Used to allocate values owned by this container. */
LinearAllocator<> &allocator_;
Map<StringRef, GMutablePointer> values_;
public:
GValueByName(LinearAllocator<> &allocator) : allocator_(allocator)
{
}
~GValueByName()
{
/* Destruct all values that have not been destructed. */
for (GMutablePointer value : values_.values()) {
value.type()->destruct(value.get());
}
}
/* Add a value to the container. The container is responsible for destructing the value that is
* passed in. */
void transfer_ownership_in(StringRef name, GMutablePointer value)
{
values_.add_new(name, value);
}
/* Add a value to the container. The caller remains responsible for destructing the value. */
void move_in(StringRef name, GMutablePointer value)
{
const CPPType &type = *value.type();
void *buffer = allocator_.allocate(type.size(), type.alignment());
type.move_to_uninitialized(value.get(), buffer);
values_.add_new(name, GMutablePointer{type, buffer});
}
/* Add a value to the container. */
template<typename T> void move_in(StringRef name, T &&value)
{
this->move_in(name, GMutablePointer{&value});
}
/* Remove the value for the given name from the container and remove it. The caller is
* responsible for freeing it. */
GMutablePointer extract(StringRef name)
{
return values_.pop(name);
}
/* Remove the value for the given name from the container and remove it. */
template<typename T> T extract(StringRef name)
{
GMutablePointer value = values_.pop(name);
const CPPType &type = *value.type();
BLI_assert(type.is<T>());
T return_value;
type.relocate_to_initialized(value.get(), &return_value);
return return_value;
}
};
} // namespace blender::nodes

View File

@@ -26,21 +26,12 @@
#include "FN_multi_function_network.hh"
#include "NOD_derived_node_tree.hh"
#include "NOD_type_callbacks.hh"
#include "BLI_resource_collector.hh"
namespace blender::nodes {
/* Maybe this should be moved to BKE_node.h. */
inline bool is_multi_function_data_socket(const bNodeSocket *bsocket)
{
if (bsocket->typeinfo->get_mf_data_type != nullptr) {
BLI_assert(bsocket->typeinfo->expand_in_mf_network != nullptr);
return true;
}
return false;
}
/**
* A MFNetworkTreeMap maps various components of a DerivedNodeTree to components of a
* fn::MFNetwork. This is necessary for further processing of a multi-function network that has
@@ -149,7 +140,7 @@ class MFNetworkTreeMap {
if (!dsocket->is_available()) {
continue;
}
if (!is_multi_function_data_socket(dsocket->bsocket())) {
if (!socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) {
continue;
}
fn::MFSocket *socket = sockets[used_sockets];
@@ -299,6 +290,11 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase {
{
this->construct_generator_fn<fn::CustomMF_Constant<T>>(std::move(value));
}
void set_constant_value(const CPPType &type, const void *value)
{
/* The value has live as long as the generated mf network. */
this->construct_generator_fn<fn::CustomMF_GenericConstant>(type, value);
}
template<typename T, typename... Args> void construct_generator_fn(Args &&... args)
{
@@ -397,4 +393,37 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
const DerivedNodeTree &tree,
ResourceCollector &resources);
using MultiFunctionByNode = Map<const DNode *, const fn::MultiFunction *>;
MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
ResourceCollector &resources);
class DataTypeConversions {
private:
Map<std::pair<fn::MFDataType, fn::MFDataType>, const fn::MultiFunction *> conversions_;
public:
void add(fn::MFDataType from_type, fn::MFDataType to_type, const fn::MultiFunction &fn)
{
conversions_.add_new({from_type, to_type}, &fn);
}
const fn::MultiFunction *get_conversion(fn::MFDataType from, fn::MFDataType to) const
{
return conversions_.lookup_default({from, to}, nullptr);
}
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
{
return conversions_.contains(
{fn::MFDataType::ForSingle(from_type), fn::MFDataType::ForSingle(to_type)});
}
void convert(const CPPType &from_type,
const CPPType &to_type,
const void *from_value,
void *to_value) const;
};
const DataTypeConversions &get_implicit_type_conversions();
} // namespace blender::nodes

View File

@@ -101,6 +101,7 @@ class SocketRef : NonCopyable, NonMovable {
StringRefNull idname() const;
StringRefNull name() const;
StringRefNull identifier() const;
bNodeSocket *bsocket() const;
bNode *bnode() const;
@@ -272,6 +273,11 @@ inline StringRefNull SocketRef::name() const
return bsocket_->name;
}
inline StringRefNull SocketRef::identifier() const
{
return bsocket_->identifier;
}
inline bNodeSocket *SocketRef::bsocket() const
{
return bsocket_;

View File

@@ -266,6 +266,11 @@ DefNode(FunctionNode, FN_NODE_COMBINE_STRINGS, 0, "COMBINE_STRINGS
DefNode(FunctionNode, FN_NODE_OBJECT_TRANSFORMS, 0, "OBJECT_TRANSFORMS", ObjectTransforms, "Object Transforms", "")
DefNode(FunctionNode, FN_NODE_RANDOM_FLOAT, 0, "RANDOM_FLOAT", RandomFloat, "Random Float", "")
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, 0, "TRIANGULATE", Triangulate, "Triangulate", "")
DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "")
DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "")
DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Boolean", "")
/* undefine macros */
#undef DefNode

View File

@@ -0,0 +1,36 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include <optional>
#include "BKE_node.h"
#include "FN_multi_function_data_type.hh"
namespace blender::nodes {
using fn::CPPType;
using fn::MFDataType;
const CPPType *socket_cpp_type_get(const bNodeSocketType &stype);
std::optional<MFDataType> socket_mf_type_get(const bNodeSocketType &stype);
bool socket_is_mf_data_socket(const bNodeSocketType &stype);
bool socket_cpp_value_get(const bNodeSocket &socket, void *r_value);
void socket_expand_in_mf_network(SocketMFNetworkBuilder &builder);
} // namespace blender::nodes

View File

@@ -20,7 +20,7 @@
bool fn_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
{
/* Function nodes are only supported in simulation node trees so far. */
return STREQ(ntree->idname, "SimulationNodeTree");
return STREQ(ntree->idname, "GeometryNodeTree");
}
void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)

View File

@@ -21,7 +21,7 @@
static bNodeSocketTemplate fn_node_random_float_in[] = {
{SOCK_FLOAT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_FLOAT, N_("Max"), 1.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_INT, N_("Seed")},
{SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000},
{-1, ""},
};

View File

@@ -14,18 +14,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include "NOD_geometry_exec.hh"
#ifdef __cplusplus
extern "C" {
#endif
MAKE_CPP_TYPE(GeometryPtr, blender::bke::GeometryPtr);
extern struct bNodeTreeType *ntreeType_Simulation;
namespace blender::nodes {
void register_node_tree_type_sim(void);
void register_node_type_sim_group(void);
#ifdef __cplusplus
}
#endif

View File

@@ -18,7 +18,7 @@
#include "MEM_guardedalloc.h"
#include "NOD_simulation.h"
#include "NOD_geometry.h"
#include "BKE_node.h"
@@ -28,18 +28,18 @@
#include "RNA_access.h"
bNodeTreeType *ntreeType_Simulation;
bNodeTreeType *ntreeType_Geometry;
void register_node_tree_type_sim(void)
void register_node_tree_type_geo(void)
{
bNodeTreeType *tt = ntreeType_Simulation = static_cast<bNodeTreeType *>(
MEM_callocN(sizeof(bNodeTreeType), "simulation node tree type"));
tt->type = NTREE_SIMULATION;
strcpy(tt->idname, "SimulationNodeTree");
strcpy(tt->ui_name, N_("Simulation Editor"));
bNodeTreeType *tt = ntreeType_Geometry = static_cast<bNodeTreeType *>(
MEM_callocN(sizeof(bNodeTreeType), "geometry node tree type"));
tt->type = NTREE_GEOMETRY;
strcpy(tt->idname, "GeometryNodeTree");
strcpy(tt->ui_name, N_("Geometry Node Editor"));
tt->ui_icon = 0; /* defined in drawnode.c */
strcpy(tt->ui_description, N_("Simulation nodes"));
tt->rna_ext.srna = &RNA_SimulationNodeTree;
strcpy(tt->ui_description, N_("Geometry nodes"));
tt->rna_ext.srna = &RNA_GeometryNodeTree;
ntreeTypeAdd(tt);
}

View File

@@ -14,16 +14,16 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "node_simulation_util.h"
#include "node_geometry_util.hh"
#include "node_util.h"
bool sim_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
bool geo_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
{
return STREQ(ntree->idname, "SimulationNodeTree");
return STREQ(ntree->idname, "GeometryNodeTree");
}
void sim_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
{
node_type_base(ntype, type, name, nclass, flag);
ntype->poll = sim_node_poll_default;
ntype->poll = geo_node_poll_default;
}

View File

@@ -18,6 +18,7 @@
#include <string.h>
#include "BLI_float3.hh"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
@@ -28,10 +29,11 @@
#include "BLT_translation.h"
#include "NOD_simulation.h"
#include "NOD_geometry.h"
#include "NOD_geometry_exec.hh"
#include "node_util.h"
void sim_node_type_base(
void geo_node_type_base(
struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
bool sim_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
bool geo_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);

View File

@@ -0,0 +1,146 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
#include "BLI_math_matrix.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "RNA_enum_types.h"
#include "BKE_mesh.h"
#include "bmesh.h"
#include "tools/bmesh_boolean.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_boolean_in[] = {
{SOCK_GEOMETRY, N_("Geometry A")},
{SOCK_GEOMETRY, N_("Geometry B")},
{-1, ""},
};
static bNodeSocketTemplate geo_node_boolean_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
{
return BM_elem_flag_test(f, BM_ELEM_DRAW) ? 1 : 0;
}
static Mesh *mesh_boolean_calc(Mesh *mesh_a, Mesh *mesh_b, int boolean_mode)
{
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh_a, mesh_b);
BMesh *bm;
{
struct BMeshCreateParams bmesh_create_params = {.use_toolflags = false};
bm = BM_mesh_create(&allocsize, &bmesh_create_params);
}
{
struct BMeshFromMeshParams bmesh_from_mesh_params = {.calc_face_normal = true};
BM_mesh_bm_from_me(bm, mesh_a, &bmesh_from_mesh_params);
BM_mesh_bm_from_me(bm, mesh_b, &bmesh_from_mesh_params);
}
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
int tottri;
BMLoop *(*looptris)[3] = (BMLoop *
(*)[3])(MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__));
BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri);
const int i_faces_end = mesh_a->totpoly;
/* We need face normals because of 'BM_face_split_edgenet'
* we could calculate on the fly too (before calling split). */
int i = 0;
BMIter iter;
BMFace *bm_face;
BM_ITER_MESH (bm_face, &iter, bm, BM_FACES_OF_MESH) {
normalize_v3(bm_face->no);
/* Temp tag to test which side split faces are from. */
BM_elem_flag_enable(bm_face, BM_ELEM_DRAW);
i++;
if (i == i_faces_end) {
break;
}
}
BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, 2, false, boolean_mode);
Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh_a);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
MEM_freeN(looptris);
return result;
}
namespace blender::nodes {
static void geo_boolean_exec(bNode *node, GValueByName &inputs, GValueByName &outputs)
{
GeometryPtr geometry_in_a = inputs.extract<GeometryPtr>("Geometry A");
GeometryPtr geometry_in_b = inputs.extract<GeometryPtr>("Geometry B");
GeometryPtr geometry_out;
if (!geometry_in_a.has_value() || !geometry_in_b.has_value()) {
outputs.move_in("Geometry", std::move(geometry_out));
return;
}
Mesh *mesh_in_a = geometry_in_a->mesh_get_for_read();
Mesh *mesh_in_b = geometry_in_b->mesh_get_for_read();
if (mesh_in_a == nullptr || mesh_in_b == nullptr) {
outputs.move_in("Geometry", std::move(geometry_out));
return;
}
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1;
if (operation < 0 || operation > 2) {
BLI_assert(false);
outputs.move_in("Geometry", std::move(geometry_out));
return;
}
geometry_out = GeometryPtr{new Geometry()};
Mesh *mesh_out = mesh_boolean_calc(mesh_in_a, mesh_in_b, operation);
geometry_out->mesh_set_and_transfer_ownership(mesh_out);
outputs.move_in("Geometry", std::move(geometry_out));
}
} // namespace blender::nodes
void register_node_type_geo_boolean()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_BOOLEAN, "Boolean", 0, 0);
node_type_socket_templates(&ntype, geo_node_boolean_in, geo_node_boolean_out);
ntype.geometry_node_execute = blender::nodes::geo_boolean_exec;
nodeRegisterType(&ntype);
}

View File

@@ -16,23 +16,23 @@
#include "BKE_node.h"
#include "NOD_simulation.h"
#include "NOD_geometry.h"
#include "NOD_common.h"
#include "node_common.h"
#include "node_simulation_util.h"
#include "node_geometry_util.hh"
void register_node_type_sim_group(void)
void register_node_type_geo_group(void)
{
static bNodeType ntype;
node_type_base_custom(&ntype, "SimulationNodeGroup", "Group", 0, 0);
node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", 0, 0);
ntype.type = NODE_GROUP;
ntype.poll = sim_node_poll_default;
ntype.poll = geo_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
ntype.insert_link = node_insert_link_default;
ntype.update_internal_links = node_update_internal_links_default;
ntype.rna_ext.srna = RNA_struct_find("SimulationNodeGroup");
ntype.rna_ext.srna = RNA_struct_find("GeometryNodeGroup");
BLI_assert(ntype.rna_ext.srna != NULL);
RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);

View File

@@ -0,0 +1,83 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BLI_math_base.h"
#include "BLI_math_rotation.h"
#include "DNA_modifier_types.h"
#include "node_geometry_util.hh"
extern "C" {
Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd);
}
static bNodeSocketTemplate geo_node_edge_split_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_FLOAT,
N_("Angle"),
DEG2RADF(30.0f),
0.0f,
0.0f,
0.0f,
0.0f,
DEG2RADF(180.0f),
PROP_ANGLE},
{SOCK_BOOLEAN, N_("Sharp Edges")},
{-1, ""},
};
static bNodeSocketTemplate geo_node_edge_split_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
static void geo_edge_split_exec(bNode *UNUSED(node), GValueByName &inputs, GValueByName &outputs)
{
GeometryPtr geometry_in = inputs.extract<GeometryPtr>("Geometry");
GeometryPtr geometry_out;
if (geometry_in.has_value()) {
Mesh *mesh_in = geometry_in->mesh_get_for_read();
if (mesh_in != nullptr) {
const float split_angle = inputs.extract<float>("Angle");
const bool use_sharp_flag = inputs.extract<bool>("Sharp Edges");
/* Use modifier struct to pass arguments to the modifier code. */
EdgeSplitModifierData emd = {.split_angle = split_angle, .flags = MOD_EDGESPLIT_FROMANGLE};
if (use_sharp_flag) {
emd.flags |= MOD_EDGESPLIT_FROMFLAG;
}
Mesh *mesh_out = doEdgeSplit(mesh_in, &emd);
geometry_out = GeometryPtr{new Geometry()};
geometry_out->mesh_set_and_transfer_ownership(mesh_out);
}
}
outputs.move_in("Geometry", std::move(geometry_out));
}
} // namespace blender::nodes
void register_node_type_geo_edge_split()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_EDGE_SPLIT, "Edge Split", 0, 0);
node_type_socket_templates(&ntype, geo_node_edge_split_in, geo_node_edge_split_out);
ntype.geometry_node_execute = blender::nodes::geo_edge_split_exec;
nodeRegisterType(&ntype);
}

View File

@@ -0,0 +1,75 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BKE_mesh.h"
#include "BLI_math_matrix.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_transform_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_VECTOR, N_("Translation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
{SOCK_VECTOR, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
{-1, ""},
};
static bNodeSocketTemplate geo_node_transform_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
static void geo_transform_exec(bNode *UNUSED(node), GValueByName &inputs, GValueByName &outputs)
{
GeometryPtr geometry = inputs.extract<GeometryPtr>("Geometry");
if (!geometry.has_value() || !geometry->mesh_available()) {
outputs.move_in("Geometry", std::move(geometry));
return;
}
bke::make_geometry_mutable(geometry);
Mesh *mesh = geometry->mesh_get_for_write();
const float3 translation = inputs.extract<float3>("Translation");
const float3 rotation = inputs.extract<float3>("Rotation");
const float3 scale = inputs.extract<float3>("Scale");
/* Use only translation if rotation and scale are zero. */
if (translation.length() > 0.0f && rotation.length() == 0.0f && scale.length() == 0.0f) {
BKE_mesh_translate(mesh, translation, true);
}
else {
float mat[4][4];
loc_eul_size_to_mat4(mat, translation, rotation, scale);
BKE_mesh_transform(mesh, mat, true);
}
outputs.move_in("Geometry", std::move(geometry));
}
} // namespace blender::nodes
void register_node_type_geo_transform()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", 0, 0);
node_type_socket_templates(&ntype, geo_node_transform_in, geo_node_transform_out);
ntype.geometry_node_execute = blender::nodes::geo_transform_exec;
nodeRegisterType(&ntype);
}

View File

@@ -0,0 +1,64 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "node_geometry_util.hh"
extern "C" {
Mesh *triangulate_mesh(Mesh *mesh,
const int quad_method,
const int ngon_method,
const int min_vertices,
const int flag);
}
static bNodeSocketTemplate geo_node_triangulate_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_INT, N_("Minimum Vertices"), 4, 0, 0, 0, 4, 10000},
{-1, ""},
};
static bNodeSocketTemplate geo_node_triangulate_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
static void geo_triangulate_exec(bNode *UNUSED(node), GValueByName &inputs, GValueByName &outputs)
{
GeometryPtr geometry_in = inputs.extract<GeometryPtr>("Geometry");
const int min_vertices = std::max(inputs.extract<int>("Minimum Vertices"), 4);
GeometryPtr geometry_out;
if (geometry_in.has_value()) {
Mesh *mesh_in = geometry_in->mesh_get_for_read();
if (mesh_in != nullptr) {
Mesh *mesh_out = triangulate_mesh(mesh_in, 3, 0, min_vertices, 0);
geometry_out = GeometryPtr{new Geometry()};
geometry_out->mesh_set_and_transfer_ownership(mesh_out);
}
}
outputs.move_in("Geometry", std::move(geometry_out));
}
} // namespace blender::nodes
void register_node_type_geo_triangulate()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", 0, 0);
node_type_socket_templates(&ntype, geo_node_triangulate_in, geo_node_triangulate_out);
ntype.geometry_node_execute = blender::nodes::geo_triangulate_exec;
nodeRegisterType(&ntype);
}

View File

@@ -32,6 +32,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_geometry.hh"
#include "BKE_lib_id.h"
#include "BKE_node.h"
#include "BKE_persistent_data_handle.hh"
@@ -552,10 +553,9 @@ static bNodeSocketType *make_socket_type_virtual(void)
static bNodeSocketType *make_socket_type_bool()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE);
socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<bool>(); };
socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
bool value = builder.socket_default_value<bNodeSocketValueBoolean>()->value;
builder.set_constant_value(value);
socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<bool>(); };
socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value;
};
return socktype;
}
@@ -563,10 +563,9 @@ static bNodeSocketType *make_socket_type_bool()
static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype);
socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<float>(); };
socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
float value = builder.socket_default_value<bNodeSocketValueFloat>()->value;
builder.set_constant_value(value);
socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<float>(); };
socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value;
};
return socktype;
}
@@ -574,10 +573,9 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype);
socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<int>(); };
socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
int value = builder.socket_default_value<bNodeSocketValueInt>()->value;
builder.set_constant_value(value);
socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<int>(); };
socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value;
};
return socktype;
}
@@ -585,12 +583,9 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype);
socktype->get_mf_data_type = []() {
return blender::fn::MFDataType::ForSingle<blender::float3>();
};
socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
blender::float3 value = builder.socket_default_value<bNodeSocketValueVector>()->value;
builder.set_constant_value(value);
socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<blender::float3>(); };
socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value;
};
return socktype;
}
@@ -598,12 +593,9 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
static bNodeSocketType *make_socket_type_rgba()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE);
socktype->get_mf_data_type = []() {
return blender::fn::MFDataType::ForSingle<blender::Color4f>();
};
socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
blender::Color4f value = builder.socket_default_value<bNodeSocketValueRGBA>()->value;
builder.set_constant_value(value);
socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<blender::Color4f>(); };
socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(blender::Color4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value;
};
return socktype;
}
@@ -611,10 +603,9 @@ static bNodeSocketType *make_socket_type_rgba()
static bNodeSocketType *make_socket_type_string()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE);
socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<std::string>(); };
socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
std::string value = builder.socket_default_value<bNodeSocketValueString>()->value;
builder.set_constant_value(value);
socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<std::string>(); };
socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value);
};
return socktype;
}
@@ -661,9 +652,9 @@ MAKE_CPP_TYPE(PersistentObjectHandle, blender::bke::PersistentObjectHandle);
static bNodeSocketType *make_socket_type_object()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE);
socktype->get_mf_data_type = []() {
socktype->get_cpp_type = []() {
/* Objects are not passed along as raw pointers, but as handles. */
return blender::fn::MFDataType::ForSingle<blender::bke::PersistentObjectHandle>();
return &blender::fn::CPPType::get<blender::bke::PersistentObjectHandle>();
};
socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
Object *object = builder.socket_default_value<bNodeSocketValueObject>()->value;
@@ -672,6 +663,18 @@ static bNodeSocketType *make_socket_type_object()
return socktype;
}
static bNodeSocketType *make_socket_type_geometry()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE);
socktype->get_cpp_type = []() {
return &blender::fn::CPPType::get<blender::bke::GeometryPtr>();
};
socktype->get_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) {
new (r_value) blender::bke::GeometryPtr();
};
return socktype;
}
void register_standard_node_socket_types(void)
{
/* draw callbacks are set in drawnode.c to avoid bad-level calls */
@@ -708,5 +711,7 @@ void register_standard_node_socket_types(void)
nodeRegisterSocketType(make_standard_socket_type(SOCK_IMAGE, PROP_NONE));
nodeRegisterSocketType(make_socket_type_geometry());
nodeRegisterSocketType(make_socket_type_virtual());
}

View File

@@ -16,21 +16,13 @@
#include "NOD_node_tree_multi_function.hh"
#include "FN_multi_function_network_evaluation.hh"
#include "BLI_color.hh"
#include "BLI_float3.hh"
namespace blender::nodes {
/* Maybe this should be moved to BKE_node.h. */
static std::optional<fn::MFDataType> try_get_multi_function_data_type_of_socket(
const bNodeSocket *bsocket)
{
if (bsocket->typeinfo->get_mf_data_type == nullptr) {
return {};
}
return bsocket->typeinfo->get_mf_data_type();
}
const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name)
{
Vector<fn::MFDataType, 10> input_types;
@@ -38,8 +30,7 @@ const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name)
for (const DInputSocket *dsocket : dnode_.inputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
dsocket->bsocket());
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
input_types.append(*data_type);
}
@@ -47,8 +38,7 @@ const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name)
}
for (const DOutputSocket *dsocket : dnode_.outputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
dsocket->bsocket());
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
output_types.append(*data_type);
}
@@ -70,8 +60,7 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
for (const DInputSocket *dsocket : dnode.inputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
dsocket->bsocket());
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
input_types.append(*data_type);
input_names.append(dsocket->name());
@@ -86,8 +75,7 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
for (const DOutputSocket *dsocket : dnode.outputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
dsocket->bsocket());
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
output_types.append(*data_type);
output_names.append(dsocket->name());
@@ -106,12 +94,12 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
static bool has_data_sockets(const DNode &dnode)
{
for (const DInputSocket *socket : dnode.inputs()) {
if (is_multi_function_data_socket(socket->bsocket())) {
if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
return true;
}
}
for (const DOutputSocket *socket : dnode.outputs()) {
if (is_multi_function_data_socket(socket->bsocket())) {
if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
return true;
}
}
@@ -140,7 +128,7 @@ static void insert_group_inputs(CommonMFNetworkBuilderData &common)
{
for (const DGroupInput *group_input : common.tree.group_inputs()) {
bNodeSocket *bsocket = group_input->bsocket();
if (is_multi_function_data_socket(bsocket)) {
if (socket_is_mf_data_socket(*bsocket->typeinfo)) {
bNodeSocketType *socktype = bsocket->typeinfo;
BLI_assert(socktype->expand_in_mf_network != nullptr);
@@ -171,44 +159,43 @@ static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common,
if (!from_dsocket.is_available()) {
return nullptr;
}
if (is_multi_function_data_socket(from_dsocket.bsocket())) {
if (socket_is_mf_data_socket(*from_dsocket.bsocket()->typeinfo)) {
return &common.network_map.lookup(from_dsocket);
}
return nullptr;
}
const DGroupInput &from_group_input = *from_group_inputs[0];
if (is_multi_function_data_socket(from_group_input.bsocket())) {
if (socket_is_mf_data_socket(*from_group_input.bsocket()->typeinfo)) {
return &common.network_map.lookup(from_group_input);
}
return nullptr;
}
using ImplicitConversionsMap =
Map<std::pair<fn::MFDataType, fn::MFDataType>, const fn::MultiFunction *>;
template<typename From, typename To>
static void add_implicit_conversion(ImplicitConversionsMap &map)
static void add_implicit_conversion(DataTypeConversions &conversions)
{
static fn::CustomMF_Convert<From, To> function;
map.add({fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>()}, &function);
conversions.add(fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>(), function);
}
template<typename From, typename To, typename ConversionF>
static void add_implicit_conversion(ImplicitConversionsMap &map,
static void add_implicit_conversion(DataTypeConversions &conversions,
StringRef name,
ConversionF conversion)
{
static fn::CustomMF_SI_SO<From, To> function{name, conversion};
map.add({fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>()}, &function);
conversions.add(fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>(), function);
}
static ImplicitConversionsMap get_implicit_conversions()
static DataTypeConversions create_implicit_conversions()
{
ImplicitConversionsMap conversions;
DataTypeConversions conversions;
add_implicit_conversion<float, int32_t>(conversions);
add_implicit_conversion<float, float3>(conversions);
add_implicit_conversion<int32_t, float>(conversions);
add_implicit_conversion<float, bool>(conversions);
add_implicit_conversion<bool, float>(conversions);
add_implicit_conversion<float3, float>(
conversions, "Vector Length", [](float3 a) { return a.length(); });
add_implicit_conversion<int32_t, float3>(
@@ -220,11 +207,26 @@ static ImplicitConversionsMap get_implicit_conversions()
return conversions;
}
static const fn::MultiFunction *try_get_conversion_function(fn::MFDataType from, fn::MFDataType to)
const DataTypeConversions &get_implicit_type_conversions()
{
static const ImplicitConversionsMap conversions = get_implicit_conversions();
const fn::MultiFunction *function = conversions.lookup_default({from, to}, nullptr);
return function;
static const DataTypeConversions conversions = create_implicit_conversions();
return conversions;
}
void DataTypeConversions::convert(const CPPType &from_type,
const CPPType &to_type,
const void *from_value,
void *to_value) const
{
const fn::MultiFunction *fn = this->get_conversion(MFDataType::ForSingle(from_type),
MFDataType::ForSingle(to_type));
BLI_assert(fn != nullptr);
fn::MFContextBuilder context;
fn::MFParamsBuilder params{*fn, 1};
params.add_readonly_single_input(fn::GSpan(from_type, from_value, 1));
params.add_uninitialized_single_output(fn::GMutableSpan(to_type, to_value, 1));
fn->call({0}, params, context);
}
static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderData &common,
@@ -253,7 +255,7 @@ static void insert_links(CommonMFNetworkBuilderData &common)
if (!to_dsocket->is_linked()) {
continue;
}
if (!is_multi_function_data_socket(to_dsocket->bsocket())) {
if (!socket_is_mf_data_socket(*to_dsocket->bsocket()->typeinfo)) {
continue;
}
@@ -269,7 +271,8 @@ static void insert_links(CommonMFNetworkBuilderData &common)
fn::MFDataType from_type = from_socket->data_type();
if (from_type != to_type) {
const fn::MultiFunction *conversion_fn = try_get_conversion_function(from_type, to_type);
const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion(
from_type, to_type);
if (conversion_fn != nullptr) {
fn::MFNode &node = common.network.add_function(*conversion_fn);
common.network.add_link(*from_socket, node.input(0));
@@ -308,7 +311,7 @@ static void insert_unlinked_inputs(CommonMFNetworkBuilderData &common)
Vector<const DInputSocket *> unlinked_data_inputs;
for (const DInputSocket *dsocket : common.tree.input_sockets()) {
if (dsocket->is_available()) {
if (is_multi_function_data_socket(dsocket->bsocket())) {
if (socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) {
if (!dsocket->is_linked()) {
insert_unlinked_input(common, *dsocket);
}
@@ -340,4 +343,150 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
return network_map;
}
/**
* A single node is allowed to expand into multiple nodes before evaluation. Depending on what
* nodes it expands to, it belongs a different type of the ones below.
*/
enum class NodeExpandType {
SingleFunctionNode,
MultipleFunctionNodes,
HasDummyNodes,
};
/**
* Checks how the given node expanded in the multi-function network. If it is only a single
* function node, the corresponding function is returned as well.
*/
static NodeExpandType get_node_expand_type(MFNetworkTreeMap &network_map,
const DNode &dnode,
const fn::MultiFunction **r_single_function)
{
const fn::MFFunctionNode *single_function_node = nullptr;
bool has_multiple_nodes = false;
bool has_dummy_nodes = false;
auto check_mf_node = [&](fn::MFNode &mf_node) {
if (mf_node.is_function()) {
if (single_function_node == nullptr) {
single_function_node = &mf_node.as_function();
}
if (&mf_node != single_function_node) {
has_multiple_nodes = true;
}
}
else {
BLI_assert(mf_node.is_dummy());
has_dummy_nodes = true;
}
};
for (const DInputSocket *dsocket : dnode.inputs()) {
if (dsocket->is_available()) {
for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) {
check_mf_node(mf_input->node());
}
}
}
for (const DOutputSocket *dsocket : dnode.outputs()) {
if (dsocket->is_available()) {
fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket);
check_mf_node(mf_output.node());
}
}
if (has_dummy_nodes) {
return NodeExpandType::HasDummyNodes;
}
if (has_multiple_nodes) {
return NodeExpandType::MultipleFunctionNodes;
}
*r_single_function = &single_function_node->function();
return NodeExpandType::SingleFunctionNode;
}
static const fn::MultiFunction &create_function_for_node_that_expands_into_multiple(
const DNode &dnode,
fn::MFNetwork &network,
MFNetworkTreeMap &network_map,
ResourceCollector &resources)
{
Vector<const fn::MFOutputSocket *> dummy_fn_inputs;
for (const DInputSocket *dsocket : dnode.inputs()) {
if (dsocket->is_available()) {
MFDataType data_type = *socket_mf_type_get(*dsocket->typeinfo());
fn::MFOutputSocket &fn_input = network.add_input(data_type.to_string(), data_type);
for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) {
network.add_link(fn_input, *mf_input);
dummy_fn_inputs.append(&fn_input);
}
}
}
Vector<const fn::MFInputSocket *> dummy_fn_outputs;
for (const DOutputSocket *dsocket : dnode.outputs()) {
if (dsocket->is_available()) {
fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket);
MFDataType data_type = mf_output.data_type();
fn::MFInputSocket &fn_output = network.add_output(data_type.to_string(), data_type);
network.add_link(mf_output, fn_output);
dummy_fn_outputs.append(&fn_output);
}
}
fn::MFNetworkEvaluator &fn_evaluator = resources.construct<fn::MFNetworkEvaluator>(
__func__, std::move(dummy_fn_inputs), std::move(dummy_fn_outputs));
return fn_evaluator;
}
/**
* Returns a single multi-function for every node that supports it. This makes it easier to reuse
* the multi-function implementation of nodes in different contexts.
*/
MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
ResourceCollector &resources)
{
/* Build a network that nodes can insert themselves into. However, the individual nodes are not
* connected. */
fn::MFNetwork &network = resources.construct<fn::MFNetwork>(__func__);
MFNetworkTreeMap network_map{tree, network};
MultiFunctionByNode functions_by_node;
CommonMFNetworkBuilderData common{resources, network, network_map, tree};
for (const DNode *dnode : tree.nodes()) {
const bNodeType *node_type = dnode->typeinfo();
if (node_type->expand_in_mf_network == nullptr) {
/* This node does not have a multi-function implementation. */
continue;
}
NodeMFNetworkBuilder builder{common, *dnode};
node_type->expand_in_mf_network(builder);
const fn::MultiFunction *single_function = nullptr;
const NodeExpandType expand_type = get_node_expand_type(network_map, *dnode, &single_function);
switch (expand_type) {
case NodeExpandType::HasDummyNodes: {
/* Dummy nodes cannot be executed, so skip them. */
break;
}
case NodeExpandType::SingleFunctionNode: {
/* This is the common case. Most nodes just expand to a single function. */
functions_by_node.add_new(dnode, single_function);
break;
}
case NodeExpandType::MultipleFunctionNodes: {
/* If a node expanded into multiple functions, a new function has to be created that
* combines those. */
const fn::MultiFunction &fn = create_function_for_node_that_expands_into_multiple(
*dnode, network, network_map, resources);
functions_by_node.add_new(dnode, &fn);
break;
}
}
}
return functions_by_node;
}
} // namespace blender::nodes

View File

@@ -0,0 +1,76 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "NOD_node_tree_multi_function.hh"
#include "NOD_type_callbacks.hh"
namespace blender::nodes {
const CPPType *socket_cpp_type_get(const bNodeSocketType &stype)
{
if (stype.get_cpp_type != nullptr) {
return stype.get_cpp_type();
}
return nullptr;
}
std::optional<MFDataType> socket_mf_type_get(const bNodeSocketType &stype)
{
const CPPType *cpp_type = socket_cpp_type_get(stype);
if (cpp_type != nullptr) {
return MFDataType::ForSingle(*cpp_type);
}
return {};
}
bool socket_is_mf_data_socket(const bNodeSocketType &stype)
{
if (!socket_mf_type_get(stype).has_value()) {
return false;
}
if (stype.expand_in_mf_network == nullptr && stype.get_cpp_value == nullptr) {
return false;
}
return true;
}
bool socket_cpp_value_get(const bNodeSocket &socket, void *r_value)
{
if (socket.typeinfo->get_cpp_value != nullptr) {
socket.typeinfo->get_cpp_value(socket, r_value);
return true;
}
return false;
}
void socket_expand_in_mf_network(SocketMFNetworkBuilder &builder)
{
bNodeSocket &socket = builder.bsocket();
if (socket.typeinfo->expand_in_mf_network != nullptr) {
socket.typeinfo->expand_in_mf_network(builder);
}
else if (socket.typeinfo->get_cpp_value != nullptr) {
const CPPType &type = *socket_cpp_type_get(*socket.typeinfo);
void *buffer = builder.resources().linear_allocator().allocate(type.size(), type.alignment());
socket.typeinfo->get_cpp_value(socket, buffer);
builder.set_constant_value(type, buffer);
}
else {
BLI_assert(false);
}
}
} // namespace blender::nodes

View File

@@ -34,7 +34,7 @@ bool sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
static bool sh_fn_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
{
return STREQ(ntree->idname, "ShaderNodeTree") || STREQ(ntree->idname, "SimulationNodeTree");
return STREQ(ntree->idname, "ShaderNodeTree") || STREQ(ntree->idname, "GeometryNodeTree");
}
void sh_node_type_base(