egg loader reads nurbs surfaces and curves into SheetNodes and RopeNodes

This commit is contained in:
David Rose 2003-10-12 18:52:57 +00:00
parent 4c4f4cf20c
commit c69cc5c96f
23 changed files with 1323 additions and 265 deletions

View File

@ -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();

View File

@ -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();

View File

@ -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);

View File

@ -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 <NurbsCurve> 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 <NurbsCurve>
// 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

View File

@ -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;

View File

@ -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 <ctype.h>
@ -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

View File

@ -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);

View File

@ -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

View File

@ -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 &

View File

@ -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();
}

View File

@ -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());

View File

@ -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:

View File

@ -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

View File

@ -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());

View File

@ -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:

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -10,3 +10,4 @@
#include "nurbsBasisVector.cxx"
#include "nurbsVertex.cxx"
#include "ropeNode.cxx"
#include "sheetNode.cxx"

View File

@ -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 &copy) :
_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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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;
};

View File

@ -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 &copy) :
_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;
}

View File

@ -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 &copy) :
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<LPoint3f> 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 &params) {
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);
}

View File

@ -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 &copy);
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 &copy);
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<CData> _cycler;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
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