00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "qtessSurface.h"
00016 #include "qtessGlobals.h"
00017 #include "qtessInputEntry.h"
00018 #include "config_egg_qtess.h"
00019 #include "eggPolygon.h"
00020 #include "eggVertexPool.h"
00021 #include "eggVertex.h"
00022 #include "eggComment.h"
00023 #include "egg_parametrics.h"
00024 #include "pset.h"
00025 #include "pmap.h"
00026
00027
00028
00029
00030
00031
00032 QtessSurface::
00033 QtessSurface(EggNurbsSurface *egg_surface) :
00034 _egg_surface(egg_surface)
00035 {
00036 _nurbs = make_nurbs_surface(_egg_surface, LMatrix4d::ident_mat());
00037 _has_vertex_color = _egg_surface->has_vertex_color();
00038
00039
00040 _next_d = 4;
00041
00042 _importance = 1.0;
00043 _importance2 = 1.0;
00044 _match_u = _match_v = NULL;
00045 _tess_u = _tess_v = 0;
00046 _got_scores = false;
00047
00048
00049
00050
00051 _min_u = _min_v = 1;
00052 if (egg_surface->is_closed_u()) {
00053 _min_u = 3;
00054 }
00055 if (egg_surface->is_closed_v()) {
00056 _min_v = 3;
00057 }
00058
00059 if (_nurbs == (NurbsSurfaceEvaluator *)NULL) {
00060 _num_u = _num_v = 0;
00061
00062 } else {
00063 record_vertex_extras();
00064
00065 _nurbs->normalize_u_knots();
00066 _nurbs->normalize_v_knots();
00067 _nurbs_result = _nurbs->evaluate();
00068
00069 _num_u = _nurbs->get_num_u_segments();
00070 _num_v = _nurbs->get_num_v_segments();
00071
00072 if (QtessGlobals::_respect_egg) {
00073 if (egg_surface->get_u_subdiv() != 0) {
00074 _num_u = egg_surface->get_u_subdiv();
00075 }
00076 if (egg_surface->get_v_subdiv() != 0) {
00077 _num_v = egg_surface->get_v_subdiv();
00078 }
00079 }
00080 }
00081 }
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 double QtessSurface::
00095 get_score(double ratio) {
00096 if (_nurbs == (NurbsSurfaceEvaluator *)NULL) {
00097 return 0.0;
00098 }
00099
00100 if (!_got_scores) {
00101 _u_placer.get_scores(_nurbs->get_num_u_segments() * 100,
00102 _nurbs->get_num_v_segments() * 2,
00103 ratio, _nurbs_result, true);
00104 _v_placer.get_scores(_nurbs->get_num_v_segments() * 100,
00105 _nurbs->get_num_u_segments() * 2,
00106 ratio, _nurbs_result, false);
00107 _got_scores = true;
00108 }
00109
00110 return _u_placer.get_total_score() * _v_placer.get_total_score() * _importance2;
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 int QtessSurface::
00122 tesselate() {
00123 apply_match();
00124 int tris = 0;
00125
00126 PT(EggGroup) group = do_uniform_tesselate(tris);
00127 PT(EggNode) new_node = group.p();
00128 if (new_node == (EggNode *)NULL) {
00129 new_node = new EggComment(_egg_surface->get_name(),
00130 "Omitted NURBS surface.");
00131 tris = 0;
00132 }
00133 EggGroupNode *parent = _egg_surface->get_parent();
00134 nassertr(parent != (EggGroupNode *)NULL, 0);
00135 parent->remove_child(_egg_surface);
00136 parent->add_child(new_node);
00137
00138 return tris;
00139 }
00140
00141
00142
00143
00144
00145
00146
00147
00148 int QtessSurface::
00149 write_qtess_parameter(ostream &out) {
00150 apply_match();
00151
00152 if (_tess_u == 0 || _tess_v == 0) {
00153 out << get_name() << " : omit\n";
00154
00155 } else if (_iso_u.empty() || _iso_v.empty()) {
00156 out << get_name() << " : " << _tess_u << " " << _tess_v << "\n";
00157
00158 } else {
00159 out << get_name() << " : " << _iso_u.back() << " " << _iso_v.back();
00160 QtessInputEntry::output_extra(out, _iso_u, 'u');
00161 QtessInputEntry::output_extra(out, _iso_v, 'v');
00162 out << "\n";
00163 }
00164
00165 return count_tris();
00166 }
00167
00168
00169
00170
00171
00172
00173
00174 void QtessSurface::
00175 omit() {
00176 _tess_u = 0;
00177 _tess_v = 0;
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00187 void QtessSurface::
00188 tesselate_uv(int u, int v, bool autoplace, double ratio) {
00189 _tess_u = u;
00190 _tess_v = v;
00191 _iso_u.clear();
00192 _iso_v.clear();
00193 if (autoplace) {
00194 tesselate_auto(_tess_u, _tess_v, ratio);
00195 }
00196 }
00197
00198
00199
00200
00201
00202
00203
00204 void QtessSurface::
00205 tesselate_specific(const pvector<double> &u_list,
00206 const pvector<double> &v_list) {
00207 _iso_u = u_list;
00208 _iso_v = v_list;
00209 _tess_u = (int)_iso_u.size() - 1;
00210 _tess_v = (int)_iso_v.size() - 1;
00211 }
00212
00213
00214
00215
00216
00217
00218
00219 void QtessSurface::
00220 tesselate_per_isoparam(double pi, bool autoplace, double ratio) {
00221 if (_num_u == 0 || _num_v == 0) {
00222 omit();
00223
00224 } else {
00225 _tess_u = max(_min_u, (int)floor(_num_u * _importance * pi + 0.5));
00226 _tess_v = max(_min_v, (int)floor(_num_v * _importance * pi + 0.5));
00227 _iso_u.clear();
00228 _iso_v.clear();
00229 if (autoplace) {
00230 tesselate_auto(_tess_u, _tess_v, ratio);
00231 }
00232 }
00233 }
00234
00235
00236
00237
00238
00239
00240
00241
00242 void QtessSurface::
00243 tesselate_per_score(double pi, bool autoplace, double ratio) {
00244 if (get_score(ratio) <= 0.0) {
00245 omit();
00246
00247 } else {
00248 _tess_u = max(_min_u, (int)floor(_u_placer.get_total_score() * _importance * pi + 0.5));
00249 _tess_v = max(_min_v, (int)floor(_v_placer.get_total_score() * _importance * pi + 0.5));
00250 _iso_u.clear();
00251 _iso_v.clear();
00252 if (autoplace) {
00253 tesselate_auto(_tess_u, _tess_v, ratio);
00254 }
00255 }
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265 void QtessSurface::
00266 tesselate_auto(int u, int v, double ratio) {
00267 if (get_score(ratio) <= 0.0) {
00268 omit();
00269
00270 } else {
00271 _u_placer.place(u, _iso_u);
00272 _v_placer.place(v, _iso_v);
00273 _tess_u = (int)_iso_u.size() - 1;
00274 _tess_v = (int)_iso_v.size() - 1;
00275 }
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286 void QtessSurface::
00287 record_vertex_extras() {
00288 int num_u_vertices = _egg_surface->get_num_u_cvs();
00289 int num_v_vertices = _egg_surface->get_num_v_cvs();
00290
00291 for (int ui = 0; ui < num_u_vertices; ui++) {
00292 for (int vi = 0; vi < num_v_vertices; vi++) {
00293 int i = _egg_surface->get_vertex_index(ui, vi);
00294 EggVertex *egg_vertex = _egg_surface->get_vertex(i);
00295
00296
00297 EggVertex::GroupRef::const_iterator gi;
00298 for (gi = egg_vertex->gref_begin(); gi != egg_vertex->gref_end(); ++gi) {
00299 EggGroup *joint = (*gi);
00300 int d = get_joint_membership_index(joint);
00301 double membership = joint->get_vertex_membership(egg_vertex);
00302 _nurbs->set_extended_vertex(ui, vi, d, membership);
00303 }
00304
00305
00306 EggMorphVertexList::const_iterator dxi;
00307 for (dxi = egg_vertex->_dxyzs.begin();
00308 dxi != egg_vertex->_dxyzs.end();
00309 ++dxi) {
00310 const string &morph_name = (*dxi).get_name();
00311 LVector3 delta = LCAST(PN_stdfloat, (*dxi).get_offset());
00312 int d = get_dxyz_index(morph_name);
00313 _nurbs->set_extended_vertices(ui, vi, d, delta.get_data(), 3);
00314 }
00315
00316
00317 EggMorphColorList::const_iterator dri;
00318 for (dri = egg_vertex->_drgbas.begin();
00319 dri != egg_vertex->_drgbas.end();
00320 ++dri) {
00321 const string &morph_name = (*dri).get_name();
00322 const LVector4 &delta = (*dri).get_offset();
00323 int d = get_drgba_index(morph_name);
00324 _nurbs->set_extended_vertices(ui, vi, d, delta.get_data(), 4);
00325 }
00326 }
00327 }
00328 }
00329
00330
00331
00332
00333
00334
00335
00336
00337 void QtessSurface::
00338 apply_match() {
00339 if (_match_u != NULL) {
00340 QtessSurface *m = *_match_u;
00341 if (m == NULL) {
00342 qtess_cat.warning()
00343 << "No surface to match " << get_name() << " to in U.\n";
00344 } else {
00345 if (qtess_cat.is_debug()) {
00346 qtess_cat.debug()
00347 << "Matching " << get_name() << " in U to " << m->get_name()
00348 << " in " << (_match_u_to_u?'U':'V') << ".\n";
00349 }
00350 if (_match_u_to_u) {
00351 _tess_u = m->_tess_u;
00352 _iso_u = m->_iso_u;
00353 } else {
00354 _tess_u = m->_tess_v;
00355 _iso_u = m->_iso_v;
00356 }
00357 }
00358 }
00359
00360 if (_match_v != NULL) {
00361 QtessSurface *m = *_match_v;
00362 if (m == NULL) {
00363 qtess_cat.warning()
00364 << "No surface to match " << get_name() << " in V.\n";
00365 } else {
00366 if (qtess_cat.is_debug()) {
00367 qtess_cat.debug()
00368 << "Matching " << get_name() << " in V to " << m->get_name()
00369 << " in " << (_match_v_to_v?'V':'U') << ".\n";
00370 }
00371 if (_match_v_to_v) {
00372 _tess_v = m->_tess_v;
00373 _iso_v = m->_iso_v;
00374 } else {
00375 _tess_v = m->_tess_u;
00376 _iso_v = m->_iso_u;
00377 }
00378 }
00379 }
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389 PT(EggGroup) QtessSurface::
00390 do_uniform_tesselate(int &tris) const {
00391 tris = 0;
00392
00393 if (_tess_u == 0 || _tess_v == 0) {
00394
00395 if (qtess_cat.is_debug()) {
00396 qtess_cat.debug()
00397 << get_name() << " : omit\n";
00398 }
00399 return NULL;
00400 }
00401
00402 PT(EggGroup) group = new EggGroup(_egg_surface->get_name());
00403
00404
00405
00406
00407 int num_u = _tess_u + 1;
00408 int num_v = _tess_v + 1;
00409
00410 if (qtess_cat.is_debug()) {
00411 qtess_cat.debug() << get_name() << " : " << tris << "\n";
00412 }
00413
00414 assert(_iso_u.empty() || (int)_iso_u.size() == num_u);
00415 assert(_iso_v.empty() || (int)_iso_v.size() == num_v);
00416
00417
00418
00419 int num_verts = num_u * num_v;
00420
00421
00422 PT(EggVertexPool) vpool = new EggVertexPool(_egg_surface->get_name());
00423 group->add_child(vpool);
00424
00425
00426 int ui, vi;
00427 double u, v;
00428
00429 typedef pvector<EggVertex *> VertexList;
00430 VertexList new_verts;
00431 new_verts.reserve(num_verts);
00432
00433
00434
00435 typedef pset<EggVertex *> NVertexGroup;
00436 typedef pmap<LVertexd, NVertexGroup> NVertexCollection;
00437 NVertexCollection n_collection;
00438
00439 for (vi = 0; vi < num_v; vi++) {
00440 if (_iso_v.empty()) {
00441 v = (double)vi / (double)(num_v-1);
00442 } else {
00443 v = _iso_v[vi] / _iso_v.back();
00444 }
00445 for (ui = 0; ui < num_u; ui++) {
00446 if (_iso_u.empty()) {
00447 u = (double)ui / (double)(num_u-1);
00448 } else {
00449 u = _iso_u[ui] / _iso_u.back();
00450 }
00451
00452 PT(EggVertex) egg_vertex = evaluate_vertex(u, v);
00453 vpool->add_vertex(egg_vertex);
00454 new_verts.push_back(egg_vertex);
00455 n_collection[egg_vertex->get_pos3()].insert(egg_vertex);
00456 }
00457 }
00458 nassertr((int)new_verts.size() == num_verts, NULL);
00459
00460
00461 for (vi = 1; vi < num_v; vi++) {
00462 for (ui = 1; ui < num_u; ui++) {
00463 PT(EggPolygon) poly = new EggPolygon;
00464 poly->add_vertex(new_verts[vi*num_u + (ui-1)]);
00465 poly->add_vertex(new_verts[(vi-1)*num_u + (ui-1)]);
00466 poly->add_vertex(new_verts[(vi-1)*num_u + ui]);
00467 poly->add_vertex(new_verts[vi*num_u + ui]);
00468
00469 poly->copy_attributes(*_egg_surface);
00470
00471
00472
00473
00474 if (poly->recompute_polygon_normal()) {
00475 tris += 2;
00476 group->add_child(poly);
00477 }
00478 }
00479 }
00480
00481
00482
00483
00484
00485
00486 NVertexCollection::const_iterator nci;
00487 for (nci = n_collection.begin(); nci != n_collection.end(); ++nci) {
00488 const NVertexGroup &group = (*nci).second;
00489
00490
00491
00492 LNormald normal = LNormald::zero();
00493 int num_polys = 0;
00494 NVertexGroup::const_iterator ngi;
00495 for (ngi = group.begin(); ngi != group.end(); ++ngi) {
00496 EggVertex *egg_vertex = (*ngi);
00497 EggVertex::PrimitiveRef::const_iterator pri;
00498 for (pri = egg_vertex->pref_begin();
00499 pri != egg_vertex->pref_end();
00500 ++pri) {
00501 EggPrimitive *egg_primitive = (*pri);
00502 nassertr(egg_primitive->has_normal(), NULL);
00503 normal += egg_primitive->get_normal();
00504 num_polys++;
00505 }
00506 }
00507
00508 if (num_polys > 0) {
00509 normal /= (double)num_polys;
00510
00511
00512
00513
00514 for (ngi = group.begin(); ngi != group.end(); ++ngi) {
00515 EggVertex *egg_vertex = (*ngi);
00516 if (egg_vertex->has_normal()) {
00517 if (normal.dot(egg_vertex->get_normal()) < 0.0) {
00518
00519 egg_vertex->set_normal(-egg_vertex->get_normal());
00520 }
00521 } else {
00522
00523
00524 egg_vertex->set_normal(normal);
00525 }
00526 }
00527 }
00528 }
00529
00530 return group;
00531 }
00532
00533
00534
00535
00536
00537
00538
00539
00540 PT(EggVertex) QtessSurface::
00541 evaluate_vertex(double u, double v) const {
00542 PT(EggVertex) egg_vertex = new EggVertex;
00543
00544 LVertex point;
00545 LNormal normal;
00546 _nurbs_result->eval_point(u, v, point);
00547 _nurbs_result->eval_normal(u, v, normal);
00548
00549
00550
00551
00552 PN_stdfloat length = normal.length();
00553 if (length > 0.0001f) {
00554 normal /= length;
00555 egg_vertex->set_normal(LCAST(double, normal));
00556 }
00557
00558 egg_vertex->set_pos(LCAST(double, point));
00559 egg_vertex->set_uv(LVecBase2d(u, v));
00560
00561
00562 if (_has_vertex_color) {
00563 LColor rgba;
00564 _nurbs_result->eval_extended_points(u, v, 0, &rgba[0], 4);
00565 egg_vertex->set_color(rgba);
00566 }
00567
00568
00569 JointTable::const_iterator jti;
00570 for (jti = _joint_table.begin(); jti != _joint_table.end(); ++jti) {
00571 EggGroup *joint = (*jti).first;
00572 int d = (*jti).second;
00573
00574 double membership = _nurbs_result->eval_extended_point(u, v, d);
00575 if (membership > 0.0) {
00576 joint->ref_vertex(egg_vertex, membership);
00577 }
00578 }
00579
00580
00581 MorphTable::const_iterator mti;
00582 for (mti = _dxyz_table.begin(); mti != _dxyz_table.end(); ++mti) {
00583 const string &morph_name = (*mti).first;
00584 int d = (*mti).second;
00585
00586 LVector3 delta;
00587 _nurbs_result->eval_extended_points(u, v, d, &delta[0], 3);
00588 if (!delta.almost_equal(LVector3::zero())) {
00589 egg_vertex->_dxyzs.insert(EggMorphVertex(morph_name, LCAST(double, delta)));
00590 }
00591 }
00592
00593 for (mti = _drgba_table.begin(); mti != _drgba_table.end(); ++mti) {
00594 const string &morph_name = (*mti).first;
00595 int d = (*mti).second;
00596
00597 LVector4 delta;
00598 _nurbs_result->eval_extended_points(u, v, d, &delta[0], 4);
00599 if (!delta.almost_equal(LVector4::zero())) {
00600 egg_vertex->_drgbas.insert(EggMorphColor(morph_name, delta));
00601 }
00602 }
00603
00604 return egg_vertex;
00605 }