Compare commits

...

10 Commits

Author SHA1 Message Date
c54bdc7fb6 fixed typo in rna 2021-08-14 00:01:13 +02:00
a28e518917 Changes based on review by Hans Goudey (HooglyBoogly) 2021-08-13 23:57:13 +02:00
a7dc3d1e90 Merge remote-tracking branch 'origin/soc-2021-porting-modifiers-to-nodes-extrude' into soc-2021-porting-modifiers-to-nodes-extrude 2021-08-06 07:53:56 +02:00
6fd836f53b Merged Master 2021-08-06 07:48:40 +02:00
991f6b15f3 Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-extrude
# Conflicts:
#	source/blender/blenkernel/BKE_node.h
2021-08-05 23:50:08 +02:00
aef45a4ef2 Merge remote-tracking branch 'origin/soc-2021-porting-modifiers-to-nodes-extrude' into soc-2021-porting-modifiers-to-nodes-extrude
# Conflicts:
#	source/blender/bmesh/intern/bmesh_mesh.c
#	source/blender/bmesh/intern/bmesh_mesh.h
#	source/blender/nodes/NOD_static_types.h
#	source/blender/nodes/geometry/nodes/node_geo_extrude.cc
2021-08-05 23:48:58 +02:00
504e3c563f added side selection. 2021-08-05 23:47:44 +02:00
b5573bfbf4 Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-extrude 2021-08-03 21:02:56 +02:00
ba9561ab0d Geometry Nodes: Extrude
Differential Revision: https://developer.blender.org/D12108
2021-08-02 19:04:04 +02:00
c659af0c13 Geometry Nodes: Extrude 2021-08-02 19:02:38 +02:00
12 changed files with 414 additions and 12 deletions

View File

@@ -552,6 +552,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeEdgeSplit"),
NodeItem("GeometryNodeSubdivisionSurface"),
NodeItem("GeometryNodeMeshSubdivide"),
NodeItem("GeometryNodeMeshInset"),
]),
GeometryNodeCategory("GEO_PRIMITIVES_MESH", "Mesh Primitives", items=[
NodeItem("GeometryNodeMeshCircle"),

View File

@@ -1476,6 +1476,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_CURVE_TRIM 1071
#define GEO_NODE_CURVE_SET_HANDLES 1072
#define GEO_NODE_CURVE_SPLINE_TYPE 1073
#define GEO_NODE_MESH_INSET 1074
/** \} */

View File

@@ -5156,6 +5156,7 @@ static void registerGeometryNodes()
register_node_type_geo_curve_trim();
register_node_type_geo_delete_geometry();
register_node_type_geo_edge_split();
register_node_type_geo_mesh_inset();
register_node_type_geo_input_material();
register_node_type_geo_is_viewport();
register_node_type_geo_join_geometry();

View File

@@ -1446,4 +1446,120 @@ void BM_mesh_vert_coords_apply_with_mat4(BMesh *bm,
}
}
/**
* Use to select bmesh vertex data based on an array of bool.
*/
void BM_select_vertices(BMesh *bm, const bool *mask)
{
BMIter iter;
BMVert *v;
int i;
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
BM_elem_flag_set(v, BM_ELEM_SELECT, mask[i]);
}
}
/**
* Use to select bmesh edge data based on an array of bool.
*/
void BM_select_edges(BMesh *bm, const bool *mask)
{
BMIter iter;
BMEdge *e;
int i;
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
BM_elem_flag_set(e, BM_ELEM_SELECT, mask[i]);
}
}
/**
* Use to select bmesh face data based on an array of bool.
*/
void BM_select_faces(BMesh *bm, const bool *mask)
{
BMIter iter;
BMFace *f;
int i = 0;
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
BM_elem_flag_set(f, BM_ELEM_SELECT, mask[i]);
}
}
void BM_get_selected_faces(BMesh *bm, bool *selection)
{
BMIter iter;
BMFace *f;
int i = 0;
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
selection[i] = BM_elem_flag_test(f, BM_ELEM_SELECT);
}
}
void BM_get_tagged_faces(BMesh *bm, bool *selection)
{
BMIter iter;
BMFace *f;
int i;
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
selection[i] = BM_elem_flag_test(f, BM_ELEM_TAG);
}
}
void BM_tag_new_faces(BMesh *bm, BMOperator *b_mesh_operator)
{
BMIter iter;
BMFace *f;
BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
BMO_ITER (f, &iter, b_mesh_operator->slots_out, "faces.out", BM_FACE) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
}
}
void BM_tag_vertices(BMesh *bm, const bool *mask)
{
BMIter iter;
BMVert *v;
int i;
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
BM_elem_flag_set(v, BM_ELEM_TAG, mask[i]);
}
}
/**
* Use to temporary tag bmesh edge data based on an array of bool.
*/
void BM_tag_edges(BMesh *bm, const bool *mask)
{
BMIter iter;
BMEdge *e;
int i;
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
BM_elem_flag_set(e, BM_ELEM_TAG, mask[i]);
}
}
/**
* Use to temporary tag bmesh face data based on an array of bool.
*/
void BM_tag_faces(BMesh *bm, const bool *mask)
{
BMIter iter;
BMFace *f;
int i;
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
BM_elem_flag_set(f, BM_ELEM_TAG, mask[i]);
}
}
void BM_untag_faces_by_tag(BMesh *bm, int tag)
{
BMIter iter;
BMFace *f;
int i;
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
if (BM_elem_flag_test(f, tag)) {
BM_elem_flag_disable(f, BM_ELEM_TAG);
}
}
}
/** \} */

View File

@@ -134,3 +134,14 @@ void BM_mesh_vert_coords_apply(BMesh *bm, const float (*vert_coords)[3]);
void BM_mesh_vert_coords_apply_with_mat4(BMesh *bm,
const float (*vert_coords)[3],
const float mat[4][4]);
void BM_select_vertices(BMesh *bm, const bool *mask);
void BM_select_edges(BMesh *bm, const bool *mask);
void BM_select_faces(BMesh *bm, const bool *mask);
void BM_get_selected_faces(BMesh *bm, bool *selection);
void BM_tag_vertices(BMesh *bm, const bool *mask);
void BM_tag_edges(BMesh *bm, const bool *mask);
void BM_tag_faces(BMesh *bm, const bool *mask);
void BM_untag_faces_by_tag(BMesh *bm, int tag);
void BM_get_tagged_faces(BMesh *bm, bool *selection);
void BM_tag_new_faces(BMesh *bm, BMOperator *b_mesh_operator);

View File

@@ -1898,6 +1898,9 @@ static BMOpDefine bmo_inset_individual_def = {
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */
{"thickness", BMO_OP_SLOT_FLT}, /* thickness */
{"depth", BMO_OP_SLOT_FLT}, /* depth */
{"thickness_array", BMO_OP_SLOT_PTR}, /* thickness */
{"depth_array", BMO_OP_SLOT_PTR}, /* depth */
{"use_attributes", BMO_OP_SLOT_BOOL}, /* Use spans for thickness and depth */
{"use_even_offset", BMO_OP_SLOT_BOOL}, /* scale the offset to give more even thickness */
{"use_interpolate", BMO_OP_SLOT_BOOL}, /* blend face data across the inset */
{"use_relative_offset", BMO_OP_SLOT_BOOL}, /* scale the offset by surrounding geometry */
@@ -1929,6 +1932,9 @@ static BMOpDefine bmo_inset_region_def = {
{"use_edge_rail", BMO_OP_SLOT_BOOL}, /* inset the region along existing edges */
{"thickness", BMO_OP_SLOT_FLT}, /* thickness */
{"depth", BMO_OP_SLOT_FLT}, /* depth */
{"thickness_array", BMO_OP_SLOT_PTR}, /* thickness */
{"depth_array", BMO_OP_SLOT_PTR}, /* depth */
{"use_attributes", BMO_OP_SLOT_BOOL}, /* Use spans for thickness and depth */
{"use_outset", BMO_OP_SLOT_BOOL}, /* outset rather than inset */
{{'\0'}},
},

View File

@@ -419,6 +419,9 @@ void bmo_inset_individual_exec(BMesh *bm, BMOperator *op)
BMOIter oiter;
MemArena *interp_arena = NULL;
const bool use_attributes = BMO_slot_bool_get(op->slots_in, "use_attributes");
const float *thickness_array = BMO_slot_ptr_get(op->slots_in, "thickness_array");
const float *depth_array = BMO_slot_ptr_get(op->slots_in, "depth_array");
const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
const float depth = BMO_slot_float_get(op->slots_in, "depth");
const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
@@ -433,19 +436,37 @@ void bmo_inset_individual_exec(BMesh *bm, BMOperator *op)
if (use_interpolate) {
interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
}
int i = 0;
if (use_attributes) {
BMO_ITER_INDEX (f, &oiter, op->slots_in, "faces", BM_FACE, i) {
bmo_face_inset_individual(bm,
f,
interp_arena,
thickness_array[i],
depth_array[i],
use_even_offset,
use_relative_offset,
use_interpolate);
BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
bmo_face_inset_individual(bm,
f,
interp_arena,
thickness,
depth,
use_even_offset,
use_relative_offset,
use_interpolate);
if (use_interpolate) {
BLI_memarena_clear(interp_arena);
}
}
}
else {
BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
bmo_face_inset_individual(bm,
f,
interp_arena,
thickness,
depth,
use_even_offset,
use_relative_offset,
use_interpolate);
if (use_interpolate) {
BLI_memarena_clear(interp_arena);
if (use_interpolate) {
BLI_memarena_clear(interp_arena);
}
}
}
@@ -677,12 +698,16 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
const bool use_outset = BMO_slot_bool_get(op->slots_in, "use_outset");
const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary") &&
(use_outset == false);
const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
const bool use_even_boundary = use_even_offset; /* could make own option */
const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
const bool use_edge_rail = BMO_slot_bool_get(op->slots_in, "use_edge_rail");
const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
const bool use_attributes = BMO_slot_bool_get(op->slots_in, "use_attributes");
const float *thickness_array = BMO_slot_ptr_get(op->slots_in, "thickness_array");
const float *depth_array = BMO_slot_ptr_get(op->slots_in, "depth_array");
const float depth = BMO_slot_float_get(op->slots_in, "depth");
#ifdef USE_LOOP_CUSTOMDATA_MERGE
const bool has_math_ldata = (use_interpolate && CustomData_has_math(&bm->ldata));
@@ -1096,7 +1121,12 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
}
/* apply the offset */
madd_v3_v3fl(v_split->co, tvec, thickness);
if (use_attributes) {
madd_v3_v3fl(v_split->co, tvec, thickness_array[v_split->head.index]);
}
else {
madd_v3_v3fl(v_split->co, tvec, thickness);
}
}
/* this saves expensive/slow glue check for common cases */

View File

@@ -10160,6 +10160,24 @@ static void def_geo_attribute_transfer(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_geo_mesh_inset(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "distance_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
RNA_def_property_ui_text(
prop, "Distance", "Changes the Distance input between Float and Attribute");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "inset_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom2");
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
RNA_def_property_ui_text(prop, "Inset", "Changes the Inset input between Float and Attribute");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_input_material(StructRNA *srna)
{
PropertyRNA *prop;

View File

@@ -183,6 +183,7 @@ set(SRC
geometry/nodes/node_geo_curve_trim.cc
geometry/nodes/node_geo_delete_geometry.cc
geometry/nodes/node_geo_edge_split.cc
geometry/nodes/node_geo_mesh_inset.cc
geometry/nodes/node_geo_input_material.cc
geometry/nodes/node_geo_is_viewport.cc
geometry/nodes/node_geo_join_geometry.cc

View File

@@ -70,6 +70,7 @@ void register_node_type_geo_curve_to_points(void);
void register_node_type_geo_curve_trim(void);
void register_node_type_geo_delete_geometry(void);
void register_node_type_geo_edge_split(void);
void register_node_type_geo_mesh_inset(void);
void register_node_type_geo_input_material(void);
void register_node_type_geo_is_viewport(void);
void register_node_type_geo_join_geometry(void);

View File

@@ -310,6 +310,7 @@ DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_
DefNode(GeometryNode, GEO_NODE_CURVE_TRIM, def_geo_curve_trim, "CURVE_TRIM", CurveTrim, "Curve Trim", "")
DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, 0, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "")
DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "")
DefNode(GeometryNode, GEO_NODE_MESH_INSET, def_geo_mesh_inset, "MESH_INSET", MeshInset, "Mesh Inset", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "")
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")

View File

@@ -0,0 +1,215 @@
/*
* 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 "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "bmesh.h"
#include "bmesh_tools.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_mesh_inset_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_STRING, N_("Distance")},
{SOCK_FLOAT, N_("Distance"), 0.0f, 0, 0, 0, FLT_MIN, FLT_MAX, PROP_DISTANCE},
{SOCK_STRING, N_("mesh_inset")},
{SOCK_FLOAT, N_("mesh_inset"), 0.0f, 0, 0, 0, FLT_MIN, FLT_MAX, PROP_DISTANCE},
{SOCK_BOOLEAN, N_("Individual")},
{SOCK_STRING, N_("Selection")},
{SOCK_STRING, N_("Top Face")},
{SOCK_STRING, N_("Side Face")},
{-1, ""},
};
static bNodeSocketTemplate geo_node_mesh_inset_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
static void geo_node_mesh_inset_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "distance_mode", 0, nullptr, ICON_NONE);
uiItemR(layout, ptr, "inset_mode", 0, nullptr, ICON_NONE);
}
static void geo_node_mesh_inset_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
node->custom2 = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
}
static void geo_node_mesh_inset_update(bNodeTree *UNUSED(ntree), bNode *node)
{
blender::nodes::update_attribute_input_socket_availabilities(
*node, "Distance", (GeometryNodeAttributeInputMode)node->custom1, true);
blender::nodes::update_attribute_input_socket_availabilities(
*node, "mesh_inset", (GeometryNodeAttributeInputMode)node->custom2, true);
}
using blender::Span;
static Mesh *mesh_inset_mesh(const Mesh *mesh,
const Span<bool> selection,
const Span<float> distance,
const Span<float> mesh_inset,
const bool mesh_inset_individual_faces,
std::string selection_top_faces_out_attribute_name,
std::string selection_side_faces_out_attribute_name)
{
const BMeshCreateParams bmesh_create_params = {true};
const BMeshFromMeshParams bmesh_from_mesh_params = {
true, 0, 0, 0, {CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX}};
BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params);
BM_select_faces(bm, selection.data());
BMOperator op;
if (mesh_inset_individual_faces) {
BMO_op_initf(bm,
&op,
0,
"inset_individual faces=%hf use_even_offset=%b thickness=%f depth=%f "
"thickness_array=%p depth_array=%p use_attributes=%b",
BM_ELEM_SELECT,
true,
mesh_inset[0],
distance[0],
mesh_inset.data(),
distance.data(),
true);
}
else {
BMO_op_initf(bm,
&op,
0,
"inset_region faces=%hf use_boundary=%b use_even_offset=%b thickness=%f depth=%f "
"thickness_array=%p depth_array=%p use_attributes=%b",
BM_ELEM_SELECT,
true,
true,
mesh_inset[0],
distance[0],
mesh_inset.data(),
distance.data(),
true);
}
BM_tag_new_faces(bm, &op);
BM_untag_faces_by_tag(bm, BM_ELEM_SELECT);
BMO_op_exec(bm, &op);
BMO_op_finish(bm, &op);
CustomData_MeshMasks cd_mask_extra = {CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX};
Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cd_mask_extra, mesh);
MeshComponent component;
component.replace(result, GeometryOwnershipType::Editable);
if (!selection_top_faces_out_attribute_name.empty()) {
blender::bke::OutputAttribute_Typed<bool> attribute =
component.attribute_try_get_for_output_only<bool>(selection_top_faces_out_attribute_name,
ATTR_DOMAIN_FACE);
BM_get_selected_faces(bm, attribute.as_span().data());
attribute.save();
}
if (!selection_side_faces_out_attribute_name.empty()) {
blender::bke::OutputAttribute_Typed<bool> attribute =
component.attribute_try_get_for_output_only<bool>(selection_side_faces_out_attribute_name,
ATTR_DOMAIN_FACE);
BM_get_tagged_faces(bm, attribute.as_span().data());
attribute.save();
}
BM_mesh_free(bm);
BKE_mesh_normals_tag_dirty(result);
return result;
}
namespace blender::nodes {
static void geo_node_mesh_inset_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
geometry_set = geometry_set_realize_instances(geometry_set);
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
if (mesh_component.has_mesh()) {
const bool default_selection = true;
GVArray_Typed<bool> selection_attribute = params.get_input_attribute<bool>(
"Selection", mesh_component, ATTR_DOMAIN_FACE, default_selection);
VArray_Span<bool> selection{selection_attribute};
const Mesh *input_mesh = mesh_component.get_for_read();
AttributeDomain attribute_domain = ATTR_DOMAIN_POINT;
const bool mesh_inset_individual_faces = params.extract_input<bool>("Individual");
if (mesh_inset_individual_faces) {
attribute_domain = ATTR_DOMAIN_FACE;
}
const float default_distance = 0;
GVArray_Typed<float> distance_attribute = params.get_input_attribute<float>(
"Distance", mesh_component, attribute_domain, default_distance);
VArray_Span<float> distance{distance_attribute};
const float default_mesh_inset = 0;
GVArray_Typed<float> mesh_inset_attribute = params.get_input_attribute<float>(
"mesh_inset", mesh_component, attribute_domain, default_mesh_inset);
VArray_Span<float> mesh_inset{mesh_inset_attribute};
std::string selection_top_faces_out_attribute_name = params.get_input<std::string>("Top Face");
std::string selection_side_faces_out_attribute_name = params.get_input<std::string>(
"Side Face");
Mesh *result = mesh_inset_mesh(input_mesh,
selection,
distance,
mesh_inset,
mesh_inset_individual_faces,
selection_top_faces_out_attribute_name,
selection_side_faces_out_attribute_name);
geometry_set.replace_mesh(result);
}
params.set_output("Geometry", std::move(geometry_set));
}
} // namespace blender::nodes
void register_node_type_geo_mesh_inset()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_INSET, "MeshInset", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(&ntype, geo_node_mesh_inset_in, geo_node_mesh_inset_out);
node_type_init(&ntype, geo_node_mesh_inset_init);
node_type_update(&ntype, geo_node_mesh_inset_update);
ntype.draw_buttons = geo_node_mesh_inset_layout;
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_inset_exec;
nodeRegisterType(&ntype);
}