00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "projectionScreen.h"
00020 #include "geomNode.h"
00021 #include "geom.h"
00022 #include "geomTristrip.h"
00023 #include "transformState.h"
00024 #include "workingNodePath.h"
00025 #include "switchNode.h"
00026
00027 TypeHandle ProjectionScreen::_type_handle;
00028
00029
00030
00031
00032
00033
00034 ProjectionScreen::
00035 ProjectionScreen(const string &name) : PandaNode(name)
00036 {
00037 _invert_uvs = project_invert_uvs;
00038 _vignette_on = false;
00039 _vignette_color.set(0.0f, 0.0f, 0.0f, 1.0f);
00040 _frame_color.set(1.0f, 1.0f, 1.0f, 1.0f);
00041 _computed_rel_top_mat = false;
00042 _stale = true;
00043 }
00044
00045
00046
00047
00048
00049
00050 ProjectionScreen::
00051 ~ProjectionScreen() {
00052 }
00053
00054
00055
00056
00057
00058
00059 ProjectionScreen::
00060 ProjectionScreen(const ProjectionScreen ©) :
00061 PandaNode(copy),
00062 _projector(copy._projector),
00063 _projector_node(copy._projector_node),
00064 _vignette_on(copy._vignette_on),
00065 _vignette_color(copy._vignette_color),
00066 _frame_color(copy._frame_color)
00067 {
00068 _computed_rel_top_mat = false;
00069 _stale = true;
00070 }
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 PandaNode *ProjectionScreen::
00081 make_copy() const {
00082 return new ProjectionScreen(*this);
00083 }
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 bool ProjectionScreen::
00095 has_cull_callback() const {
00096 return true;
00097 }
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 bool ProjectionScreen::
00119 cull_callback(CullTraverser *, CullTraverserData &) {
00120 recompute_if_stale();
00121 return true;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 void ProjectionScreen::
00137 set_projector(const NodePath &projector) {
00138 _projector_node = (LensNode *)NULL;
00139 _projector = projector;
00140 if (!projector.is_empty()) {
00141 nassertv(projector.node()->is_of_type(LensNode::get_class_type()));
00142 _projector_node = DCAST(LensNode, projector.node());
00143 _stale = true;
00144 }
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 PT(GeomNode) ProjectionScreen::
00168 generate_screen(const NodePath &projector, const string &screen_name,
00169 int num_x_verts, int num_y_verts, float distance) {
00170 nassertr(!projector.is_empty() &&
00171 projector.node()->is_of_type(LensNode::get_class_type()),
00172 NULL);
00173 LensNode *projector_node = DCAST(LensNode, projector.node());
00174 nassertr(projector_node->get_lens() != NULL, NULL);
00175
00176
00177 LMatrix4f rel_mat;
00178 NodePath this_np(this);
00179 rel_mat = projector.get_mat(this_np);
00180
00181
00182
00183 int num_verts = num_x_verts * num_y_verts;
00184 Lens *lens = projector_node->get_lens();
00185 float t = (distance - lens->get_near()) / (lens->get_far() - lens->get_near());
00186
00187 PTA_Vertexf coords;
00188 coords.reserve(num_verts);
00189 float x_scale = 2.0f / (num_x_verts - 1);
00190 float y_scale = 2.0f / (num_y_verts - 1);
00191 for (int yi = 0; yi < num_y_verts; yi++) {
00192 for (int xi = 0; xi < num_x_verts; xi++) {
00193 LPoint2f film = LPoint2f((float)xi * x_scale - 1.0f,
00194 (float)yi * y_scale - 1.0f);
00195 LPoint3f near_point, far_point;
00196 lens->extrude(film, near_point, far_point);
00197
00198 LPoint3f point = near_point + t * (far_point - near_point);
00199 point = point * rel_mat;
00200
00201 coords.push_back(point);
00202 }
00203 }
00204 nassertr((int)coords.size() == num_verts, NULL);
00205
00206
00207
00208 int num_tstrips = (num_y_verts-1);
00209 int tstrip_length = 2*(num_x_verts-1)+2;
00210
00211 PTA_int lengths;
00212 PTA_ushort vindex;
00213
00214
00215
00216 lengths.reserve(num_tstrips);
00217 int n;
00218 for (n = 0; n < num_tstrips; n++) {
00219 lengths.push_back(tstrip_length);
00220 }
00221 nassertr((int)lengths.size() == num_tstrips, NULL);
00222
00223
00224
00225 vindex.reserve(num_tstrips * tstrip_length);
00226 n = 0;
00227 int ti, si;
00228 for (ti = 1; ti < num_y_verts; ti++) {
00229 vindex.push_back(ti * num_x_verts);
00230 for (si = 1; si < num_x_verts; si++) {
00231 vindex.push_back((ti - 1) * num_x_verts + (si-1));
00232 vindex.push_back(ti * num_x_verts + si);
00233 }
00234 vindex.push_back((ti - 1) * num_x_verts + (num_x_verts-1));
00235 }
00236 nassertr((int)vindex.size() == num_tstrips * tstrip_length, NULL);
00237
00238 GeomTristrip *geom = new GeomTristrip;
00239 geom->set_num_prims(num_tstrips);
00240 geom->set_lengths(lengths);
00241
00242 geom->set_coords(coords, G_PER_VERTEX, vindex);
00243
00244
00245 PTA_Colorf colors;
00246 colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
00247 geom->set_colors(colors, G_OVERALL);
00248
00249
00250 PT(GeomNode) geom_node = new GeomNode(screen_name);
00251 geom_node->add_geom(geom);
00252
00253 _stale = true;
00254 ++_last_screen;
00255 return geom_node;
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265 void ProjectionScreen::
00266 regenerate_screen(const NodePath &projector, const string &screen_name,
00267 int num_x_verts, int num_y_verts, float distance) {
00268
00269 remove_all_children();
00270
00271
00272 PT(GeomNode) geom_node =
00273 generate_screen(projector, screen_name, num_x_verts, num_y_verts,
00274 distance);
00275 add_child(geom_node);
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 PT(PandaNode) ProjectionScreen::
00298 make_flat_mesh(const NodePath &camera) {
00299 nassertr(!camera.is_empty() &&
00300 camera.node()->is_of_type(LensNode::get_class_type()),
00301 NULL);
00302 LensNode *camera_node = DCAST(LensNode, camera.node());
00303 nassertr(camera_node->get_lens() != (Lens *)NULL, NULL);
00304
00305
00306 recompute_if_stale();
00307
00308 PT(PandaNode) top = new PandaNode(get_name());
00309 NodePath this_np(this);
00310
00311 LMatrix4f rel_mat;
00312 bool computed_rel_mat = false;
00313 make_mesh_children(top, this_np, camera, rel_mat, computed_rel_mat);
00314
00315 return top;
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 void ProjectionScreen::
00332 recompute() {
00333 NodePath this_np(this);
00334 do_recompute(this_np);
00335 }
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 void ProjectionScreen::
00346 recompute_if_stale() {
00347 if (_projector_node != (LensNode *)NULL &&
00348 _projector_node->get_lens() != (Lens *)NULL) {
00349 UpdateSeq lens_change = _projector_node->get_lens()->get_last_change();
00350 if (_stale || lens_change != _projector_lens_change) {
00351 recompute();
00352
00353 } else {
00354
00355 NodePath this_np(this);
00356 const LMatrix4f &top_mat = this_np.get_mat(_projector);
00357 if (!_rel_top_mat.almost_equal(top_mat)) {
00358 _rel_top_mat = top_mat;
00359 _computed_rel_top_mat = true;
00360 do_recompute(this_np);
00361 }
00362 }
00363 }
00364 }
00365
00366
00367
00368
00369
00370
00371 void ProjectionScreen::
00372 do_recompute(const NodePath &this_np) {
00373 if (_projector_node != (LensNode *)NULL &&
00374 _projector_node->get_lens() != (Lens *)NULL) {
00375 _colors.clear();
00376 _colors.push_back(_vignette_color);
00377 _colors.push_back(_frame_color);
00378
00379 recompute_node(this_np, _rel_top_mat, _computed_rel_top_mat);
00380
00381 _computed_rel_top_mat = false;
00382
00383 _projector_lens_change = _projector_node->get_lens()->get_last_change();
00384 _stale = false;
00385 }
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 void ProjectionScreen::
00397 recompute_node(const WorkingNodePath &np, LMatrix4f &rel_mat,
00398 bool &computed_rel_mat) {
00399 PandaNode *node = np.node();
00400 if (node->is_geom_node()) {
00401 recompute_geom_node(np, rel_mat, computed_rel_mat);
00402 }
00403
00404 if (node->is_exact_type(SwitchNode::get_class_type())) {
00405
00406
00407
00408
00409 int i = DCAST(SwitchNode, node)->get_visible_child();
00410 if (i >= 0 && i < node->get_num_children()) {
00411 PandaNode *child = node->get_child(i);
00412 recompute_child(WorkingNodePath(np, child), rel_mat, computed_rel_mat);
00413 }
00414
00415 } else {
00416
00417 int num_children = node->get_num_children();
00418 for (int i = 0; i < num_children; i++) {
00419 PandaNode *child = node->get_child(i);
00420 recompute_child(WorkingNodePath(np, child), rel_mat, computed_rel_mat);
00421 }
00422 }
00423 }
00424
00425
00426
00427
00428
00429
00430
00431
00432 void ProjectionScreen::
00433 recompute_child(const WorkingNodePath &np, LMatrix4f &rel_mat,
00434 bool &computed_rel_mat) {
00435 PandaNode *child = np.node();
00436
00437 const TransformState *transform = child->get_transform();
00438 if (!transform->is_identity()) {
00439
00440
00441 LMatrix4f new_rel_mat;
00442 bool computed_new_rel_mat = false;
00443 recompute_node(np, new_rel_mat, computed_new_rel_mat);
00444
00445 } else {
00446
00447
00448 recompute_node(np, rel_mat, computed_rel_mat);
00449 }
00450 }
00451
00452
00453
00454
00455
00456
00457 void ProjectionScreen::
00458 recompute_geom_node(const WorkingNodePath &np, LMatrix4f &rel_mat,
00459 bool &computed_rel_mat) {
00460 GeomNode *node = DCAST(GeomNode, np.node());
00461 if (!computed_rel_mat) {
00462
00463 NodePath true_np = np.get_node_path();
00464 rel_mat = true_np.get_mat(_projector);
00465 computed_rel_mat = true;
00466 }
00467
00468 int num_geoms = node->get_num_geoms();
00469 for (int i = 0; i < num_geoms; i++) {
00470 Geom *geom = node->get_geom(i);
00471 recompute_geom(geom, rel_mat);
00472 }
00473 }
00474
00475
00476
00477
00478
00479
00480 void ProjectionScreen::
00481 recompute_geom(Geom *geom, const LMatrix4f &rel_mat) {
00482 static const LMatrix3f lens_to_uv
00483 (0.5f, 0.0f, 0.0f,
00484 0.0f, 0.5f, 0.0f,
00485 0.5f, 0.5f, 1.0f);
00486
00487 static const LMatrix3f lens_to_uv_inverted
00488 (0.5f, 0.0f, 0.0f,
00489 0.0f,-0.5f, 0.0f,
00490 0.5f, 0.5f, 1.0f);
00491
00492 PTA_TexCoordf uvs;
00493 PTA_ushort color_index;
00494 Lens *lens = _projector_node->get_lens();
00495 nassertv(lens != (Lens *)NULL);
00496
00497 const LMatrix3f &to_uv = _invert_uvs ? lens_to_uv_inverted : lens_to_uv;
00498
00499
00500 int num_vertices = geom->get_num_vertices();
00501 Geom::VertexIterator vi = geom->make_vertex_iterator();
00502
00503 for (int i = 0; i < num_vertices; i++) {
00504 const Vertexf &vert = geom->get_next_vertex(vi);
00505
00506
00507 LPoint2f film(0.0, 0.0);
00508 bool good = lens->project(vert * rel_mat, film);
00509
00510
00511
00512 uvs.push_back(film * to_uv);
00513
00514
00515
00516 if (_vignette_on) {
00517 color_index.push_back(good ? 1 : 0);
00518 }
00519 }
00520
00521
00522 geom->set_texcoords(uvs, G_PER_VERTEX);
00523
00524 if (_vignette_on) {
00525 geom->set_colors(_colors, G_PER_VERTEX, color_index);
00526 }
00527 }
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538 PandaNode *ProjectionScreen::
00539 make_mesh_node(PandaNode *result_parent, const WorkingNodePath &np,
00540 const NodePath &camera,
00541 LMatrix4f &rel_mat, bool &computed_rel_mat) {
00542 PandaNode *node = np.node();
00543 if (!node->safe_to_flatten()) {
00544
00545
00546 return NULL;
00547 }
00548
00549 PT(PandaNode) new_node;
00550 if (node->is_geom_node()) {
00551 new_node = make_mesh_geom_node(np, camera, rel_mat, computed_rel_mat);
00552 } else {
00553 new_node = node->make_copy();
00554 }
00555
00556
00557 result_parent->add_child(new_node);
00558 make_mesh_children(new_node, np, camera, rel_mat, computed_rel_mat);
00559 return new_node;
00560 }
00561
00562
00563
00564
00565
00566
00567
00568 void ProjectionScreen::
00569 make_mesh_children(PandaNode *new_node, const WorkingNodePath &np,
00570 const NodePath &camera,
00571 LMatrix4f &rel_mat, bool &computed_rel_mat) {
00572 PandaNode *node = np.node();
00573 int num_children = node->get_num_children();
00574 for (int i = 0; i < num_children; i++) {
00575 PandaNode *child = node->get_child(i);
00576 PandaNode *new_child;
00577
00578 const TransformState *transform = child->get_transform();
00579 if (!transform->is_identity()) {
00580
00581
00582 LMatrix4f new_rel_mat;
00583 bool computed_new_rel_mat = false;
00584 new_child = make_mesh_node(new_node, WorkingNodePath(np, child), camera,
00585 new_rel_mat, computed_new_rel_mat);
00586
00587 } else {
00588
00589
00590 new_child = make_mesh_node(new_node, WorkingNodePath(np, child), camera,
00591 rel_mat, computed_rel_mat);
00592 }
00593
00594
00595
00596 new_child->set_state(child->get_state());
00597 }
00598 }
00599
00600
00601
00602
00603
00604
00605
00606
00607 PT(GeomNode) ProjectionScreen::
00608 make_mesh_geom_node(const WorkingNodePath &np, const NodePath &camera,
00609 LMatrix4f &rel_mat, bool &computed_rel_mat) {
00610 GeomNode *node = DCAST(GeomNode, np.node());
00611 PT(GeomNode) new_node = new GeomNode(node->get_name());
00612 LensNode *lens_node = DCAST(LensNode, camera.node());
00613
00614 if (!computed_rel_mat) {
00615
00616 NodePath true_np = np.get_node_path();
00617 rel_mat = true_np.get_mat(camera);
00618 computed_rel_mat = true;
00619 }
00620
00621 int num_geoms = node->get_num_geoms();
00622 for (int i = 0; i < num_geoms; i++) {
00623 Geom *geom = node->get_geom(i);
00624 PT(Geom) new_geom =
00625 make_mesh_geom(geom, lens_node->get_lens(), rel_mat);
00626 if (new_geom != (Geom *)NULL) {
00627 new_node->add_geom(new_geom, node->get_geom_state(i));
00628 }
00629 }
00630
00631 return new_node;
00632 }
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642 PT(Geom) ProjectionScreen::
00643 make_mesh_geom(Geom *geom, Lens *lens, LMatrix4f &rel_mat) {
00644 Geom *new_geom = geom->make_copy();
00645 PT(Geom) result = new_geom;
00646
00647 PTA_Vertexf coords;
00648 GeomBindType bind;
00649 PTA_ushort vindex;
00650
00651 new_geom->get_coords(coords, bind, vindex);
00652
00653 PTA_Vertexf new_coords;
00654 new_coords.reserve(coords.size());
00655 for (int i = 0; i < (int)coords.size(); i++) {
00656 const Vertexf &vert = coords[i];
00657
00658
00659
00660 LPoint3f film(0.0f, 0.0f, 0.0f);
00661 lens->project(vert * rel_mat, film);
00662
00663 new_coords.push_back(film);
00664 }
00665
00666 new_geom->set_coords(new_coords, bind, vindex);
00667
00668 return result;
00669 }