Simulations: Embed simulation node tree in simulation data block
This adds an embedded node tree to the simulation data block dna. The UI in the `Simulation Editor` has been updated to show a list of simulation data blocks, instead of individual node trees. The new `SpaceNodeEditor.simulation` property wraps the existing `SpaceNodeEditor.id` property. It allows scripts to get and set the simulation data block that is being edited. Reviewers: brecht, mont29 Differential Revision: https://developer.blender.org/D7301
This commit is contained in:
parent
8d53e59e32
commit
2b2d3c14fe
Notes:
blender-bot
2023-02-14 06:45:14 +01:00
Referenced by issue #76277, Enabling Viewer Border in Compositor Crashes Blender
|
@ -42,6 +42,7 @@ _modules = [
|
|||
"rigidbody",
|
||||
"screen_play_rendered_anim",
|
||||
"sequencer",
|
||||
"simulation",
|
||||
"userpref",
|
||||
"uvcalc_follow_active",
|
||||
"uvcalc_lightmap",
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
|
||||
class NewSimulation(bpy.types.Operator):
|
||||
"""Create a new simulation data block and edit it in the opened simulation editor"""
|
||||
|
||||
bl_idname = "simulation.new"
|
||||
bl_label = "New Simulation"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.area.type == 'NODE_EDITOR' and context.space_data.tree_type == 'SimulationNodeTree'
|
||||
|
||||
def execute(self, context):
|
||||
simulation = bpy.data.simulations.new("Simulation")
|
||||
context.space_data.simulation = simulation
|
||||
return {'FINISHED'}
|
||||
|
||||
classes = (
|
||||
NewSimulation,
|
||||
)
|
|
@ -151,6 +151,14 @@ 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="")
|
||||
|
||||
else:
|
||||
# Custom node tree is edited as independent ID block
|
||||
NODE_MT_editor_menus.draw_collapsible(context, layout)
|
||||
|
|
|
@ -58,6 +58,13 @@ class TextureNodeCategory(SortedNodeCategory):
|
|||
context.space_data.tree_type == 'TextureNodeTree')
|
||||
|
||||
|
||||
class SimulationNodeCategory(SortedNodeCategory):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.space_data.type == 'NODE_EDITOR' and
|
||||
context.space_data.tree_type == 'SimulationNodeTree')
|
||||
|
||||
|
||||
# menu entry for node group tools
|
||||
def group_tools_draw(self, layout, context):
|
||||
layout.operator("node.group_make")
|
||||
|
@ -70,6 +77,7 @@ node_tree_group_type = {
|
|||
'CompositorNodeTree': 'CompositorNodeGroup',
|
||||
'ShaderNodeTree': 'ShaderNodeGroup',
|
||||
'TextureNodeTree': 'TextureNodeGroup',
|
||||
'SimulationNodeTree': 'SimulationNodeGroup',
|
||||
}
|
||||
|
||||
|
||||
|
@ -467,17 +475,28 @@ texture_node_categories = [
|
|||
]),
|
||||
]
|
||||
|
||||
simulation_node_categories = [
|
||||
# Simulation Nodes
|
||||
SimulationNodeCategory("SIM_GROUP", "Group", items=node_group_items),
|
||||
SimulationNodeCategory("SIM_LAYOUT", "Layout", items=[
|
||||
NodeItem("NodeFrame"),
|
||||
NodeItem("NodeReroute"),
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -852,6 +852,7 @@ struct NodeTreeIterStore {
|
|||
struct Light *light;
|
||||
struct World *world;
|
||||
struct FreestyleLineStyle *linestyle;
|
||||
struct Simulation *simulation;
|
||||
};
|
||||
|
||||
void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain);
|
||||
|
|
|
@ -1286,6 +1286,15 @@ static void library_foreach_ID_link(Main *bmain,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ID_SIM: {
|
||||
Simulation *simulation = (Simulation *)id;
|
||||
if (simulation->nodetree) {
|
||||
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
|
||||
library_foreach_ID_as_subdata_link(
|
||||
(ID **)&simulation->nodetree, callback, user_data, flag, &data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Nothing needed for those... */
|
||||
case ID_IM:
|
||||
|
@ -1295,7 +1304,6 @@ static void library_foreach_ID_link(Main *bmain,
|
|||
case ID_PAL:
|
||||
case ID_PC:
|
||||
case ID_CF:
|
||||
case ID_SIM:
|
||||
break;
|
||||
|
||||
/* Deprecated. */
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "DNA_material_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_simulation_types.h"
|
||||
#include "DNA_texture_types.h"
|
||||
#include "DNA_world_types.h"
|
||||
|
||||
|
@ -2267,6 +2268,8 @@ bNodeTree **BKE_ntree_ptr_from_id(ID *id)
|
|||
return &((Scene *)id)->nodetree;
|
||||
case ID_LS:
|
||||
return &((FreestyleLineStyle *)id)->nodetree;
|
||||
case ID_SIM:
|
||||
return &((Simulation *)id)->nodetree;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -4200,6 +4203,7 @@ void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *b
|
|||
ntreeiter->light = bmain->lights.first;
|
||||
ntreeiter->world = bmain->worlds.first;
|
||||
ntreeiter->linestyle = bmain->linestyles.first;
|
||||
ntreeiter->simulation = bmain->simulations.first;
|
||||
}
|
||||
bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
|
||||
bNodeTree **r_nodetree,
|
||||
|
@ -4240,6 +4244,11 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
|
|||
*r_id = (ID *)ntreeiter->linestyle;
|
||||
ntreeiter->linestyle = ntreeiter->linestyle->id.next;
|
||||
}
|
||||
else if (ntreeiter->simulation) {
|
||||
*r_nodetree = ntreeiter->simulation->nodetree;
|
||||
*r_id = (ID *)ntreeiter->simulation;
|
||||
ntreeiter->simulation = ntreeiter->simulation->id.next;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -37,8 +37,11 @@
|
|||
#include "BKE_lib_query.h"
|
||||
#include "BKE_lib_remap.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_simulation.h"
|
||||
|
||||
#include "NOD_simulation.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
static void simulation_init_data(ID *id)
|
||||
|
@ -47,13 +50,38 @@ static void simulation_init_data(ID *id)
|
|||
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(simulation, id));
|
||||
|
||||
MEMCPY_STRUCT_AFTER(simulation, DNA_struct_default_get(Simulation), id);
|
||||
|
||||
bNodeTree *ntree = ntreeAddTree(nullptr, "Simulation Nodetree", ntreeType_Simulation->idname);
|
||||
simulation->nodetree = ntree;
|
||||
}
|
||||
|
||||
static void simulation_copy_data(Main *UNUSED(bmain),
|
||||
ID *UNUSED(id_dst),
|
||||
const ID *UNUSED(id_src),
|
||||
const int UNUSED(flag))
|
||||
static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
|
||||
{
|
||||
Simulation *simulation_dst = (Simulation *)id_dst;
|
||||
Simulation *simulation_src = (Simulation *)id_src;
|
||||
|
||||
/* We always need allocation of our private ID data. */
|
||||
const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
|
||||
|
||||
if (simulation_src->nodetree) {
|
||||
BKE_id_copy_ex(bmain,
|
||||
(ID *)simulation_src->nodetree,
|
||||
(ID **)&simulation_dst->nodetree,
|
||||
flag_private_id_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void simulation_free_data(ID *id)
|
||||
{
|
||||
Simulation *simulation = (Simulation *)id;
|
||||
|
||||
BKE_animdata_free(&simulation->id, false);
|
||||
|
||||
if (simulation->nodetree) {
|
||||
ntreeFreeNestedTree(simulation->nodetree);
|
||||
MEM_freeN(simulation->nodetree);
|
||||
simulation->nodetree = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void *BKE_simulation_add(Main *bmain, const char *name)
|
||||
|
@ -77,6 +105,6 @@ IDTypeInfo IDType_ID_SIM = {
|
|||
|
||||
/* init_data */ simulation_init_data,
|
||||
/* copy_data */ simulation_copy_data,
|
||||
/* free_data */ nullptr,
|
||||
/* free_data */ simulation_free_data,
|
||||
/* make_local */ nullptr,
|
||||
};
|
||||
|
|
|
@ -3858,6 +3858,12 @@ static void write_simulation(WriteData *wd, Simulation *simulation)
|
|||
if (simulation->adt) {
|
||||
write_animdata(wd, simulation->adt);
|
||||
}
|
||||
|
||||
/* nodetree is integral part of simulation, no libdata */
|
||||
if (simulation->nodetree) {
|
||||
writestruct(wd, DATA, bNodeTree, 1, simulation->nodetree);
|
||||
write_nodetree_nolib(wd, simulation->nodetree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ typedef struct Simulation {
|
|||
ID id;
|
||||
struct AnimData *adt; /* animation data (must be immediately after id) */
|
||||
|
||||
struct bNodeTree *nodetree;
|
||||
|
||||
int flag;
|
||||
int _pad1[1];
|
||||
} Simulation;
|
||||
|
|
|
@ -34,11 +34,16 @@
|
|||
static void rna_def_simulation(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "Simulation", "ID");
|
||||
RNA_def_struct_ui_text(srna, "Simulation", "Simulation data-block");
|
||||
RNA_def_struct_ui_icon(srna, ICON_PHYSICS); /* TODO: Use correct icon. */
|
||||
|
||||
prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "nodetree");
|
||||
RNA_def_property_ui_text(prop, "Node Tree", "Node tree defining the simulation");
|
||||
|
||||
/* common */
|
||||
rna_def_animdata_common(srna);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#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"
|
||||
|
@ -2166,6 +2167,40 @@ static void rna_SpaceNodeEditor_node_tree_update(const bContext *C, PointerRNA *
|
|||
ED_node_tree_update(C);
|
||||
}
|
||||
|
||||
# ifdef WITH_NEW_SIMULATION_TYPE
|
||||
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;
|
||||
|
@ -6215,6 +6250,19 @@ 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_NEW_SIMULATION_TYPE
|
||||
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");
|
||||
|
|
Loading…
Reference in New Issue