15 #include "qtessSurface.h"
16 #include "qtessGlobals.h"
17 #include "qtessInputEntry.h"
18 #include "config_egg_qtess.h"
19 #include "eggPolygon.h"
20 #include "eggVertexPool.h"
21 #include "eggVertex.h"
22 #include "eggComment.h"
23 #include "egg_parametrics.h"
34 _egg_surface(egg_surface)
37 _has_vertex_color = _egg_surface->has_vertex_color();
44 _match_u = _match_v = NULL;
45 _tess_u = _tess_v = 0;
63 record_vertex_extras();
65 _nurbs->normalize_u_knots();
66 _nurbs->normalize_v_knots();
67 _nurbs_result = _nurbs->evaluate();
69 _num_u = _nurbs->get_num_u_segments();
70 _num_v = _nurbs->get_num_v_segments();
72 if (QtessGlobals::_respect_egg) {
101 _u_placer.get_scores(_nurbs->get_num_u_segments() * 100,
102 _nurbs->get_num_v_segments() * 2,
103 ratio, _nurbs_result,
true);
104 _v_placer.get_scores(_nurbs->get_num_v_segments() * 100,
105 _nurbs->get_num_u_segments() * 2,
106 ratio, _nurbs_result,
false);
110 return _u_placer.get_total_score() * _v_placer.get_total_score() * _importance2;
126 PT(
EggGroup) group = do_uniform_tesselate(tris);
127 PT(
EggNode) new_node = group.p();
128 if (new_node == (
EggNode *)NULL) {
129 new_node =
new EggComment(_egg_surface->get_name(),
130 "Omitted NURBS surface.");
135 parent->remove_child(_egg_surface);
152 if (_tess_u == 0 || _tess_v == 0) {
153 out << get_name() <<
" : omit\n";
155 }
else if (_iso_u.empty() || _iso_v.empty()) {
156 out << get_name() <<
" : " << _tess_u <<
" " << _tess_v <<
"\n";
159 out << get_name() <<
" : " << _iso_u.back() <<
" " << _iso_v.back();
209 _tess_u = (int)_iso_u.size() - 1;
210 _tess_v = (int)_iso_v.size() - 1;
221 if (_num_u == 0 || _num_v == 0) {
225 _tess_u = max(_min_u, (
int)floor(_num_u * _importance * pi + 0.5));
226 _tess_v = max(_min_v, (
int)floor(_num_v * _importance * pi + 0.5));
248 _tess_u = max(_min_u, (
int)floor(_u_placer.get_total_score() * _importance * pi + 0.5));
249 _tess_v = max(_min_v, (
int)floor(_v_placer.get_total_score() * _importance * pi + 0.5));
271 _u_placer.place(u, _iso_u);
272 _v_placer.place(v, _iso_v);
273 _tess_u = (int)_iso_u.size() - 1;
274 _tess_v = (int)_iso_v.size() - 1;
287 record_vertex_extras() {
288 int num_u_vertices = _egg_surface->get_num_u_cvs();
289 int num_v_vertices = _egg_surface->get_num_v_cvs();
291 for (
int ui = 0; ui < num_u_vertices; ui++) {
292 for (
int vi = 0; vi < num_v_vertices; vi++) {
293 int i = _egg_surface->get_vertex_index(ui, vi);
294 EggVertex *egg_vertex = _egg_surface->get_vertex(i);
297 EggVertex::GroupRef::const_iterator gi;
300 int d = get_joint_membership_index(joint);
302 _nurbs->set_extended_vertex(ui, vi, d, membership);
306 EggMorphVertexList::const_iterator dxi;
307 for (dxi = egg_vertex->_dxyzs.begin();
308 dxi != egg_vertex->_dxyzs.end();
310 const string &morph_name = (*dxi).get_name();
311 LVector3 delta = LCAST(PN_stdfloat, (*dxi).get_offset());
312 int d = get_dxyz_index(morph_name);
313 _nurbs->set_extended_vertices(ui, vi, d, delta.
get_data(), 3);
317 EggMorphColorList::const_iterator dri;
318 for (dri = egg_vertex->_drgbas.begin();
319 dri != egg_vertex->_drgbas.end();
321 const string &morph_name = (*dri).get_name();
322 const LVector4 &delta = (*dri).get_offset();
323 int d = get_drgba_index(morph_name);
324 _nurbs->set_extended_vertices(ui, vi, d, delta.
get_data(), 4);
339 if (_match_u != NULL) {
343 <<
"No surface to match " << get_name() <<
" to in U.\n";
345 if (qtess_cat.is_debug()) {
347 <<
"Matching " << get_name() <<
" in U to " << m->get_name()
348 <<
" in " << (_match_u_to_u?
'U':
'V') <<
".\n";
351 _tess_u = m->_tess_u;
354 _tess_u = m->_tess_v;
360 if (_match_v != NULL) {
364 <<
"No surface to match " << get_name() <<
" in V.\n";
366 if (qtess_cat.is_debug()) {
368 <<
"Matching " << get_name() <<
" in V to " << m->get_name()
369 <<
" in " << (_match_v_to_v?
'V':
'U') <<
".\n";
372 _tess_v = m->_tess_v;
375 _tess_v = m->_tess_u;
390 do_uniform_tesselate(
int &tris)
const {
393 if (_tess_u == 0 || _tess_v == 0) {
395 if (qtess_cat.is_debug()) {
397 << get_name() <<
" : omit\n";
407 int num_u = _tess_u + 1;
408 int num_v = _tess_v + 1;
410 if (qtess_cat.is_debug()) {
411 qtess_cat.debug() << get_name() <<
" : " << tris <<
"\n";
414 assert(_iso_u.empty() || (int)_iso_u.size() == num_u);
415 assert(_iso_v.empty() || (int)_iso_v.size() == num_v);
419 int num_verts = num_u * num_v;
423 group->add_child(vpool);
430 VertexList new_verts;
431 new_verts.reserve(num_verts);
437 NVertexCollection n_collection;
439 for (vi = 0; vi < num_v; vi++) {
440 if (_iso_v.empty()) {
441 v = (double)vi / (
double)(num_v-1);
443 v = _iso_v[vi] / _iso_v.back();
445 for (ui = 0; ui < num_u; ui++) {
446 if (_iso_u.empty()) {
447 u = (double)ui / (
double)(num_u-1);
449 u = _iso_u[ui] / _iso_u.back();
452 PT(
EggVertex) egg_vertex = evaluate_vertex(u, v);
453 vpool->add_vertex(egg_vertex);
454 new_verts.push_back(egg_vertex);
455 n_collection[egg_vertex->get_pos3()].insert(egg_vertex);
458 nassertr((
int)new_verts.size() == num_verts, NULL);
461 for (vi = 1; vi < num_v; vi++) {
462 for (ui = 1; ui < num_u; ui++) {
464 poly->add_vertex(new_verts[vi*num_u + (ui-1)]);
465 poly->add_vertex(new_verts[(vi-1)*num_u + (ui-1)]);
466 poly->add_vertex(new_verts[(vi-1)*num_u + ui]);
467 poly->add_vertex(new_verts[vi*num_u + ui]);
469 poly->copy_attributes(*_egg_surface);
474 if (poly->recompute_polygon_normal()) {
476 group->add_child(poly);
486 NVertexCollection::const_iterator nci;
487 for (nci = n_collection.begin(); nci != n_collection.end(); ++nci) {
488 const NVertexGroup &group = (*nci).second;
494 NVertexGroup::const_iterator ngi;
495 for (ngi = group.begin(); ngi != group.end(); ++ngi) {
497 EggVertex::PrimitiveRef::const_iterator pri;
502 nassertr(egg_primitive->has_normal(), NULL);
503 normal += egg_primitive->get_normal();
509 normal /= (double)num_polys;
514 for (ngi = group.begin(); ngi != group.end(); ++ngi) {
516 if (egg_vertex->has_normal()) {
517 if (normal.dot(egg_vertex->get_normal()) < 0.0) {
519 egg_vertex->set_normal(-egg_vertex->get_normal());
524 egg_vertex->set_normal(normal);
541 evaluate_vertex(
double u,
double v)
const {
546 _nurbs_result->eval_point(u, v, point);
547 _nurbs_result->eval_normal(u, v, normal);
552 PN_stdfloat length = normal.length();
553 if (length > 0.0001f) {
555 egg_vertex->set_normal(LCAST(
double, normal));
558 egg_vertex->
set_pos(LCAST(
double, point));
562 if (_has_vertex_color) {
564 _nurbs_result->eval_extended_points(u, v, 0, &rgba[0], 4);
565 egg_vertex->set_color(rgba);
569 JointTable::const_iterator jti;
570 for (jti = _joint_table.begin(); jti != _joint_table.end(); ++jti) {
572 int d = (*jti).second;
574 double membership = _nurbs_result->eval_extended_point(u, v, d);
575 if (membership > 0.0) {
581 MorphTable::const_iterator mti;
582 for (mti = _dxyz_table.begin(); mti != _dxyz_table.end(); ++mti) {
583 const string &morph_name = (*mti).first;
584 int d = (*mti).second;
587 _nurbs_result->eval_extended_points(u, v, d, &delta[0], 3);
593 for (mti = _drgba_table.begin(); mti != _drgba_table.end(); ++mti) {
594 const string &morph_name = (*mti).first;
595 int d = (*mti).second;
598 _nurbs_result->eval_extended_points(u, v, d, &delta[0], 4);
A base class for any of a number of kinds of geometry primitives: polygons, point lights...
bool almost_equal(const LVecBase4f &other, float threshold) const
Returns true if two vectors are memberwise equal within a specified tolerance.
PrimitiveRef::const_iterator pref_end() const
Returns an iterator that can, in conjunction with pref_begin(), be used to traverse the entire set of...
A reference to an EggNurbsSurface in the egg file, and its parameters as set by the user input file a...
const float * get_data() const
Returns the address of the first of the four data elements in the vector.
This is our own Panda specialization on the default STL map.
const float * get_data() const
Returns the address of the first of the three data elements in the vector.
void set_pos(double pos)
Sets the vertex position.
This is the base class for all two-component vectors and points.
A base class for nodes in the hierarchy that are not leaf nodes.
PrimitiveRef::const_iterator pref_begin() const
Returns an iterator that can, in conjunction with pref_end(), be used to traverse the entire set of p...
static const LVector3f & zero()
Returns a zero-length vector.
pair< iterator, bool > insert(const MorphType &value)
This is similar to the insert() interface for sets, except it does not guarantee that the resulting l...
GroupRef::const_iterator gref_end() const
Returns an iterator that can, in conjunction with gref_begin(), be used to traverse the entire set of...
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
This class is an abstraction for evaluating NURBS surfaces.
GroupRef::const_iterator gref_begin() const
Returns an iterator that can, in conjunction with gref_end(), be used to traverse the entire set of g...
A single <Dxyz> or <Duv> or some such entry.
static const LVector3d & zero()
Returns a zero-length vector.
int get_v_subdiv() const
Returns the requested number of subdivisions in the U direction, or 0 if no particular subdivisions h...
static const LVector4f & zero()
Returns a zero-length vector.
bool is_closed_u() const
Returns true if the surface appears to be closed in the U direction.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
int get_u_subdiv() const
Returns the requested number of subdivisions in the U direction, or 0 if no particular subdivisions h...
static const LMatrix4d & ident_mat()
Returns an identity matrix.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
void tesselate_auto(int u, int v, double ratio)
Sets the surface up to tesselate itself by automatically determining the best place to put the indica...
double get_score(double ratio)
Computes the curvature/stretch score for the surface, if it has not been already computed, and returns the net surface score.
double get_vertex_membership(const EggVertex *vert) const
Returns the amount of membership of the indicated vertex in this group.
int write_qtess_parameter(ostream &out)
Writes a line to the given output file telling qtess how this surface should be tesselated uniformly...
This is a four-component vector distance.
void omit()
Sets up the surface to omit itself from the output.
void tesselate_specific(const pvector< double > &u_list, const pvector< double > &v_list)
Sets the surface up to tesselate itself at specific isoparams only.
This is the base class for all three-component vectors and points.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
bool is_closed_v() const
Returns true if the surface appears to be closed in the V direction.
bool almost_equal(const LVecBase3f &other, float threshold) const
Returns true if two vectors are memberwise equal within a specified tolerance.
A base class for things that may be directly added into the egg hierarchy.
int tesselate()
Applies the appropriate tesselation to the surface, and replaces its node in the tree with an EggGrou...
A parametric NURBS surface.
void tesselate_per_isoparam(double pi, bool autoplace, double ratio)
Sets the surface up to tesselate itself to a uniform amount per isoparam.
void tesselate_per_score(double pi, bool autoplace, double ratio)
Sets the surface up to tesselate itself according to its computed curvature score in both dimensions...
void ref_vertex(EggVertex *vert, double membership=1.0)
Adds the vertex to the set of those referenced by the group, at the indicated membership level...
This is our own Panda specialization on the default STL set.
void set_uv(const LTexCoordd &texCoord)
Replaces the unnamed UV coordinate pair on the vertex with the indicated value.
A collection of vertices.
void tesselate_uv(int u, int v, bool autoplace, double ratio)
Sets the surface up to tesselate itself uniformly at u x v, or if autoplace is true, automatically with u x v quads.
static void output_extra(ostream &out, const pvector< double > &iso, char axis)
This function is used to identify the extra isoparams in the list added by user control.
int count_tris() const
Returns the number of triangles that will be generated by the current tesselation parameters...