egg loader reads nurbs surfaces and curves into SheetNodes and RopeNodes
This commit is contained in:
parent
4c4f4cf20c
commit
c69cc5c96f
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 &
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -10,3 +10,4 @@
|
|||
#include "nurbsBasisVector.cxx"
|
||||
#include "nurbsVertex.cxx"
|
||||
#include "ropeNode.cxx"
|
||||
#include "sheetNode.cxx"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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<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 ¶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);
|
||||
}
|
||||
|
|
@ -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<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 ¶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
|
||||
Loading…
Reference in New Issue