00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "nonlinearImager.h"
00020 #include "config_distort.h"
00021
00022 #include "graphicsStateGuardian.h"
00023 #include "matrixLens.h"
00024 #include "graphicsWindow.h"
00025 #include "graphicsEngine.h"
00026 #include "dcast.h"
00027
00028
00029
00030
00031
00032
00033 NonlinearImager::
00034 NonlinearImager() {
00035 _gsg = (GraphicsStateGuardian *)NULL;
00036 _stale = true;
00037 }
00038
00039
00040
00041
00042
00043
00044 NonlinearImager::
00045 ~NonlinearImager() {
00046 remove_all_screens();
00047 remove_all_viewers();
00048 }
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 int NonlinearImager::
00076 add_screen(ProjectionScreen *screen) {
00077 _screens.push_back(Screen());
00078 Screen &new_screen = _screens.back();
00079 new_screen._screen = screen;
00080 new_screen._texture = (Texture *)NULL;
00081 new_screen._tex_width = 256;
00082 new_screen._tex_height = 256;
00083 new_screen._active = true;
00084
00085
00086 size_t vi;
00087 for (vi = 0; vi < _viewers.size(); ++vi) {
00088 new_screen._meshes.push_back(Mesh());
00089 new_screen._meshes[vi]._last_screen = screen->get_last_screen();
00090 }
00091
00092 _stale = true;
00093 return _screens.size() - 1;
00094 }
00095
00096
00097
00098
00099
00100
00101
00102
00103 int NonlinearImager::
00104 find_screen(ProjectionScreen *screen) const {
00105 for (size_t i = 0; i < _screens.size(); i++) {
00106 if (_screens[i]._screen == screen) {
00107 return i;
00108 }
00109 }
00110
00111 return -1;
00112 }
00113
00114
00115
00116
00117
00118
00119
00120 void NonlinearImager::
00121 remove_screen(int index) {
00122 nassertv_always(index >= 0 && index < (int)_screens.size());
00123 Screen &screen = _screens[index];
00124 for (size_t vi = 0; vi < screen._meshes.size(); vi++) {
00125 screen._meshes[vi]._mesh.remove_node();
00126 }
00127 _screens.erase(_screens.begin() + index);
00128 }
00129
00130
00131
00132
00133
00134
00135 void NonlinearImager::
00136 remove_all_screens() {
00137 while (!_screens.empty()) {
00138 remove_screen(_screens.size() - 1);
00139 }
00140 }
00141
00142
00143
00144
00145
00146
00147
00148 int NonlinearImager::
00149 get_num_screens() const {
00150 return _screens.size();
00151 }
00152
00153
00154
00155
00156
00157
00158
00159 ProjectionScreen *NonlinearImager::
00160 get_screen(int index) const {
00161 nassertr(index >= 0 && index < (int)_screens.size(), (ProjectionScreen *)NULL);
00162 return _screens[index]._screen;
00163 }
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 void NonlinearImager::
00177 set_texture_size(int index, int width, int height) {
00178 nassertv(index >= 0 && index < (int)_screens.size());
00179 _screens[index]._tex_width = width;
00180 _screens[index]._tex_height = height;
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 void NonlinearImager::
00194 set_source_camera(int index, const NodePath &source_camera) {
00195 nassertv(index >= 0 && index < (int)_screens.size());
00196 nassertv(!source_camera.is_empty() &&
00197 source_camera.node()->is_of_type(Camera::get_class_type()));
00198 _screens[index]._source_camera = source_camera;
00199 }
00200
00201
00202
00203
00204
00205
00206
00207
00208 void NonlinearImager::
00209 set_screen_active(int index, bool active) {
00210 nassertv(index >= 0 && index < (int)_screens.size());
00211 _screens[index]._active = active;
00212
00213 if (!active) {
00214 Screen &screen = _screens[index];
00215
00216 for (size_t vi = 0; vi < screen._meshes.size(); vi++) {
00217 screen._meshes[vi]._mesh.remove_node();
00218 }
00219 screen._texture.clear();
00220 } else {
00221
00222 _stale = true;
00223 }
00224 }
00225
00226
00227
00228
00229
00230
00231 bool NonlinearImager::
00232 get_screen_active(int index) const {
00233 nassertr(index >= 0 && index < (int)_screens.size(), false);
00234 return _screens[index]._active;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 int NonlinearImager::
00259 add_viewer(DisplayRegion *dr) {
00260 GraphicsWindow *win = dr->get_window();
00261 GraphicsStateGuardian *gsg = win->get_gsg();
00262 nassertr(_viewers.empty() || (gsg == _gsg && win == _win), -1);
00263 _gsg = gsg;
00264 _win = win;
00265
00266 int previous_vi = find_viewer(dr);
00267 if (previous_vi >= 0) {
00268 return previous_vi;
00269 }
00270
00271 size_t vi = _viewers.size();
00272 _viewers.push_back(Viewer());
00273 Viewer &viewer = _viewers[vi];
00274
00275 viewer._dr = dr;
00276
00277
00278 viewer._viewer = dr->get_camera();
00279 if (viewer._viewer.is_empty()) {
00280 viewer._viewer_node = (LensNode *)NULL;
00281 } else {
00282 viewer._viewer_node = DCAST(LensNode, viewer._viewer.node());
00283 }
00284
00285
00286
00287 viewer._internal_camera = new Camera("NonlinearImager");
00288 viewer._internal_camera->set_lens(new MatrixLens);
00289 viewer._internal_scene = NodePath("screens");
00290 viewer._internal_camera->set_scene(viewer._internal_scene);
00291
00292 NodePath camera_np = viewer._internal_scene.attach_new_node(viewer._internal_camera);
00293 viewer._dr->set_camera(camera_np);
00294
00295
00296
00297
00298 viewer._internal_scene.set_two_sided(0);
00299
00300
00301 Screens::iterator si;
00302 for (si = _screens.begin(); si != _screens.end(); ++si) {
00303 Screen &screen = (*si);
00304 screen._meshes.push_back(Mesh());
00305 nassertr(screen._meshes.size() == _viewers.size(), -1);
00306 }
00307
00308 _stale = true;
00309 return vi;
00310 }
00311
00312
00313
00314
00315
00316
00317
00318
00319 int NonlinearImager::
00320 find_viewer(DisplayRegion *dr) const {
00321 for (size_t vi = 0; vi < _viewers.size(); vi++) {
00322 if (_viewers[vi]._dr == dr) {
00323 return vi;
00324 }
00325 }
00326
00327 return -1;
00328 }
00329
00330
00331
00332
00333
00334
00335
00336 void NonlinearImager::
00337 remove_viewer(int index) {
00338 nassertv_always(index >= 0 && index < (int)_viewers.size());
00339 Viewer &viewer = _viewers[index];
00340 viewer._internal_camera->set_scene(NodePath());
00341 viewer._dr->set_camera(viewer._viewer);
00342
00343
00344 Screens::iterator si;
00345 for (si = _screens.begin(); si != _screens.end(); ++si) {
00346 Screen &screen = (*si);
00347 nassertv(index < (int)screen._meshes.size());
00348 screen._meshes[index]._mesh.remove_node();
00349 screen._meshes.erase(screen._meshes.begin() + index);
00350 }
00351
00352 _viewers.erase(_viewers.begin() + index);
00353 }
00354
00355
00356
00357
00358
00359
00360 void NonlinearImager::
00361 remove_all_viewers() {
00362 while (!_viewers.empty()) {
00363 remove_viewer(_viewers.size() - 1);
00364 }
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 void NonlinearImager::
00385 set_viewer_camera(int index, const NodePath &viewer_camera) {
00386 nassertv(index >= 0 && index < (int)_viewers.size());
00387 nassertv(!viewer_camera.is_empty() &&
00388 viewer_camera.node()->is_of_type(LensNode::get_class_type()));
00389 Viewer &viewer = _viewers[index];
00390 viewer._viewer = viewer_camera;
00391 viewer._viewer_node = DCAST(LensNode, viewer_camera.node());
00392 _stale = true;
00393 }
00394
00395
00396
00397
00398
00399
00400
00401 NodePath NonlinearImager::
00402 get_viewer_camera(int index) const {
00403 nassertr(index >= 0 && index < (int)_viewers.size(), NodePath());
00404 return _viewers[index]._viewer;
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414 NodePath NonlinearImager::
00415 get_internal_scene(int index) const {
00416 nassertr(index >= 0 && index < (int)_viewers.size(), NodePath());
00417 return _viewers[index]._internal_scene;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426 int NonlinearImager::
00427 get_num_viewers() const {
00428 return _viewers.size();
00429 }
00430
00431
00432
00433
00434
00435
00436
00437 DisplayRegion *NonlinearImager::
00438 get_viewer(int index) const {
00439 nassertr(index >= 0 && index < (int)_viewers.size(), (DisplayRegion *)NULL);
00440 return _viewers[index]._dr;
00441 }
00442
00443
00444
00445
00446
00447
00448 void NonlinearImager::
00449 recompute() {
00450
00451 Screens::iterator si;
00452 for (si = _screens.begin(); si != _screens.end(); ++si) {
00453 Screen &screen = (*si);
00454 screen._texture.clear();
00455 }
00456
00457 size_t vi;
00458 for (vi = 0; vi < _viewers.size(); ++vi) {
00459 Viewer &viewer = _viewers[vi];
00460
00461 for (si = _screens.begin(); si != _screens.end(); ++si) {
00462 Screen &screen = (*si);
00463 if (screen._active) {
00464 recompute_screen(screen, vi);
00465 }
00466 }
00467
00468 if (viewer._viewer_node != (LensNode *)NULL &&
00469 viewer._viewer_node->get_lens() != (Lens *)NULL) {
00470 viewer._viewer_lens_change =
00471 viewer._viewer_node->get_lens()->get_last_change();
00472 }
00473 }
00474
00475 _stale = false;
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488 void NonlinearImager::
00489 render(GraphicsEngine *engine) {
00490 recompute_if_stale();
00491
00492 Screens::iterator si;
00493 for (si = _screens.begin(); si != _screens.end(); ++si) {
00494 if ((*si)._active) {
00495 render_screen(engine, *si);
00496 }
00497 }
00498 }
00499
00500
00501
00502
00503
00504
00505 void NonlinearImager::
00506 recompute_if_stale() {
00507 if (_stale) {
00508 recompute();
00509 } else {
00510 size_t vi;
00511 for (vi = 0; vi < _viewers.size(); ++vi) {
00512 Viewer &viewer = _viewers[vi];
00513 if (viewer._viewer_node != (LensNode *)NULL) {
00514 UpdateSeq lens_change =
00515 viewer._viewer_node->get_lens()->get_last_change();
00516 if (lens_change != viewer._viewer_lens_change) {
00517
00518
00519 Screens::iterator si;
00520 for (si = _screens.begin(); si != _screens.end(); ++si) {
00521 Screen &screen = (*si);
00522 if (screen._active) {
00523 recompute_screen(screen, vi);
00524 }
00525 }
00526
00527 } else {
00528
00529
00530 Screens::iterator si;
00531 for (si = _screens.begin(); si != _screens.end(); ++si) {
00532 Screen &screen = (*si);
00533 if (screen._active &&
00534 screen._meshes[vi]._last_screen != screen._screen->get_last_screen()) {
00535 recompute_screen(screen, vi);
00536 }
00537 }
00538 }
00539 }
00540 }
00541 }
00542 }
00543
00544
00545
00546
00547
00548
00549
00550 void NonlinearImager::
00551 recompute_screen(NonlinearImager::Screen &screen, size_t vi) {
00552 nassertv(vi < screen._meshes.size());
00553 screen._meshes[vi]._mesh.remove_node();
00554 if (!screen._active) {
00555 return;
00556 }
00557
00558 Viewer &viewer = _viewers[vi];
00559 PT(PandaNode) mesh = screen._screen->make_flat_mesh(viewer._viewer);
00560 if (mesh != (PandaNode *)NULL) {
00561 screen._meshes[vi]._mesh = viewer._internal_scene.attach_new_node(mesh);
00562 }
00563
00564 if (screen._texture == (Texture *)NULL ||
00565 screen._texture->_pbuffer == (PixelBuffer *)NULL ||
00566 screen._texture->_pbuffer->get_xsize() != screen._tex_width ||
00567 screen._texture->_pbuffer->get_ysize() != screen._tex_height) {
00568 PT(Texture) texture = new Texture;
00569 texture->set_minfilter(Texture::FT_linear);
00570 texture->set_magfilter(Texture::FT_linear);
00571 texture->set_wrapu(Texture::WM_clamp);
00572 texture->set_wrapv(Texture::WM_clamp);
00573 texture->_pbuffer->set_xsize(screen._tex_width);
00574 texture->_pbuffer->set_ysize(screen._tex_height);
00575
00576 screen._texture = texture;
00577 }
00578
00579 screen._meshes[vi]._mesh.set_texture(screen._texture);
00580 screen._meshes[vi]._last_screen = screen._screen->get_last_screen();
00581 }
00582
00583
00584
00585
00586
00587
00588
00589 void NonlinearImager::
00590 render_screen(GraphicsEngine *engine, NonlinearImager::Screen &screen) {
00591 if (screen._source_camera.is_empty()) {
00592 distort_cat.error()
00593 << "No source camera specified for screen " << screen._screen->get_name()
00594 << "\n";
00595 return;
00596 }
00597
00598 nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00599
00600 screen._screen->recompute_if_stale();
00601
00602
00603
00604 PT(DisplayRegion) scratch_region =
00605 _win->make_scratch_display_region(screen._tex_width, screen._tex_height);
00606 scratch_region->set_camera(screen._source_camera);
00607 engine->render_subframe(_gsg, scratch_region, true);
00608
00609
00610
00611 screen._texture->copy(_gsg, scratch_region,
00612 _gsg->get_render_buffer(RenderBuffer::T_back));
00613
00614
00615
00616
00617 }