From c69cc5c96f1a8903074239850dd06dddf03045c8 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sun, 12 Oct 2003 18:52:57 +0000 Subject: [PATCH] egg loader reads nurbs surfaces and curves into SheetNodes and RopeNodes --- panda/src/egg/eggNurbsCurve.h | 4 +- panda/src/egg/eggNurbsSurface.h | 4 +- panda/src/egg2pg/characterMaker.cxx | 13 +- panda/src/egg2pg/config_egg2pg.cxx | 14 +- panda/src/egg2pg/config_egg2pg.h | 1 + panda/src/egg2pg/eggLoader.cxx | 542 +++++++++++++----- panda/src/egg2pg/eggLoader.h | 9 +- panda/src/parametrics/Sources.pp | 7 +- panda/src/parametrics/config_parametrics.cxx | 3 + panda/src/parametrics/nurbsCurveEvaluator.I | 18 +- panda/src/parametrics/nurbsCurveEvaluator.cxx | 2 +- panda/src/parametrics/nurbsCurveEvaluator.h | 2 + panda/src/parametrics/nurbsSurfaceEvaluator.I | 34 +- .../src/parametrics/nurbsSurfaceEvaluator.cxx | 4 +- panda/src/parametrics/nurbsSurfaceEvaluator.h | 3 + panda/src/parametrics/nurbsSurfaceResult.cxx | 154 ++--- .../parametrics/parametrics_composite2.cxx | 1 + panda/src/parametrics/ropeNode.I | 58 +- panda/src/parametrics/ropeNode.cxx | 47 +- panda/src/parametrics/ropeNode.h | 10 +- panda/src/parametrics/sheetNode.I | 150 +++++ panda/src/parametrics/sheetNode.cxx | 383 +++++++++++++ panda/src/parametrics/sheetNode.h | 125 ++++ 23 files changed, 1323 insertions(+), 265 deletions(-) create mode 100644 panda/src/parametrics/sheetNode.I create mode 100644 panda/src/parametrics/sheetNode.cxx create mode 100644 panda/src/parametrics/sheetNode.h diff --git a/panda/src/egg/eggNurbsCurve.h b/panda/src/egg/eggNurbsCurve.h index b00af4e10d..102a606ec6 100644 --- a/panda/src/egg/eggNurbsCurve.h +++ b/panda/src/egg/eggNurbsCurve.h @@ -66,9 +66,9 @@ public: return _type_handle; } static void init_type() { - EggPrimitive::init_type(); + EggCurve::init_type(); register_type(_type_handle, "EggNurbsCurve", - EggPrimitive::get_class_type()); + EggCurve::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/egg/eggNurbsSurface.h b/panda/src/egg/eggNurbsSurface.h index 5d1b6c4285..a6aec745dc 100644 --- a/panda/src/egg/eggNurbsSurface.h +++ b/panda/src/egg/eggNurbsSurface.h @@ -100,9 +100,9 @@ public: return _type_handle; } static void init_type() { - EggPrimitive::init_type(); + EggSurface::init_type(); register_type(_type_handle, "EggNurbsSurface", - EggPrimitive::get_class_type()); + EggSurface::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/egg2pg/characterMaker.cxx b/panda/src/egg2pg/characterMaker.cxx index b6943be7ba..40cceed1af 100644 --- a/panda/src/egg2pg/characterMaker.cxx +++ b/panda/src/egg2pg/characterMaker.cxx @@ -29,6 +29,8 @@ #include "characterSlider.h" #include "character.h" #include "transformState.h" +#include "eggSurface.h" +#include "eggCurve.h" //////////////////////////////////////////////////////////////////// // Function: CharacterMaker::Construtor @@ -239,7 +241,16 @@ make_geometry(EggNode *egg_node) { if (!egg_primitive->empty()) { EggGroupNode *prim_home = determine_primitive_home(egg_primitive); - if (prim_home == NULL) { + if (prim_home == (EggGroupNode *)NULL && + (egg_primitive->is_of_type(EggSurface::get_class_type()) || + egg_primitive->is_of_type(EggCurve::get_class_type()))) { + // If the primitive would be dynamic but is a parametric + // primitive, we can't animate it anyway, so just put the + // whole thing under the primitive's parent node. + prim_home = egg_primitive->get_parent(); + } + + if (prim_home == (EggGroupNode *)NULL) { // This is a totally dynamic primitive that lives under the // character's node. make_dynamic_primitive(egg_primitive, _egg_root); diff --git a/panda/src/egg2pg/config_egg2pg.cxx b/panda/src/egg2pg/config_egg2pg.cxx index 482791a2a7..8dfa38b4c0 100644 --- a/panda/src/egg2pg/config_egg2pg.cxx +++ b/panda/src/egg2pg/config_egg2pg.cxx @@ -53,10 +53,16 @@ bool egg_flatten_siblings = config_egg2pg.GetBool("egg-flatten-siblings", false) bool egg_show_collision_solids = config_egg2pg.GetBool("egg-show-collision-solids", false); // When this is true, a entry appearing in an egg file -// will load a ClassicNurbsCurve object instead of the default, a -// NurbsCurve object. This only makes a difference when the NURBS++ -// library is available, in which case the default, NurbsCurve, is -// actually a NurbsPPCurve object. +// will load as a NurbsCurve or ClassicNurbsCurve object (see below). +// When this is false, it will load a RopeNode instead, which uses the +// new NurbsCurveEvaluator interface. +bool egg_load_old_curves = config_egg2pg.GetBool("egg-load-old-curves", true); + +// When this is true (and the above is also true), a +// entry appearing in an egg file will load a ClassicNurbsCurve object +// instead of the default, a NurbsCurve object. This only makes a +// difference when the NURBS++ library is available, in which case the +// default, NurbsCurve, is actually a NurbsPPCurve object. bool egg_load_classic_nurbs_curves = config_egg2pg.GetBool("egg-load-classic-nurbs-curves", false); // When this is true, certain kinds of recoverable errors (not syntax diff --git a/panda/src/egg2pg/config_egg2pg.h b/panda/src/egg2pg/config_egg2pg.h index adbcfd4727..419f0596bd 100644 --- a/panda/src/egg2pg/config_egg2pg.h +++ b/panda/src/egg2pg/config_egg2pg.h @@ -52,6 +52,7 @@ extern EXPCL_PANDAEGG bool egg_ignore_decals; extern EXPCL_PANDAEGG bool egg_flatten; extern EXPCL_PANDAEGG bool egg_flatten_siblings; extern EXPCL_PANDAEGG bool egg_show_collision_solids; +extern EXPCL_PANDAEGG bool egg_load_old_curves; extern EXPCL_PANDAEGG bool egg_load_classic_nurbs_curves; extern EXPCL_PANDAEGG bool egg_accept_errors; extern EXPCL_PANDAEGG EggRenderMode::AlphaMode egg_alpha_mode; diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 6a27240718..7c1836312f 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -34,6 +34,8 @@ #include "depthTestAttrib.h" #include "depthWriteAttrib.h" #include "materialAttrib.h" +#include "texMatrixAttrib.h" +#include "colorAttrib.h" #include "materialPool.h" #include "geomNode.h" #include "sequenceNode.h" @@ -46,6 +48,7 @@ #include "eggPoint.h" #include "eggTextureCollection.h" #include "eggNurbsCurve.h" +#include "eggNurbsSurface.h" #include "eggGroupNode.h" #include "eggGroup.h" #include "eggPolygon.h" @@ -67,6 +70,10 @@ #include "nurbsCurve.h" #include "classicNurbsCurve.h" #include "nurbsCurveInterface.h" +#include "nurbsCurveEvaluator.h" +#include "nurbsSurfaceEvaluator.h" +#include "ropeNode.h" +#include "sheetNode.h" #include "look_at.h" #include @@ -238,66 +245,75 @@ make_nonindexed_primitive(EggPrimitive *egg_prim, PandaNode *parent, mat = egg_prim->get_vertex_to_node(); } - BuilderPrim bprim; - bprim.set_type(BPT_poly); - if (egg_prim->is_of_type(EggPoint::get_class_type())) { - bprim.set_type(BPT_point); - } + if (egg_prim->is_of_type(EggNurbsCurve::get_class_type())) { + make_nurbs_curve(DCAST(EggNurbsCurve, egg_prim), parent, mat); - if (egg_prim->has_normal()) { - Normald norm = egg_prim->get_normal() * mat; - norm.normalize(); - bprim.set_normal(LCAST(float, norm)); - } - if (egg_prim->has_color() && !egg_false_color) { - bprim.set_color(egg_prim->get_color()); - } + } else if (egg_prim->is_of_type(EggNurbsSurface::get_class_type())) { + make_nurbs_surface(DCAST(EggNurbsSurface, egg_prim), parent, mat); - bool has_vert_color = true; - EggPrimitive::const_iterator vi; - for (vi = egg_prim->begin(); vi != egg_prim->end(); ++vi) { - EggVertex *egg_vert = *vi; - if (egg_vert->get_num_dimensions() != 3) { - egg2pg_cat.error() - << "Vertex " << egg_vert->get_pool()->get_name() - << ":" << egg_vert->get_index() << " has dimension " - << egg_vert->get_num_dimensions() << "\n"; - } else { - BuilderVertex bvert(LCAST(float, egg_vert->get_pos3() * mat)); - - if (egg_vert->has_normal()) { - Normald norm = egg_vert->get_normal() * mat; - norm.normalize(); - bvert.set_normal(LCAST(float, norm)); - } - if (egg_vert->has_color() && !egg_false_color) { - bvert.set_color(egg_vert->get_color()); - } else { - // If any vertex doesn't have a color, we can't use any of the - // vertex colors. - has_vert_color = false; - } - if (egg_vert->has_uv()) { - TexCoordd uv = egg_vert->get_uv(); - if (egg_prim->has_texture() && - egg_prim->get_texture()->has_transform()) { - // If we have a texture matrix, apply it. - uv = uv * egg_prim->get_texture()->get_transform(); - } - bvert.set_texcoord(LCAST(float, uv)); - } - - bprim.add_vertex(bvert); + } else { + // A normal primitive: polygon or point. + BuilderPrim bprim; + bprim.set_type(BPT_poly); + if (egg_prim->is_of_type(EggPoint::get_class_type())) { + bprim.set_type(BPT_point); + } + + if (egg_prim->has_normal()) { + Normald norm = egg_prim->get_normal() * mat; + norm.normalize(); + bprim.set_normal(LCAST(float, norm)); + } + if (egg_prim->has_color() && !egg_false_color) { + bprim.set_color(egg_prim->get_color()); + } + + bool has_vert_color = true; + EggPrimitive::const_iterator vi; + for (vi = egg_prim->begin(); vi != egg_prim->end(); ++vi) { + EggVertex *egg_vert = *vi; + if (egg_vert->get_num_dimensions() != 3) { + egg2pg_cat.error() + << "Vertex " << egg_vert->get_pool()->get_name() + << ":" << egg_vert->get_index() << " has dimension " + << egg_vert->get_num_dimensions() << "\n"; + } else { + BuilderVertex bvert(LCAST(float, egg_vert->get_pos3() * mat)); + + if (egg_vert->has_normal()) { + Normald norm = egg_vert->get_normal() * mat; + norm.normalize(); + bvert.set_normal(LCAST(float, norm)); + } + if (egg_vert->has_color() && !egg_false_color) { + bvert.set_color(egg_vert->get_color()); + } else { + // If any vertex doesn't have a color, we can't use any of the + // vertex colors. + has_vert_color = false; + } + if (egg_vert->has_uv()) { + TexCoordd uv = egg_vert->get_uv(); + if (egg_prim->has_texture() && + egg_prim->get_texture()->has_transform()) { + // If we have a texture matrix, apply it. + uv = uv * egg_prim->get_texture()->get_transform(); + } + bvert.set_texcoord(LCAST(float, uv)); + } + + bprim.add_vertex(bvert); + } } - } - // Finally, if the primitive didn't have a color, and it didn't have - // vertex color, make it white. - if (!egg_prim->has_color() && !has_vert_color && !egg_false_color) { - bprim.set_color(Colorf(1.0, 1.0, 1.0, 1.0)); - } + // Finally, if the primitive didn't have a color, and it didn't have + // vertex color, make it white. + if (!egg_prim->has_color() && !has_vert_color && !egg_false_color) { + bprim.set_color(Colorf(1.0, 1.0, 1.0, 1.0)); + } - _builder.add_prim(bucket, bprim); + _builder.add_prim(bucket, bprim); + } } //////////////////////////////////////////////////////////////////// @@ -430,6 +446,339 @@ make_indexed_primitive(EggPrimitive *egg_prim, PandaNode *parent, _builder.add_prim(bucket, bprim); } +//////////////////////////////////////////////////////////////////// +// Function: EggLoader::make_nurbs_curve +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +void EggLoader:: +make_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent, + const LMatrix4d &mat) { + if (egg_load_old_curves) { + // Make a NurbsCurve instead of a RopeNode (old interface). + make_old_nurbs_curve(egg_curve, parent, mat); + return; + } + + assert(parent != NULL); + assert(!parent->is_geom_node()); + + PT(NurbsCurveEvaluator) nurbs = new NurbsCurveEvaluator; + + if (egg_curve->get_order() < 1 || egg_curve->get_order() > 4) { + egg2pg_cat.error() + << "Invalid NURBSCurve order for " << egg_curve->get_name() << ": " + << egg_curve->get_order() << "\n"; + _error = true; + return; + } + + nurbs->set_order(egg_curve->get_order()); + + nurbs->reset(egg_curve->size()); + EggPrimitive::const_iterator pi; + int vi = 0; + for (pi = egg_curve->begin(); pi != egg_curve->end(); ++pi) { + EggVertex *egg_vertex = (*pi); + nurbs->set_vertex(vi, LCAST(float, egg_vertex->get_pos4() * mat)); + Colorf color = egg_vertex->get_color(); + nurbs->set_extended_vertex(vi, 0, color[0]); + nurbs->set_extended_vertex(vi, 1, color[1]); + nurbs->set_extended_vertex(vi, 2, color[2]); + nurbs->set_extended_vertex(vi, 3, color[3]); + vi++; + } + + int num_knots = egg_curve->get_num_knots(); + if (num_knots != nurbs->get_num_knots()) { + egg2pg_cat.error() + << "Invalid NURBSCurve number of knots for " + << egg_curve->get_name() << ": got " << num_knots + << " knots, expected " << nurbs->get_num_knots() << "\n"; + _error = true; + return; + } + + for (int i = 0; i < num_knots; i++) { + nurbs->set_knot(i, egg_curve->get_knot(i)); + } + + /* + switch (egg_curve->get_curve_type()) { + case EggCurve::CT_xyz: + curve->set_curve_type(PCT_XYZ); + break; + + case EggCurve::CT_hpr: + curve->set_curve_type(PCT_HPR); + break; + + case EggCurve::CT_t: + curve->set_curve_type(PCT_T); + break; + + default: + break; + } + */ + + PT(RopeNode) rope = new RopeNode(egg_curve->get_name()); + rope->set_curve(nurbs); + + // Respect the subdivision values in the egg file, if any. + if (egg_curve->get_subdiv() != 0) { + int subdiv_per_segment = + (int)((egg_curve->get_subdiv() + 0.5) / nurbs->get_num_segments()); + rope->set_num_subdiv(subdiv_per_segment); + } + + // Now get the attributes to apply to the rope. We create a + // BuilderBucket for this purpose, so we can call setup_bucket(), + // but all we do with this bucket is immediately extract the state + // from it. + BuilderBucket bucket; + setup_bucket(bucket, parent, egg_curve); + + rope->set_state(bucket._state); + + // If we have a texture matrix, we have to apply that explicitly + // (the UV's are computed on the fly, so we can't precompute the + // texture matrix into them). + if (egg_curve->has_texture()) { + rope->set_uv_mode(RopeNode::UV_parametric); + + PT(EggTexture) egg_tex = egg_curve->get_texture(); + if (egg_tex->has_transform()) { + // Expand the 2-d matrix to a 3-d matrix. + const LMatrix3d &mat3 = egg_tex->get_transform(); + LMatrix4f mat4(mat3(0, 0), mat3(0, 1), 0.0f, mat3(0, 2), + mat3(1, 0), mat3(1, 1), 0.0f, mat3(1, 2), + 0.0f, 0.0f, 1.0f, 0.0f, + mat3(2, 0), mat3(2, 1), 0.0f, mat3(2, 2)); + rope->set_attrib(TexMatrixAttrib::make(mat4)); + } + } + if (egg_curve->has_vertex_color()) { + // If the curve had individual vertex color, enable it. + rope->set_use_vertex_color(true); + } else if (egg_curve->has_color()) { + // Otherwise, if the curve has overall color, apply it. + rope->set_attrib(ColorAttrib::make_flat(egg_curve->get_color())); + } + + parent->add_child(rope); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggLoader::make_old_nurbs_curve +// Access: Private +// Description: This deprecated interface creates a NurbsCurve (or a +// ClassicNurbsCurve) object for the EggNurbsCurve +// entry. It will eventually be removed in favor of the +// above, which creates a RopeNode. +//////////////////////////////////////////////////////////////////// +void EggLoader:: +make_old_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent, + const LMatrix4d &mat) { + assert(parent != NULL); + assert(!parent->is_geom_node()); + + PT(ParametricCurve) curve; + + if (egg_load_classic_nurbs_curves) { + curve = new ClassicNurbsCurve; + } else { + curve = new NurbsCurve; + } + + NurbsCurveInterface *nurbs = curve->get_nurbs_interface(); + nassertv(nurbs != (NurbsCurveInterface *)NULL); + + if (egg_curve->get_order() < 1 || egg_curve->get_order() > 4) { + egg2pg_cat.error() + << "Invalid NURBSCurve order for " << egg_curve->get_name() << ": " + << egg_curve->get_order() << "\n"; + _error = true; + return; + } + + nurbs->set_order(egg_curve->get_order()); + + EggPrimitive::const_iterator pi; + for (pi = egg_curve->begin(); pi != egg_curve->end(); ++pi) { + nurbs->append_cv(LCAST(float, (*pi)->get_pos4() * mat)); + } + + int num_knots = egg_curve->get_num_knots(); + if (num_knots != nurbs->get_num_knots()) { + egg2pg_cat.error() + << "Invalid NURBSCurve number of knots for " + << egg_curve->get_name() << ": got " << num_knots + << " knots, expected " << nurbs->get_num_knots() << "\n"; + _error = true; + return; + } + + for (int i = 0; i < num_knots; i++) { + nurbs->set_knot(i, egg_curve->get_knot(i)); + } + + switch (egg_curve->get_curve_type()) { + case EggCurve::CT_xyz: + curve->set_curve_type(PCT_XYZ); + break; + + case EggCurve::CT_hpr: + curve->set_curve_type(PCT_HPR); + break; + + case EggCurve::CT_t: + curve->set_curve_type(PCT_T); + break; + + default: + break; + } + curve->set_name(egg_curve->get_name()); + + if (!curve->recompute()) { + egg2pg_cat.error() + << "Invalid NURBSCurve " << egg_curve->get_name() << "\n"; + _error = true; + return; + } + + parent->add_child(curve); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggLoader::make_nurbs_surface +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +void EggLoader:: +make_nurbs_surface(EggNurbsSurface *egg_surface, PandaNode *parent, + const LMatrix4d &mat) { + assert(parent != NULL); + assert(!parent->is_geom_node()); + + PT(NurbsSurfaceEvaluator) nurbs = new NurbsSurfaceEvaluator; + + if (egg_surface->get_u_order() < 1 || egg_surface->get_u_order() > 4) { + egg2pg_cat.error() + << "Invalid NURBSSurface U order for " << egg_surface->get_name() << ": " + << egg_surface->get_u_order() << "\n"; + _error = true; + return; + } + + if (egg_surface->get_v_order() < 1 || egg_surface->get_v_order() > 4) { + egg2pg_cat.error() + << "Invalid NURBSSurface V order for " << egg_surface->get_name() << ": " + << egg_surface->get_v_order() << "\n"; + _error = true; + return; + } + + nurbs->set_u_order(egg_surface->get_u_order()); + nurbs->set_v_order(egg_surface->get_v_order()); + + int num_u_vertices = egg_surface->get_num_u_cvs(); + int num_v_vertices = egg_surface->get_num_v_cvs(); + nurbs->reset(num_u_vertices, num_v_vertices); + for (int ui = 0; ui < num_u_vertices; ui++) { + for (int vi = 0; vi < num_v_vertices; vi++) { + int i = egg_surface->get_vertex_index(ui, vi); + EggVertex *egg_vertex = egg_surface->get_vertex(i); + nurbs->set_vertex(ui, vi, LCAST(float, egg_vertex->get_pos4() * mat)); + + Colorf color = egg_vertex->get_color(); + nurbs->set_extended_vertex(ui, vi, 0, color[0]); + nurbs->set_extended_vertex(ui, vi, 1, color[1]); + nurbs->set_extended_vertex(ui, vi, 2, color[2]); + nurbs->set_extended_vertex(ui, vi, 3, color[3]); + } + } + + int num_u_knots = egg_surface->get_num_u_knots(); + if (num_u_knots != nurbs->get_num_u_knots()) { + egg2pg_cat.error() + << "Invalid NURBSSurface number of U knots for " + << egg_surface->get_name() << ": got " << num_u_knots + << " knots, expected " << nurbs->get_num_u_knots() << "\n"; + _error = true; + return; + } + + int num_v_knots = egg_surface->get_num_v_knots(); + if (num_v_knots != nurbs->get_num_v_knots()) { + egg2pg_cat.error() + << "Invalid NURBSSurface number of U knots for " + << egg_surface->get_name() << ": got " << num_v_knots + << " knots, expected " << nurbs->get_num_v_knots() << "\n"; + _error = true; + return; + } + + int i; + for (i = 0; i < num_u_knots; i++) { + nurbs->set_u_knot(i, egg_surface->get_u_knot(i)); + } + for (i = 0; i < num_v_knots; i++) { + nurbs->set_v_knot(i, egg_surface->get_v_knot(i)); + } + + PT(SheetNode) sheet = new SheetNode(egg_surface->get_name()); + sheet->set_surface(nurbs); + + // Respect the subdivision values in the egg file, if any. + if (egg_surface->get_u_subdiv() != 0) { + int u_subdiv_per_segment = + (int)((egg_surface->get_u_subdiv() + 0.5) / nurbs->get_num_u_segments()); + sheet->set_num_u_subdiv(u_subdiv_per_segment); + } + if (egg_surface->get_v_subdiv() != 0) { + int v_subdiv_per_segment = + (int)((egg_surface->get_v_subdiv() + 0.5) / nurbs->get_num_v_segments()); + sheet->set_num_v_subdiv(v_subdiv_per_segment); + } + + // Now get the attributes to apply to the sheet. We create a + // BuilderBucket for this purpose, so we can call setup_bucket(), + // but all we do with this bucket is immediately extract the state + // from it. + BuilderBucket bucket; + setup_bucket(bucket, parent, egg_surface); + + sheet->set_state(bucket._state); + + // If we have a texture matrix, we have to apply that explicitly + // (the UV's are computed on the fly, so we can't precompute the + // texture matrix into them). + if (egg_surface->has_texture()) { + PT(EggTexture) egg_tex = egg_surface->get_texture(); + if (egg_tex->has_transform()) { + // Expand the 2-d matrix to a 3-d matrix. + const LMatrix3d &mat3 = egg_tex->get_transform(); + LMatrix4f mat4(mat3(0, 0), mat3(0, 1), 0.0f, mat3(0, 2), + mat3(1, 0), mat3(1, 1), 0.0f, mat3(1, 2), + 0.0f, 0.0f, 1.0f, 0.0f, + mat3(2, 0), mat3(2, 1), 0.0f, mat3(2, 2)); + sheet->set_attrib(TexMatrixAttrib::make(mat4)); + } + } + + if (egg_surface->has_vertex_color()) { + // If the surface had individual vertex color, enable it. + sheet->set_use_vertex_color(true); + } else if (egg_surface->has_color()) { + // Otherwise, if the surface has overall color, apply it. + sheet->set_attrib(ColorAttrib::make_flat(egg_surface->get_color())); + } + + parent->add_child(sheet); +} + //////////////////////////////////////////////////////////////////// // Function: EggLoader::load_textures // Access: Private @@ -1146,9 +1495,7 @@ setup_bucket(BuilderBucket &bucket, PandaNode *parent, //////////////////////////////////////////////////////////////////// PandaNode *EggLoader:: make_node(EggNode *egg_node, PandaNode *parent) { - if (egg_node->is_of_type(EggNurbsCurve::get_class_type())) { - return make_node(DCAST(EggNurbsCurve, egg_node), parent); - } else if (egg_node->is_of_type(EggPrimitive::get_class_type())) { + if (egg_node->is_of_type(EggPrimitive::get_class_type())) { return make_node(DCAST(EggPrimitive, egg_node), parent); } else if (egg_node->is_of_type(EggBin::get_class_type())) { return make_node(DCAST(EggBin, egg_node), parent); @@ -1163,85 +1510,6 @@ make_node(EggNode *egg_node, PandaNode *parent) { return (PandaNode *)NULL; } -//////////////////////////////////////////////////////////////////// -// Function: EggLoader::make_node (EggNurbsCurve) -// Access: Private -// Description: -//////////////////////////////////////////////////////////////////// -PandaNode *EggLoader:: -make_node(EggNurbsCurve *egg_curve, PandaNode *parent) { - assert(parent != NULL); - assert(!parent->is_geom_node()); - - PT(ParametricCurve) curve; - - if (egg_load_classic_nurbs_curves) { - curve = new ClassicNurbsCurve; - } else { - curve = new NurbsCurve; - } - - NurbsCurveInterface *nurbs = curve->get_nurbs_interface(); - nassertr(nurbs != (NurbsCurveInterface *)NULL, (PandaNode *)NULL); - - if (egg_curve->get_order() < 1 || egg_curve->get_order() > 4) { - egg2pg_cat.error() - << "Invalid NURBSCurve order for " << egg_curve->get_name() << ": " - << egg_curve->get_order() << "\n"; - _error = true; - return (PandaNode *)NULL; - } - - nurbs->set_order(egg_curve->get_order()); - - EggPrimitive::const_iterator pi; - for (pi = egg_curve->begin(); pi != egg_curve->end(); ++pi) { - nurbs->append_cv(LCAST(float, (*pi)->get_pos4())); - } - - int num_knots = egg_curve->get_num_knots(); - if (num_knots != nurbs->get_num_knots()) { - egg2pg_cat.error() - << "Invalid NURBSCurve number of knots for " - << egg_curve->get_name() << ": got " << num_knots - << " knots, expected " << nurbs->get_num_knots() << "\n"; - _error = true; - return (PandaNode *)NULL; - } - - for (int i = 0; i < num_knots; i++) { - nurbs->set_knot(i, egg_curve->get_knot(i)); - } - - switch (egg_curve->get_curve_type()) { - case EggCurve::CT_xyz: - curve->set_curve_type(PCT_XYZ); - break; - - case EggCurve::CT_hpr: - curve->set_curve_type(PCT_HPR); - break; - - case EggCurve::CT_t: - curve->set_curve_type(PCT_T); - break; - - default: - break; - } - curve->set_name(egg_curve->get_name()); - - if (!curve->recompute()) { - egg2pg_cat.error() - << "Invalid NURBSCurve " << egg_curve->get_name() << "\n"; - _error = true; - return (PandaNode *)NULL; - } - - parent->add_child(curve); - return curve; -} - //////////////////////////////////////////////////////////////////// // Function: EggLoader::make_node (EggPrimitive) // Access: Private diff --git a/panda/src/egg2pg/eggLoader.h b/panda/src/egg2pg/eggLoader.h index 512a673ecb..6a10060798 100644 --- a/panda/src/egg2pg/eggLoader.h +++ b/panda/src/egg2pg/eggLoader.h @@ -41,6 +41,7 @@ class EggNode; class EggBin; class EggTable; class EggNurbsCurve; +class EggNurbsSurface; class EggPrimitive; class EggPolygon; class EggMaterial; @@ -81,6 +82,13 @@ private: CPT(RenderAttrib) _apply; }; + void make_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent, + const LMatrix4d &mat); + void make_old_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent, + const LMatrix4d &mat); + void make_nurbs_surface(EggNurbsSurface *egg_surface, PandaNode *parent, + const LMatrix4d &mat); + void load_textures(); bool load_texture(TextureDef &def, const EggTexture *egg_tex); void apply_texture_attributes(Texture *tex, const EggTexture *egg_tex); @@ -93,7 +101,6 @@ private: EggPrimitive *egg_prim); PandaNode *make_node(EggNode *egg_node, PandaNode *parent); - PandaNode *make_node(EggNurbsCurve *egg_curve, PandaNode *parent); PandaNode *make_node(EggPrimitive *egg_prim, PandaNode *parent); PandaNode *make_node(EggBin *egg_bin, PandaNode *parent); PandaNode *make_node(EggGroup *egg_group, PandaNode *parent); diff --git a/panda/src/parametrics/Sources.pp b/panda/src/parametrics/Sources.pp index 071da62e6e..f0f7da81b3 100644 --- a/panda/src/parametrics/Sources.pp +++ b/panda/src/parametrics/Sources.pp @@ -27,6 +27,7 @@ parametricCurveCollection.I parametricCurveCollection.h \ piecewiseCurve.h \ ropeNode.I ropeNode.h \ + sheetNode.I sheetNode.h \ $[if $[HAVE_NURBSPP], nurbsPPCurve.cxx nurbsPPCurve.h] @@ -43,7 +44,8 @@ nurbsVertex.cxx \ parametricCurve.cxx parametricCurveCollection.cxx \ piecewiseCurve.cxx \ - ropeNode.cxx + ropeNode.cxx \ + sheetNode.cxx #define INSTALL_HEADERS \ classicNurbsCurve.I classicNurbsCurve.h \ @@ -65,7 +67,8 @@ parametricCurve.h \ parametricCurveCollection.I parametricCurveCollection.h \ piecewiseCurve.h \ - ropeNode.I ropeNode.h + ropeNode.I ropeNode.h \ + sheetNode.I sheetNode.h #define IGATESCAN all diff --git a/panda/src/parametrics/config_parametrics.cxx b/panda/src/parametrics/config_parametrics.cxx index 603c6962fd..6d6f4e387d 100644 --- a/panda/src/parametrics/config_parametrics.cxx +++ b/panda/src/parametrics/config_parametrics.cxx @@ -27,6 +27,7 @@ #include "parametricCurveDrawer.h" #include "piecewiseCurve.h" #include "ropeNode.h" +#include "sheetNode.h" #ifdef HAVE_NURBSPP #include "nurbsPPCurve.h" @@ -48,6 +49,7 @@ ConfigureFn(config_parametrics) { ParametricCurveDrawer::init_type(); PiecewiseCurve::init_type(); RopeNode::init_type(); + SheetNode::init_type(); #ifdef HAVE_NURBSPP NurbsPPCurve::init_type(); @@ -58,6 +60,7 @@ ConfigureFn(config_parametrics) { CubicCurveseg::register_with_read_factory(); HermiteCurve::register_with_read_factory(); RopeNode::register_with_read_factory(); + SheetNode::register_with_read_factory(); } const DSearchPath & diff --git a/panda/src/parametrics/nurbsCurveEvaluator.I b/panda/src/parametrics/nurbsCurveEvaluator.I index dc3a5d4bec..96dd76cd3f 100644 --- a/panda/src/parametrics/nurbsCurveEvaluator.I +++ b/panda/src/parametrics/nurbsCurveEvaluator.I @@ -157,7 +157,7 @@ set_vertex_space(int i, const string &space) { // ordinary vertex must be set first, before the // extended vertices can be set. //////////////////////////////////////////////////////////////////// -void NurbsCurveEvaluator:: +INLINE void NurbsCurveEvaluator:: set_extended_vertex(int i, int d, float value) { nassertv(i >= 0 && i < (int)_vertices.size()); _vertices[i].set_extended_vertex(d, value); @@ -171,7 +171,7 @@ set_extended_vertex(int i, int d, float value) { // for the indicated dimension, or 0.0 if nothing has // been set. //////////////////////////////////////////////////////////////////// -float NurbsCurveEvaluator:: +INLINE float NurbsCurveEvaluator:: get_extended_vertex(int i, int d) const { nassertr(i >= 0 && i < (int)_vertices.size(), 0.0f); return _vertices[i].get_extended_vertex(d); @@ -187,3 +187,17 @@ INLINE int NurbsCurveEvaluator:: get_num_knots() const { return (int)_vertices.size() + _order; } + +//////////////////////////////////////////////////////////////////// +// Function: NurbsCurveEvaluator::get_num_segments +// Access: Published +// Description: Returns the number of piecewise continuous segments +// in the curve. This is based on the knot vector. +//////////////////////////////////////////////////////////////////// +INLINE int NurbsCurveEvaluator:: +get_num_segments() const { + if (_basis_dirty) { + ((NurbsCurveEvaluator *)this)->recompute_basis(); + } + return _basis.get_num_segments(); +} diff --git a/panda/src/parametrics/nurbsCurveEvaluator.cxx b/panda/src/parametrics/nurbsCurveEvaluator.cxx index edde644423..d71d84de31 100644 --- a/panda/src/parametrics/nurbsCurveEvaluator.cxx +++ b/panda/src/parametrics/nurbsCurveEvaluator.cxx @@ -227,7 +227,7 @@ recompute_basis() { _basis.clear(_order); if ((int)_vertices.size() > _order - 1) { int min_knot = _order; - int max_knot = (int)_vertices.size() + 1; + int max_knot = (int)_vertices.size(); for (int i = min_knot; i <= max_knot; i++) { nassertv(i - 1 >= 0 && i < (int)_knots.size()); diff --git a/panda/src/parametrics/nurbsCurveEvaluator.h b/panda/src/parametrics/nurbsCurveEvaluator.h index c5f085f21a..06f31f99e5 100644 --- a/panda/src/parametrics/nurbsCurveEvaluator.h +++ b/panda/src/parametrics/nurbsCurveEvaluator.h @@ -71,6 +71,8 @@ PUBLISHED: void set_knot(int i, float knot); float get_knot(int i) const; + INLINE int get_num_segments() const; + PT(NurbsCurveResult) evaluate(const NodePath &rel_to = NodePath()) const; public: diff --git a/panda/src/parametrics/nurbsSurfaceEvaluator.I b/panda/src/parametrics/nurbsSurfaceEvaluator.I index fd1e878041..0eb6ed3f94 100644 --- a/panda/src/parametrics/nurbsSurfaceEvaluator.I +++ b/panda/src/parametrics/nurbsSurfaceEvaluator.I @@ -202,7 +202,7 @@ set_vertex_space(int ui, int vi, const string &space) { // ordinary vertex must be set first, before the // extended vertices can be set. //////////////////////////////////////////////////////////////////// -void NurbsSurfaceEvaluator:: +INLINE void NurbsSurfaceEvaluator:: set_extended_vertex(int ui, int vi, int d, float value) { nassertv(ui >= 0 && ui < _num_u_vertices && vi >= 0 && vi < _num_v_vertices); @@ -217,7 +217,7 @@ set_extended_vertex(int ui, int vi, int d, float value) { // for the indicated dimension, or 0.0 if nothing has // been set. //////////////////////////////////////////////////////////////////// -float NurbsSurfaceEvaluator:: +INLINE float NurbsSurfaceEvaluator:: get_extended_vertex(int ui, int vi, int d) const { nassertr(ui >= 0 && ui < _num_u_vertices && vi >= 0 && vi < _num_v_vertices, 0.0f); @@ -248,6 +248,36 @@ get_num_v_knots() const { return _num_v_vertices + _v_order; } +//////////////////////////////////////////////////////////////////// +// Function: NurbsSurfaceEvaluator::get_num_u_segments +// Access: Published +// Description: Returns the number of piecewise continuous segments +// in the surface in the U direction. This is based on +// the knot vector. +//////////////////////////////////////////////////////////////////// +INLINE int NurbsSurfaceEvaluator:: +get_num_u_segments() const { + if (_u_basis_dirty) { + ((NurbsSurfaceEvaluator *)this)->recompute_u_basis(); + } + return _u_basis.get_num_segments(); +} + +//////////////////////////////////////////////////////////////////// +// Function: NurbsSurfaceEvaluator::get_num_v_segments +// Access: Published +// Description: Returns the number of piecewise continuous segments +// in the surface in the V direction. This is based on +// the knot vector. +//////////////////////////////////////////////////////////////////// +INLINE int NurbsSurfaceEvaluator:: +get_num_v_segments() const { + if (_v_basis_dirty) { + ((NurbsSurfaceEvaluator *)this)->recompute_v_basis(); + } + return _v_basis.get_num_segments(); +} + //////////////////////////////////////////////////////////////////// // Function: NurbsSurfaceEvaluator::vert // Access: Private diff --git a/panda/src/parametrics/nurbsSurfaceEvaluator.cxx b/panda/src/parametrics/nurbsSurfaceEvaluator.cxx index 08ee54daf6..efec3683c4 100644 --- a/panda/src/parametrics/nurbsSurfaceEvaluator.cxx +++ b/panda/src/parametrics/nurbsSurfaceEvaluator.cxx @@ -309,7 +309,7 @@ recompute_u_basis() { _u_basis.clear(_u_order); if (_num_u_vertices > _u_order - 1) { int min_knot = _u_order; - int max_knot = _num_u_vertices + 1; + int max_knot = _num_u_vertices; for (int i = min_knot; i <= max_knot; i++) { nassertv(i - 1 >= 0 && i < (int)_u_knots.size()); @@ -338,7 +338,7 @@ recompute_v_basis() { _v_basis.clear(_v_order); if (_num_v_vertices > _v_order - 1) { int min_knot = _v_order; - int max_knot = _num_v_vertices + 1; + int max_knot = _num_v_vertices; for (int i = min_knot; i <= max_knot; i++) { nassertv(i - 1 >= 0 && i < (int)_v_knots.size()); diff --git a/panda/src/parametrics/nurbsSurfaceEvaluator.h b/panda/src/parametrics/nurbsSurfaceEvaluator.h index e964cb5d91..012015a59e 100644 --- a/panda/src/parametrics/nurbsSurfaceEvaluator.h +++ b/panda/src/parametrics/nurbsSurfaceEvaluator.h @@ -72,6 +72,9 @@ PUBLISHED: void set_v_knot(int i, float knot); float get_v_knot(int i) const; + INLINE int get_num_u_segments() const; + INLINE int get_num_v_segments() const; + PT(NurbsSurfaceResult) evaluate(const NodePath &rel_to = NodePath()) const; public: diff --git a/panda/src/parametrics/nurbsSurfaceResult.cxx b/panda/src/parametrics/nurbsSurfaceResult.cxx index c5f285f62c..6960bdb252 100644 --- a/panda/src/parametrics/nurbsSurfaceResult.cxx +++ b/panda/src/parametrics/nurbsSurfaceResult.cxx @@ -46,63 +46,54 @@ NurbsSurfaceResult(const NurbsBasisVector &u_basis, int num_segments = num_u_segments * num_v_segments; _composed.reserve(num_segments); - for (int ui = 0; ui < num_u_segments; ui++) { - const LMatrix4f &u_basis_mat = _u_basis.get_basis(ui); - - int un = _u_basis.get_vertex_index(ui); - nassertv(un >= 0 && un + u_order - 1 < _num_u_vertices); - - for (int vi = 0; vi < num_v_segments; vi++) { - LMatrix4f v_basis_transpose = transpose(_v_basis.get_basis(vi)); - - int vn = _v_basis.get_vertex_index(vi); - nassertv(vn >= 0 && vn + v_order - 1 < _num_v_vertices); + for (int i = 0; i < num_segments; i++) { + _composed.push_back(ComposedMats()); + } + for (int vi = 0; vi < num_v_segments; vi++) { + LMatrix4f v_basis_transpose = transpose(_v_basis.get_basis(vi)); + + int vn = _v_basis.get_vertex_index(vi); + nassertv(vn >= 0 && vn + v_order - 1 < _num_v_vertices); + + for (int ui = 0; ui < num_u_segments; ui++) { + const LMatrix4f &u_basis_mat = _u_basis.get_basis(ui); + + int un = _u_basis.get_vertex_index(ui); + nassertv(un >= 0 && un + u_order - 1 < _num_u_vertices); + // Create four geometry matrices from our (up to) sixteen // involved vertices. - LVecBase4f c[4][4]; + LMatrix4f geom_x, geom_y, geom_z, geom_w; + memset(&geom_x, 0, sizeof(geom_x)); + memset(&geom_y, 0, sizeof(geom_y)); + memset(&geom_z, 0, sizeof(geom_z)); + memset(&geom_w, 0, sizeof(geom_w)); + for (int uni = 0; uni < 4; uni++) { for (int vni = 0; vni < 4; vni++) { - c[uni][vni] = (uni < u_order && vni < v_order) ? - vecs[verti(un + uni, vn + vni)] : - LVecBase4f::zero(); + if (uni < u_order && vni < v_order) { + const LVecBase4f &vec = vecs[verti(un + uni, vn + vni)]; + geom_x(uni, vni) = vec[0]; + geom_y(uni, vni) = vec[1]; + geom_z(uni, vni) = vec[2]; + geom_w(uni, vni) = vec[3]; + } } } - LMatrix4f geom_x(c[0][0][0], c[0][1][0], c[0][2][0], c[0][3][0], - c[1][0][0], c[1][1][0], c[1][2][0], c[1][3][0], - c[2][0][0], c[2][1][0], c[2][2][0], c[2][3][0], - c[3][0][0], c[3][1][0], c[3][2][0], c[3][3][0]); - - LMatrix4f geom_y(c[0][0][1], c[0][1][1], c[0][2][1], c[0][3][1], - c[1][0][1], c[1][1][1], c[1][2][1], c[1][3][1], - c[2][0][1], c[2][1][1], c[2][2][1], c[2][3][1], - c[3][0][1], c[3][1][1], c[3][2][1], c[3][3][1]); - - LMatrix4f geom_z(c[0][0][2], c[0][1][2], c[0][2][2], c[0][3][2], - c[1][0][2], c[1][1][2], c[1][2][2], c[1][3][2], - c[2][0][2], c[2][1][2], c[2][2][2], c[2][3][2], - c[3][0][2], c[3][1][2], c[3][2][2], c[3][3][2]); - - LMatrix4f geom_w(c[0][0][3], c[0][1][3], c[0][2][3], c[0][3][3], - c[1][0][3], c[1][1][3], c[1][2][3], c[1][3][3], - c[2][0][3], c[2][1][3], c[2][2][3], c[2][3][3], - c[3][0][3], c[3][1][3], c[3][2][3], c[3][3][3]); - // And compose these geometry matrices with the basis matrices // to produce a new set of matrices, which will be used to // evaluate the surface. - ComposedMats result; + int i = segi(ui, vi); + nassertv(i >= 0 && i < (int)_composed.size()); + ComposedMats &result = _composed[i]; result._x = u_basis_mat * geom_x * v_basis_transpose; result._y = u_basis_mat * geom_y * v_basis_transpose; result._z = u_basis_mat * geom_z * v_basis_transpose; result._w = u_basis_mat * geom_w * v_basis_transpose; - - _composed.push_back(result); } } - - nassertv((int)_composed.size() == num_segments); } //////////////////////////////////////////////////////////////////// @@ -125,12 +116,13 @@ NurbsSurfaceResult(const NurbsBasisVector &u_basis, //////////////////////////////////////////////////////////////////// void NurbsSurfaceResult:: eval_segment_point(int ui, int vi, float u, float v, LVecBase3f &point) const { + int i = segi(ui, vi); + nassertv(i >= 0 && i < (int)_composed.size()); + float u2 = u*u; LVecBase4f uvec(u*u2, u2, u, 1.0f); float v2 = v*v; LVecBase4f vvec(v*v2, v2, v, 1.0f); - int i = segi(ui, vi); - nassertv(i >= 0 && i < (int)_composed.size()); float weight = vvec.dot(uvec * _composed[i]._w); @@ -149,14 +141,25 @@ eval_segment_point(int ui, int vi, float u, float v, LVecBase3f &point) const { //////////////////////////////////////////////////////////////////// void NurbsSurfaceResult:: eval_segment_normal(int ui, int vi, float u, float v, LVecBase3f &normal) const { - /* - float t2 = t*t; - LVecBase4f tvec(t2, t, 1.0f, 0.0f); + int i = segi(ui, vi); + nassertv(i >= 0 && i < (int)_composed.size()); - normal.set(tvec.dot(_composed[segment].get_col(0)), - tvec.dot(_composed[segment].get_col(1)), - tvec.dot(_composed[segment].get_col(2))); - */ + float u2 = u*u; + LVecBase4f uvec(u*u2, u2, u, 1.0f); + LVecBase4f duvec(3.0f * u2, 2.0f * u, 1.0f, 0.0f); + float v2 = v*v; + LVecBase4f vvec(v*v2, v2, v, 1.0f); + LVecBase4f dvvec(3.0f * v2, 2.0f * v, 1.0f, 0.0f); + + LVector3f utan(vvec.dot(duvec * _composed[i]._x), + vvec.dot(duvec * _composed[i]._y), + vvec.dot(duvec * _composed[i]._z)); + + LVector3f vtan(dvvec.dot(uvec * _composed[i]._x), + dvvec.dot(uvec * _composed[i]._y), + dvvec.dot(uvec * _composed[i]._z)); + + normal = utan.cross(vtan); } //////////////////////////////////////////////////////////////////// @@ -168,40 +171,39 @@ eval_segment_normal(int ui, int vi, float u, float v, LVecBase3f &normal) const //////////////////////////////////////////////////////////////////// float NurbsSurfaceResult:: eval_segment_extended_point(int ui, int vi, float u, float v, int d) const { - /* - nassertr(segment >= 0 && segment < _basis.get_num_segments(), 0.0f); + // Calculate the composition of the basis matrices and the geometry + // matrix on-the-fly. + LMatrix4f v_basis_transpose = transpose(_v_basis.get_basis(vi)); + const LMatrix4f &u_basis_mat = _u_basis.get_basis(ui); + int u_order = _u_basis.get_order(); + int v_order = _v_basis.get_order(); - int order = _basis.get_order(); - int vi = _basis.get_vertex_index(segment); + int un = _u_basis.get_vertex_index(ui); + int vn = _v_basis.get_vertex_index(vi); - LVecBase4f geom; - int ci = 0; - while (ci < order) { - geom[ci] = _verts[vi + ci].get_extended_vertex(d); - ci++; - } - while (ci < 4) { - geom[ci] = 0.0f; - ci++; + LMatrix4f geom; + memset(&geom, 0, sizeof(geom)); + + for (int uni = 0; uni < 4; uni++) { + for (int vni = 0; vni < 4; vni++) { + if (uni < u_order && vni < v_order) { + geom(uni, vni) = _verts[verti(un + uni, vn + vni)].get_extended_vertex(d); + } + } } - const LMatrix4f &basis = _basis.get_basis(segment); + LMatrix4f composed = u_basis_mat * geom * v_basis_transpose; - // Compute matrix * column vector. - LVecBase4f composed_geom(basis.get_row(0).dot(geom), - basis.get_row(1).dot(geom), - basis.get_row(2).dot(geom), - basis.get_row(3).dot(geom)); + int i = segi(ui, vi); + nassertr(i >= 0 && i < (int)_composed.size(), 0.0f); - float t2 = t*t; - LVecBase4f tvec(t*t2, t2, t, 1.0f); + float u2 = u*u; + LVecBase4f uvec(u*u2, u2, u, 1.0f); + float v2 = v*v; + LVecBase4f vvec(v*v2, v2, v, 1.0f); - float weight = tvec.dot(_composed[segment].get_col(3)); - - float result = tvec.dot(composed_geom) / weight; - return result; - */ - return 0.0f; + float weight = vvec.dot(uvec * _composed[i]._w); + return vvec.dot(uvec * composed) / weight; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/parametrics/parametrics_composite2.cxx b/panda/src/parametrics/parametrics_composite2.cxx index 8ab62563ca..68cd45c912 100644 --- a/panda/src/parametrics/parametrics_composite2.cxx +++ b/panda/src/parametrics/parametrics_composite2.cxx @@ -10,3 +10,4 @@ #include "nurbsBasisVector.cxx" #include "nurbsVertex.cxx" #include "ropeNode.cxx" +#include "sheetNode.cxx" diff --git a/panda/src/parametrics/ropeNode.I b/panda/src/parametrics/ropeNode.I index 8f6c0d3ada..d8b3515398 100644 --- a/panda/src/parametrics/ropeNode.I +++ b/panda/src/parametrics/ropeNode.I @@ -28,7 +28,8 @@ CData() { _render_mode = RopeNode::RM_thread; _uv_mode = RopeNode::UV_none; _uv_scale.set(1.0f, 1.0f); - _num_segs = 10; + _use_vertex_color = false; + _num_subdiv = 10; _thickness = 1.0f; } @@ -43,7 +44,8 @@ CData(const RopeNode::CData ©) : _render_mode(copy._render_mode), _uv_mode(copy._uv_mode), _uv_scale(copy._uv_scale), - _num_segs(copy._num_segs), + _use_vertex_color(copy._use_vertex_color), + _num_subdiv(copy._num_subdiv), _thickness(copy._thickness) { } @@ -145,29 +147,57 @@ get_uv_scale() const { } //////////////////////////////////////////////////////////////////// -// Function: set_num_segs +// Function: set_use_vertex_color // Access: Public -// Description: Specifies the number of segments per cubic segment -// (that is, per unique knot value) to draw in a fixed -// uniform tesselation of the curve. +// Description: Sets the "use vertex color" flag. When this is true, +// the R, G, B, A vertex color is assumed to be stored +// as the dimensions 0, 1, 2, 3, respectively, of the +// extended vertex values. Use +// NurbsCurveEvaluator::set_extended_vertex() to set +// these values. //////////////////////////////////////////////////////////////////// INLINE void RopeNode:: -set_num_segs(int num_segs) { - nassertv(num_segs >= 0); +set_use_vertex_color(bool flag) { CDWriter cdata(_cycler); - cdata->_num_segs = num_segs; + cdata->_use_vertex_color = flag; } //////////////////////////////////////////////////////////////////// -// Function: get_num_segs +// Function: get_use_vertex_color // Access: Public -// Description: Returns the number of segments per cubic segment to -// draw. See set_num_segs(). +// Description: Returns the "use vertex color" flag. See +// set_use_vertex_color(). +//////////////////////////////////////////////////////////////////// +INLINE bool RopeNode:: +get_use_vertex_color() const { + CDReader cdata(_cycler); + return cdata->_use_vertex_color; +} + +//////////////////////////////////////////////////////////////////// +// Function: set_num_subdiv +// Access: Public +// Description: Specifies the number of subdivisions per cubic +// segment (that is, per unique knot value) to draw in a +// fixed uniform tesselation of the curve. +//////////////////////////////////////////////////////////////////// +INLINE void RopeNode:: +set_num_subdiv(int num_subdiv) { + nassertv(num_subdiv >= 0); + CDWriter cdata(_cycler); + cdata->_num_subdiv = num_subdiv; +} + +//////////////////////////////////////////////////////////////////// +// Function: get_num_subdiv +// Access: Public +// Description: Returns the number of subdivisions per cubic segment +// to draw. See set_num_subdiv(). //////////////////////////////////////////////////////////////////// INLINE int RopeNode:: -get_num_segs() const { +get_num_subdiv() const { CDReader cdata(_cycler); - return cdata->_num_segs; + return cdata->_num_subdiv; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/parametrics/ropeNode.cxx b/panda/src/parametrics/ropeNode.cxx index fe655fd442..383560d682 100644 --- a/panda/src/parametrics/ropeNode.cxx +++ b/panda/src/parametrics/ropeNode.cxx @@ -151,19 +151,21 @@ has_cull_callback() const { bool RopeNode:: cull_callback(CullTraverser *trav, CullTraverserData &data) { // Create some geometry on-the-fly to render the rope. - if (get_num_segs() > 0) { + if (get_num_subdiv() > 0) { NurbsCurveEvaluator *curve = get_curve(); - PT(NurbsCurveResult) result = curve->evaluate(data._node_path.get_node_path()); + if (curve != (NurbsCurveEvaluator *)NULL) { + PT(NurbsCurveResult) result = curve->evaluate(data._node_path.get_node_path()); - if (result->get_num_segments() > 0) { - switch (get_render_mode()) { - case RM_thread: - render_thread(trav, data, result); - break; - - case RM_billboard: - render_billboard(trav, data, result); - break; + if (result->get_num_segments() > 0) { + switch (get_render_mode()) { + case RM_thread: + render_thread(trav, data, result); + break; + + case RM_billboard: + render_billboard(trav, data, result); + break; + } } } } @@ -261,13 +263,14 @@ render_thread(CullTraverser *trav, CullTraverserData &data, NurbsCurveResult *result) { UVMode uv_mode = get_uv_mode(); LVecBase2f uv_scale = get_uv_scale(); + bool use_vertex_color = get_use_vertex_color(); PTA_Vertexf verts; PTA_TexCoordf uvs; PTA_Colorf colors; PTA_int lengths; - int num_verts = get_num_segs() + 1; + int num_verts = get_num_subdiv() + 1; int num_segments = result->get_num_segments(); float dist = 0.0f; for (int segment = 0; segment < num_segments; segment++) { @@ -278,6 +281,14 @@ render_thread(CullTraverser *trav, CullTraverserData &data, result->eval_segment_point(segment, t, point); verts.push_back(point); + if (use_vertex_color) { + Colorf color(result->eval_segment_extended_point(segment, t, 0), + result->eval_segment_extended_point(segment, t, 1), + result->eval_segment_extended_point(segment, t, 2), + result->eval_segment_extended_point(segment, t, 3)); + colors.push_back(color); + } + t = result->get_segment_t(segment, t); switch (uv_mode) { case UV_none: @@ -308,8 +319,6 @@ render_thread(CullTraverser *trav, CullTraverserData &data, } lengths.push_back(num_verts); } - - colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); PT(GeomLinestrip) geom = new GeomLinestrip; geom->set_width(get_thickness()); @@ -318,7 +327,13 @@ render_thread(CullTraverser *trav, CullTraverserData &data, if (uv_mode != UV_none) { geom->set_texcoords(uvs, G_PER_VERTEX); } - geom->set_colors(colors, G_OVERALL); + + if (use_vertex_color) { + geom->set_colors(colors, G_PER_VERTEX); + } else { + colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); + geom->set_colors(colors, G_OVERALL); + } geom->set_lengths(lengths); CullableObject *object = new CullableObject(geom, data._state, @@ -355,7 +370,7 @@ render_billboard(CullTraverser *trav, CullTraverserData &data, // build one continuous tristrip for all connected segments, so we // can stitch them together properly at the seams. - int num_verts = get_num_segs() + 1; + int num_verts = get_num_subdiv() + 1; int num_segments = result->get_num_segments(); vector_Vertexf center_verts; diff --git a/panda/src/parametrics/ropeNode.h b/panda/src/parametrics/ropeNode.h index c3a21bc4c4..60f8d0f29c 100644 --- a/panda/src/parametrics/ropeNode.h +++ b/panda/src/parametrics/ropeNode.h @@ -95,8 +95,11 @@ PUBLISHED: INLINE void set_uv_scale(const LVecBase2f &uv_scale); INLINE const LVecBase2f &get_uv_scale() const; - INLINE void set_num_segs(int num_segs); - INLINE int get_num_segs() const; + INLINE void set_use_vertex_color(bool flag); + INLINE bool get_use_vertex_color() const; + + INLINE void set_num_subdiv(int num_subdiv); + INLINE int get_num_subdiv() const; INLINE void set_thickness(float thickness); INLINE float get_thickness() const; @@ -127,7 +130,8 @@ private: RenderMode _render_mode; UVMode _uv_mode; LVecBase2f _uv_scale; - int _num_segs; + bool _use_vertex_color; + int _num_subdiv; float _thickness; }; diff --git a/panda/src/parametrics/sheetNode.I b/panda/src/parametrics/sheetNode.I new file mode 100644 index 0000000000..ce57fad8ba --- /dev/null +++ b/panda/src/parametrics/sheetNode.I @@ -0,0 +1,150 @@ +// Filename: sheetNode.I +// Created by: drose (11Oct03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::CData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE SheetNode::CData:: +CData() { + _surface = new NurbsSurfaceEvaluator; + _use_vertex_color = false; + _num_u_subdiv = 2; + _num_v_subdiv = 2; +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::CData::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE SheetNode::CData:: +CData(const SheetNode::CData ©) : + _surface(copy._surface), + _use_vertex_color(copy._use_vertex_color), + _num_u_subdiv(copy._num_u_subdiv), + _num_v_subdiv(copy._num_v_subdiv) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: set_surface +// Access: Public +// Description: Sets the particular surface represented by the +// SheetNode. +//////////////////////////////////////////////////////////////////// +INLINE void SheetNode:: +set_surface(NurbsSurfaceEvaluator *surface) { + CDWriter cdata(_cycler); + cdata->_surface = surface; +} + +//////////////////////////////////////////////////////////////////// +// Function: get_surface +// Access: Public +// Description: Returns the surface represented by the SheetNode. +//////////////////////////////////////////////////////////////////// +INLINE NurbsSurfaceEvaluator *SheetNode:: +get_surface() const { + CDReader cdata(_cycler); + return cdata->_surface; +} + +//////////////////////////////////////////////////////////////////// +// Function: set_use_vertex_color +// Access: Public +// Description: Sets the "use vertex color" flag. When this is true, +// the R, G, B, A vertex color is assumed to be stored +// as the dimensions 0, 1, 2, 3, respectively, of the +// extended vertex values. Use +// NurbsCurveEvaluator::set_extended_vertex() to set +// these values. +//////////////////////////////////////////////////////////////////// +INLINE void SheetNode:: +set_use_vertex_color(bool flag) { + CDWriter cdata(_cycler); + cdata->_use_vertex_color = flag; +} + +//////////////////////////////////////////////////////////////////// +// Function: get_use_vertex_color +// Access: Public +// Description: Returns the "use vertex color" flag. See +// set_use_vertex_color(). +//////////////////////////////////////////////////////////////////// +INLINE bool SheetNode:: +get_use_vertex_color() const { + CDReader cdata(_cycler); + return cdata->_use_vertex_color; +} + +//////////////////////////////////////////////////////////////////// +// Function: set_num_u_subdiv +// Access: Public +// Description: Specifies the number of subdivisions per cubic +// segment (that is, per unique knot value) to draw in a +// fixed uniform tesselation of the surface in the U +// direction. +//////////////////////////////////////////////////////////////////// +INLINE void SheetNode:: +set_num_u_subdiv(int num_u_subdiv) { + nassertv(num_u_subdiv >= 0); + CDWriter cdata(_cycler); + cdata->_num_u_subdiv = num_u_subdiv; +} + +//////////////////////////////////////////////////////////////////// +// Function: get_num_u_subdiv +// Access: Public +// Description: Returns the number of subdivisions per cubic segment +// to draw in the U direction. See set_num_u_subdiv(). +//////////////////////////////////////////////////////////////////// +INLINE int SheetNode:: +get_num_u_subdiv() const { + CDReader cdata(_cycler); + return cdata->_num_u_subdiv; +} + +//////////////////////////////////////////////////////////////////// +// Function: set_num_v_subdiv +// Access: Public +// Description: Specifies the number of subdivisions per cubic +// segment (that is, per unique knot value) to draw in a +// fixed uniform tesselation of the surface in the V +// direction. +//////////////////////////////////////////////////////////////////// +INLINE void SheetNode:: +set_num_v_subdiv(int num_v_subdiv) { + nassertv(num_v_subdiv >= 0); + CDWriter cdata(_cycler); + cdata->_num_v_subdiv = num_v_subdiv; +} + +//////////////////////////////////////////////////////////////////// +// Function: get_num_v_subdiv +// Access: Public +// Description: Returns the number of subdivisions per cubic segment +// to draw in the V direction. See set_num_v_subdiv(). +//////////////////////////////////////////////////////////////////// +INLINE int SheetNode:: +get_num_v_subdiv() const { + CDReader cdata(_cycler); + return cdata->_num_v_subdiv; +} diff --git a/panda/src/parametrics/sheetNode.cxx b/panda/src/parametrics/sheetNode.cxx new file mode 100644 index 0000000000..07bbb3e240 --- /dev/null +++ b/panda/src/parametrics/sheetNode.cxx @@ -0,0 +1,383 @@ +// Filename: sheetNode.cxx +// Created by: drose (11Oct03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "sheetNode.h" +#include "cullTraverser.h" +#include "cullTraverserData.h" +#include "cullableObject.h" +#include "cullHandler.h" +#include "geomTristrip.h" +#include "bamWriter.h" +#include "bamReader.h" +#include "datagram.h" +#include "datagramIterator.h" + +TypeHandle SheetNode::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::CData::make_copy +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +CycleData *SheetNode::CData:: +make_copy() const { + return new CData(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::CData::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void SheetNode::CData:: +write_datagram(BamWriter *writer, Datagram &dg) const { + // For now, we write a NULL pointer. Eventually we will write out + // the NurbsSurfaceEvaluator pointer. + writer->write_pointer(dg, (TypedWritable *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::CData::fillin +// Access: Public, Virtual +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new SheetNode. +//////////////////////////////////////////////////////////////////// +void SheetNode::CData:: +fillin(DatagramIterator &scan, BamReader *reader) { + // For now, we skip over the NULL pointer that we wrote out. + reader->skip_pointer(scan); +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +SheetNode:: +SheetNode(const string &name) : + PandaNode(name) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::Copy Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +SheetNode:: +SheetNode(const SheetNode ©) : + PandaNode(copy), + _cycler(copy._cycler) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::make_copy +// Access: Public, Virtual +// Description: Returns a newly-allocated Node that is a shallow copy +// of this one. It will be a different Node pointer, +// but its internal data may or may not be shared with +// that of the original Node. +//////////////////////////////////////////////////////////////////// +PandaNode *SheetNode:: +make_copy() const { + return new SheetNode(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::safe_to_transform +// Access: Public, Virtual +// Description: Returns true if it is generally safe to transform +// this particular kind of Node by calling the xform() +// method, false otherwise. For instance, it's usually +// a bad idea to attempt to xform a SheetNode. +//////////////////////////////////////////////////////////////////// +bool SheetNode:: +safe_to_transform() const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::has_cull_callback +// Access: Public, Virtual +// Description: Should be overridden by derived classes to return +// true if cull_callback() has been defined. Otherwise, +// returns false to indicate cull_callback() does not +// need to be called for this node during the cull +// traversal. +//////////////////////////////////////////////////////////////////// +bool SheetNode:: +has_cull_callback() const { + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::cull_callback +// Access: Public, Virtual +// Description: If has_cull_callback() returns true, this function +// will be called during the cull traversal to perform +// any additional operations that should be performed at +// cull time. This may include additional manipulation +// of render state or additional visible/invisible +// decisions, or any other arbitrary operation. +// +// By the time this function is called, the node has +// already passed the bounding-volume test for the +// viewing frustum, and the node's transform and state +// have already been applied to the indicated +// CullTraverserData object. +// +// The return value is true if this node should be +// visible, or false if it should be culled. +//////////////////////////////////////////////////////////////////// +bool SheetNode:: +cull_callback(CullTraverser *trav, CullTraverserData &data) { + // Create some geometry on-the-fly to render the sheet. + if (get_num_u_subdiv() > 0 && get_num_v_subdiv() > 0) { + NurbsSurfaceEvaluator *surface = get_surface(); + if (surface != (NurbsSurfaceEvaluator *)NULL) { + PT(NurbsSurfaceResult) result = surface->evaluate(data._node_path.get_node_path()); + + if (result->get_num_u_segments() > 0 && result->get_num_v_segments() > 0) { + render_sheet(trav, data, result); + } + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void SheetNode:: +output(ostream &out) const { + PandaNode::output(out); + out << " " << get_surface(); +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void SheetNode:: +write(ostream &out, int indent_level) const { + PandaNode::write(out, indent_level); + indent(out, indent_level) << get_surface() << "\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::reset_bound +// Access: Published +// Description: Recomputes the bounding volume. This is normally +// called automatically, but it must occasionally be +// called explicitly when the surface has changed +// properties outside of this node's knowledge. +//////////////////////////////////////////////////////////////////// +void SheetNode:: +reset_bound(const NodePath &rel_to) { + do_recompute_bound(rel_to); + changed_internal_bound(); +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::recompute_internal_bound +// Access: Protected, Virtual +// Description: Called when needed to recompute the node's +// _internal_bound object. Nodes that contain anything +// of substance should redefine this to do the right +// thing. +//////////////////////////////////////////////////////////////////// +BoundingVolume *SheetNode:: +recompute_internal_bound() { + return do_recompute_bound(NodePath(this)); +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::do_recompute_bound +// Access: Private +// Description: Does the actual internal recompute. +//////////////////////////////////////////////////////////////////// +BoundingVolume *SheetNode:: +do_recompute_bound(const NodePath &rel_to) { + // First, get ourselves a fresh, empty bounding volume. + BoundingVolume *bound = PandaNode::recompute_internal_bound(); + nassertr(bound != (BoundingVolume *)NULL, bound); + + NurbsSurfaceEvaluator *surface = get_surface(); + if (surface != (NurbsSurfaceEvaluator *)NULL) { + pvector verts; + get_surface()->get_vertices(verts, rel_to); + + GeometricBoundingVolume *gbv; + DCAST_INTO_R(gbv, bound, bound); + gbv->around(&verts[0], &verts[verts.size() - 1]); + } + return bound; +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::render_sheet +// Access: Private +// Description: Draws the sheet as a series of tristrips along its +// length. +//////////////////////////////////////////////////////////////////// +void SheetNode:: +render_sheet(CullTraverser *trav, CullTraverserData &data, + NurbsSurfaceResult *result) { + bool use_vertex_color = get_use_vertex_color(); + + PTA_Vertexf verts; + PTA_Normalf normals; + PTA_TexCoordf uvs; + PTA_Colorf colors; + PTA_int lengths; + + // We define a series of triangle strips, parallel to the V + // direction. + + int num_u_segments = result->get_num_u_segments(); + int num_v_segments = result->get_num_v_segments(); + int num_u_verts = get_num_u_subdiv() + 1; + int num_v_verts = get_num_v_subdiv() + 1; + + for (int ui = 0; ui < num_u_segments; ui++) { + for (int uni = 0; uni < num_u_verts; uni++) { + float u0 = (float)uni / (float)num_u_verts; + float u1 = (float)(uni + 1) / (float)num_u_verts; + float u0_tc = result->get_segment_u(ui, u0); + float u1_tc = result->get_segment_u(ui, u1); + + for (int vi = 0; vi < num_v_segments; vi++) { + for (int vni = 0; vni < num_v_verts; vni++) { + float v = (float)vni / (float)(num_v_verts - 1); + float v_tc = result->get_segment_v(vi, v); + + LPoint3f point; + LVector3f normal; + result->eval_segment_point(ui, vi, u0, v, point); + result->eval_segment_normal(ui, vi, u0, v, normal); + verts.push_back(point); + normals.push_back(normal); + uvs.push_back(TexCoordf(u0_tc, v_tc)); + + result->eval_segment_point(ui, vi, u1, v, point); + result->eval_segment_normal(ui, vi, u1, v, normal); + verts.push_back(point); + normals.push_back(normal); + uvs.push_back(TexCoordf(u1_tc, v_tc)); + + if (use_vertex_color) { + Colorf c0(result->eval_segment_extended_point(ui, vi, u0, v, 0), + result->eval_segment_extended_point(ui, vi, u0, v, 1), + result->eval_segment_extended_point(ui, vi, u0, v, 2), + result->eval_segment_extended_point(ui, vi, u0, v, 3)); + colors.push_back(c0); + Colorf c1(result->eval_segment_extended_point(ui, vi, u1, v, 0), + result->eval_segment_extended_point(ui, vi, u1, v, 1), + result->eval_segment_extended_point(ui, vi, u1, v, 2), + result->eval_segment_extended_point(ui, vi, u1, v, 3)); + colors.push_back(c1); + } + } + lengths.push_back(num_v_verts * 2); + } + } + } + + colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); + + PT(GeomTristrip) geom = new GeomTristrip; + geom->set_num_prims(lengths.size()); + geom->set_coords(verts); + geom->set_normals(normals, G_PER_VERTEX); + geom->set_texcoords(uvs, G_PER_VERTEX); + + if (use_vertex_color) { + geom->set_colors(colors, G_PER_VERTEX); + } else { + colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); + geom->set_colors(colors, G_OVERALL); + } + geom->set_lengths(lengths); + + CullableObject *object = new CullableObject(geom, data._state, + data._render_transform); + trav->get_cull_handler()->record_object(object); +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// SheetNode. +//////////////////////////////////////////////////////////////////// +void SheetNode:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void SheetNode:: +write_datagram(BamWriter *manager, Datagram &dg) { + PandaNode::write_datagram(manager, dg); + manager->write_cdata(dg, _cycler); +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type SheetNode is encountered +// in the Bam file. It should create the SheetNode +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *SheetNode:: +make_from_bam(const FactoryParams ¶ms) { + SheetNode *node = new SheetNode(""); + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + node->fillin(scan, manager); + + return node; +} + +//////////////////////////////////////////////////////////////////// +// Function: SheetNode::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new SheetNode. +//////////////////////////////////////////////////////////////////// +void SheetNode:: +fillin(DatagramIterator &scan, BamReader *manager) { + PandaNode::fillin(scan, manager); + manager->read_cdata(scan, _cycler); +} diff --git a/panda/src/parametrics/sheetNode.h b/panda/src/parametrics/sheetNode.h new file mode 100644 index 0000000000..5d7143f944 --- /dev/null +++ b/panda/src/parametrics/sheetNode.h @@ -0,0 +1,125 @@ +// Filename: sheetNode.h +// Created by: drose (11Oct03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef SHEETNODE_H +#define SHEETNODE_H + +#include "pandabase.h" +#include "nurbsSurfaceEvaluator.h" +#include "pandaNode.h" + +//////////////////////////////////////////////////////////////////// +// Class : SheetNode +// Description : This class draws a visible representation of the +// NURBS surface stored in its NurbsSurfaceEvaluator. It +// automatically recomputes the surface every frame. +// +// This is not related to NurbsSurface, ClassicNurbsSurface, +// CubicSurfaceseg or any of the ParametricSurface-derived +// objects in this module. It is a completely parallel +// implementation of NURBS surfaces, and will probably +// eventually replace the whole ParametricSurface class +// hierarchy. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA SheetNode : public PandaNode { +PUBLISHED: + SheetNode(const string &name); + +protected: + SheetNode(const SheetNode ©); +public: + virtual void output(ostream &out) const; + virtual void write(ostream &out, int indent_level = 0) const; + + virtual PandaNode *make_copy() const; + + virtual bool safe_to_transform() const; + virtual bool has_cull_callback() const; + virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); + +PUBLISHED: + INLINE void set_surface(NurbsSurfaceEvaluator *surface); + INLINE NurbsSurfaceEvaluator *get_surface() const; + + INLINE void set_use_vertex_color(bool flag); + INLINE bool get_use_vertex_color() const; + + INLINE void set_num_u_subdiv(int num_u_subdiv); + INLINE int get_num_u_subdiv() const; + INLINE void set_num_v_subdiv(int num_v_subdiv); + INLINE int get_num_v_subdiv() const; + + void reset_bound(const NodePath &rel_to); + +protected: + virtual BoundingVolume *recompute_internal_bound(); + +private: + BoundingVolume *do_recompute_bound(const NodePath &rel_to); + void render_sheet(CullTraverser *trav, CullTraverserData &data, + NurbsSurfaceResult *result); + +private: + // This is the data that must be cycled between pipeline stages. + class EXPCL_PANDA CData : public CycleData { + public: + INLINE CData(); + INLINE CData(const CData ©); + virtual CycleData *make_copy() const; + virtual void write_datagram(BamWriter *manager, Datagram &dg) const; + virtual void fillin(DatagramIterator &scan, BamReader *manager); + + PT(NurbsSurfaceEvaluator) _surface; + bool _use_vertex_color; + int _num_u_subdiv; + int _num_v_subdiv; + }; + + PipelineCycler _cycler; + typedef CycleDataReader CDReader; + typedef CycleDataWriter CDWriter; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + PandaNode::init_type(); + register_type(_type_handle, "SheetNode", + PandaNode::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "sheetNode.I" + +#endif