00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "graphicsOutput.h"
00016 #include "graphicsPipe.h"
00017 #include "graphicsEngine.h"
00018 #include "graphicsWindow.h"
00019 #include "config_display.h"
00020 #include "lightMutexHolder.h"
00021 #include "renderBuffer.h"
00022 #include "indirectLess.h"
00023 #include "pStatTimer.h"
00024 #include "configVariableBool.h"
00025 #include "camera.h"
00026 #include "displayRegion.h"
00027 #include "lens.h"
00028 #include "perspectiveLens.h"
00029 #include "pointerTo.h"
00030 #include "compassEffect.h"
00031 #include "geom.h"
00032 #include "geomNode.h"
00033 #include "geomTristrips.h"
00034 #include "geomVertexWriter.h"
00035 #include "throw_event.h"
00036 #include "config_gobj.h"
00037
00038 TypeHandle GraphicsOutput::_type_handle;
00039
00040 PStatCollector GraphicsOutput::_make_current_pcollector("Draw:Make current");
00041 PStatCollector GraphicsOutput::_copy_texture_pcollector("Draw:Copy texture");
00042 PStatCollector GraphicsOutput::_cull_pcollector("Cull");
00043 PStatCollector GraphicsOutput::_draw_pcollector("Draw");
00044
00045 struct CubeFaceDef {
00046 CubeFaceDef(const char *name, const LPoint3 &look_at, const LVector3 &up) :
00047 _name(name), _look_at(look_at), _up(up) { }
00048
00049 const char *_name;
00050 LPoint3 _look_at;
00051 LVector3 _up;
00052 };
00053
00054 static CubeFaceDef cube_faces[6] = {
00055 CubeFaceDef("positive_x", LPoint3(1, 0, 0), LVector3(0, -1, 0)),
00056 CubeFaceDef("negative_x", LPoint3(-1, 0, 0), LVector3(0, -1, 0)),
00057 CubeFaceDef("positive_y", LPoint3(0, 1, 0), LVector3(0, 0, 1)),
00058 CubeFaceDef("negative_y", LPoint3(0, -1, 0), LVector3(0, 0, -1)),
00059 CubeFaceDef("positive_z", LPoint3(0, 0, 1), LVector3(0, -1, 0)),
00060 CubeFaceDef("negative_z", LPoint3(0, 0, -1), LVector3(0, -1, 0))
00061 };
00062
00063
00064
00065
00066
00067
00068
00069
00070 GraphicsOutput::
00071 GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
00072 const string &name,
00073 const FrameBufferProperties &fb_prop,
00074 const WindowProperties &win_prop,
00075 int flags,
00076 GraphicsStateGuardian *gsg,
00077 GraphicsOutput *host,
00078 bool default_stereo_flags) :
00079 _lock("GraphicsOutput"),
00080 _cull_window_pcollector(_cull_pcollector, name),
00081 _draw_window_pcollector(_draw_pcollector, name)
00082 {
00083 #ifdef DO_MEMORY_USAGE
00084 MemoryUsage::update_type(this, this);
00085 #endif
00086 _engine = engine;
00087 _pipe = pipe;
00088 _gsg = gsg;
00089 _host = host;
00090 _fb_properties = fb_prop;
00091 _name = name;
00092 _creation_flags = flags;
00093 _x_size = _y_size = 0;
00094 _has_size = win_prop.has_size();
00095 _is_nonzero_size = false;
00096 if (_has_size) {
00097 _x_size = win_prop.get_x_size();
00098 _y_size = win_prop.get_y_size();
00099 _is_nonzero_size = (_x_size > 0 && _y_size > 0);
00100 }
00101 if (_creation_flags & GraphicsPipe::BF_size_track_host) {
00102
00103
00104 _is_nonzero_size = true;
00105 }
00106
00107 _is_valid = false;
00108 _flip_ready = false;
00109 _cube_map_index = -1;
00110 _cube_map_dr = NULL;
00111 _sort = 0;
00112 _child_sort = 0;
00113 _got_child_sort = false;
00114 _internal_sort_index = 0;
00115 _inverted = window_inverted;
00116 _swap_eyes = swap_eyes;
00117 _red_blue_stereo = false;
00118 _left_eye_color_mask = 0x0f;
00119 _right_eye_color_mask = 0x0f;
00120 _side_by_side_stereo = false;
00121 _sbs_left_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
00122 _sbs_right_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
00123 _delete_flag = false;
00124 _texture_card = 0;
00125 _trigger_copy = false;
00126
00127 if (_fb_properties.is_single_buffered()) {
00128 _draw_buffer_type = RenderBuffer::T_front;
00129 } else {
00130 _draw_buffer_type = RenderBuffer::T_back;
00131 }
00132
00133 if (default_stereo_flags) {
00134
00135
00136 _red_blue_stereo = red_blue_stereo && !fb_prop.is_stereo();
00137 if (_red_blue_stereo) {
00138 _left_eye_color_mask = parse_color_mask(red_blue_stereo_colors.get_word(0));
00139 _right_eye_color_mask = parse_color_mask(red_blue_stereo_colors.get_word(1));
00140 }
00141 _side_by_side_stereo = side_by_side_stereo && !fb_prop.is_stereo();
00142 if (_side_by_side_stereo) {
00143 _sbs_left_dimensions.set(sbs_left_dimensions[0], sbs_left_dimensions[1],
00144 sbs_left_dimensions[2], sbs_left_dimensions[3]);
00145 _sbs_right_dimensions.set(sbs_right_dimensions[0], sbs_right_dimensions[1],
00146 sbs_right_dimensions[2], sbs_right_dimensions[3]);
00147 }
00148 }
00149
00150
00151
00152
00153 _overlay_display_region = make_mono_display_region(0.0f, 1.0f, 0.0f, 1.0f);
00154 _overlay_display_region->set_active(false);
00155
00156
00157 {
00158 CDWriter cdata(_cycler, true);
00159 cdata->_active = true;
00160 }
00161
00162
00163
00164 set_clear_color_active(true);
00165 set_clear_depth_active(true);
00166 set_clear_stencil_active(true);
00167
00168 switch (background_color.get_num_words()) {
00169 case 1:
00170 set_clear_color(LColor(background_color[0], background_color[0], background_color[0], 0.0f));
00171 break;
00172
00173 case 2:
00174 set_clear_color(LColor(background_color[0], background_color[0], background_color[0], background_color[1]));
00175 break;
00176
00177 case 3:
00178 set_clear_color(LColor(background_color[0], background_color[1], background_color[2], 0.0f));
00179 break;
00180
00181 case 4:
00182 set_clear_color(LColor(background_color[0], background_color[1], background_color[2], background_color[3]));
00183 break;
00184
00185 default:
00186 display_cat.warning()
00187 << "Invalid background-color specification: "
00188 << background_color.get_string_value() << "\n";
00189 }
00190 }
00191
00192
00193
00194
00195
00196
00197 GraphicsOutput::
00198 GraphicsOutput(const GraphicsOutput &) :
00199 _cull_window_pcollector(_cull_pcollector, "Invalid"),
00200 _draw_window_pcollector(_draw_pcollector, "Invalid")
00201 {
00202 nassertv(false);
00203 }
00204
00205
00206
00207
00208
00209
00210 void GraphicsOutput::
00211 operator = (const GraphicsOutput &) {
00212 nassertv(false);
00213 }
00214
00215
00216
00217
00218
00219
00220 GraphicsOutput::
00221 ~GraphicsOutput() {
00222
00223 nassertv(!is_valid());
00224
00225
00226 nassertv(_pipe == (GraphicsPipe *)NULL);
00227
00228
00229
00230
00231
00232 TotalDisplayRegions::iterator dri;
00233 for (dri = _total_display_regions.begin();
00234 dri != _total_display_regions.end();
00235 ++dri) {
00236 (*dri)->_window = NULL;
00237 }
00238
00239 _total_display_regions.clear();
00240 _overlay_display_region = NULL;
00241 }
00242
00243
00244
00245
00246
00247
00248
00249
00250 void GraphicsOutput::
00251 clear_render_textures() {
00252 CDWriter cdata(_cycler, true);
00253 cdata->_textures.clear();
00254 ++(cdata->_textures_seq);
00255 throw_event("render-texture-targets-changed");
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 void GraphicsOutput::
00300 add_render_texture(Texture *tex, RenderTextureMode mode,
00301 RenderTexturePlane plane) {
00302
00303 if (mode == RTM_none) {
00304 return;
00305 }
00306 LightMutexHolder holder(_lock);
00307
00308
00309 if (tex == (Texture *)NULL) {
00310 tex = new Texture(get_name());
00311 tex->set_wrap_u(Texture::WM_clamp);
00312 tex->set_wrap_v(Texture::WM_clamp);
00313 } else {
00314 tex->clear_ram_image();
00315 }
00316
00317
00318
00319
00320
00321 tex->set_compression(Texture::CM_off);
00322
00323
00324 if (plane == RTP_COUNT) {
00325 if (tex->get_format()==Texture::F_depth_stencil) {
00326 plane = RTP_depth_stencil;
00327 } else if (tex->get_format()==Texture::F_depth_component) {
00328 plane = RTP_depth;
00329 } else {
00330 plane = RTP_color;
00331 }
00332 }
00333
00334
00335
00336
00337 if (plane == RTP_depth) {
00338 tex->set_format(Texture::F_depth_component);
00339 tex->set_match_framebuffer_format(true);
00340 } else if (plane == RTP_depth_stencil) {
00341 tex->set_format(Texture::F_depth_stencil);
00342 tex->set_match_framebuffer_format(true);
00343 } else if ((plane == RTP_color)||
00344 (plane == RTP_aux_rgba_0)||
00345 (plane == RTP_aux_rgba_1)||
00346 (plane == RTP_aux_rgba_2)||
00347 (plane == RTP_aux_rgba_3)) {
00348 tex->set_format(Texture::F_rgba);
00349 tex->set_match_framebuffer_format(true);
00350 } else if ((plane == RTP_aux_hrgba_0)||
00351 (plane == RTP_aux_hrgba_1)||
00352 (plane == RTP_aux_hrgba_2)||
00353 (plane == RTP_aux_hrgba_3)) {
00354 tex->set_format(Texture::F_rgba16);
00355 tex->set_match_framebuffer_format(true);
00356 } else if ((plane == RTP_aux_float_0)||
00357 (plane == RTP_aux_float_1)||
00358 (plane == RTP_aux_float_2)||
00359 (plane == RTP_aux_float_3)) {
00360 tex->set_format(Texture::F_rgba32);
00361 tex->set_match_framebuffer_format(true);
00362 } else {
00363 display_cat.error() <<
00364 "add_render_texture: invalid bitplane specified.\n";
00365 return;
00366 }
00367
00368
00369
00370
00371 tex->set_size_padded(get_x_size(), get_y_size());
00372
00373 if (mode == RTM_bind_or_copy) {
00374 if (!support_render_texture || !get_supports_render_texture()) {
00375
00376
00377 mode = RTM_copy_texture;
00378 }
00379 }
00380
00381 if (mode == RTM_bind_or_copy) {
00382
00383
00384 tex->set_render_to_texture(true);
00385 }
00386
00387 CDWriter cdata(_cycler, true);
00388 RenderTexture result;
00389 result._texture = tex;
00390 result._plane = plane;
00391 result._rtm_mode = mode;
00392 cdata->_textures.push_back(result);
00393 ++(cdata->_textures_seq);
00394
00395 throw_event("render-texture-targets-changed");
00396 }
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407 void GraphicsOutput::
00408 setup_render_texture(Texture *tex, bool allow_bind, bool to_ram) {
00409 display_cat.warning() <<
00410 "Using deprecated setup_render_texture interface.\n";
00411 clear_render_textures();
00412 if (to_ram) {
00413 add_render_texture(tex, RTM_copy_ram);
00414 } else if (allow_bind) {
00415 add_render_texture(tex, RTM_bind_or_copy);
00416 } else {
00417 add_render_texture(tex, RTM_copy_texture);
00418 }
00419 }
00420
00421
00422
00423
00424
00425
00426
00427
00428 void GraphicsOutput::
00429 set_active(bool active) {
00430 CDLockedReader cdata(_cycler);
00431 if (cdata->_active != active) {
00432 CDWriter cdataw(((GraphicsOutput *)this)->_cycler, cdata, true);
00433 cdataw->_active = active;
00434 }
00435 }
00436
00437
00438
00439
00440
00441
00442
00443 bool GraphicsOutput::
00444 is_active() const {
00445 if (!is_valid()) {
00446 return false;
00447 }
00448
00449 CDReader cdata(_cycler);
00450 if (cdata->_one_shot_frame != -1) {
00451
00452
00453 if (cdata->_one_shot_frame != ClockObject::get_global_clock()->get_frame_count()) {
00454 return false;
00455 }
00456 }
00457 return cdata->_active;
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481 void GraphicsOutput::
00482 set_one_shot(bool one_shot) {
00483 CDWriter cdata(_cycler, true);
00484 if (one_shot) {
00485 cdata->_one_shot_frame = ClockObject::get_global_clock()->get_frame_count();
00486 } else {
00487 cdata->_one_shot_frame = -1;
00488 }
00489 }
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499 bool GraphicsOutput::
00500 get_one_shot() const {
00501 CDReader cdata(_cycler);
00502 return (cdata->_one_shot_frame == ClockObject::get_global_clock()->get_frame_count());
00503 }
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521 void GraphicsOutput::
00522 set_inverted(bool inverted) {
00523 if (_inverted != inverted) {
00524 _inverted = inverted;
00525
00526 if (_y_size != 0) {
00527
00528
00529 TotalDisplayRegions::iterator dri;
00530 for (dri = _total_display_regions.begin();
00531 dri != _total_display_regions.end();
00532 ++dri) {
00533 (*dri)->compute_pixels(_x_size, _y_size);
00534 }
00535 }
00536 }
00537 }
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556 void GraphicsOutput::
00557 set_side_by_side_stereo(bool side_by_side_stereo) {
00558 LVecBase4 left, right;
00559 left.set(sbs_left_dimensions[0], sbs_left_dimensions[1],
00560 sbs_left_dimensions[2], sbs_left_dimensions[3]);
00561 right.set(sbs_right_dimensions[0], sbs_right_dimensions[1],
00562 sbs_right_dimensions[2], sbs_right_dimensions[3]);
00563 set_side_by_side_stereo(side_by_side_stereo, left, right);
00564 }
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583 void GraphicsOutput::
00584 set_side_by_side_stereo(bool side_by_side_stereo,
00585 const LVecBase4 &sbs_left_dimensions,
00586 const LVecBase4 &sbs_right_dimensions) {
00587 _side_by_side_stereo = side_by_side_stereo;
00588 if (_side_by_side_stereo) {
00589 _sbs_left_dimensions = sbs_left_dimensions;
00590 _sbs_right_dimensions = sbs_right_dimensions;
00591 } else {
00592 _sbs_left_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
00593 _sbs_right_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
00594 }
00595 }
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605 bool GraphicsOutput::
00606 get_delete_flag() const {
00607
00608
00609 for (int i = 0; i < (int)_hold_textures.size(); i++) {
00610 if (_hold_textures[i].is_valid_pointer()) {
00611 return false;
00612 }
00613 }
00614
00615 return _delete_flag;
00616 }
00617
00618
00619
00620
00621
00622
00623
00624 void GraphicsOutput::
00625 set_sort(int sort) {
00626 if (_sort != sort) {
00627 if (_gsg != (GraphicsStateGuardian *)NULL &&
00628 _gsg->get_engine() != (GraphicsEngine *)NULL) {
00629 _gsg->get_engine()->set_window_sort(this, sort);
00630 }
00631 }
00632 }
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648 DisplayRegion *GraphicsOutput::
00649 make_display_region(const LVecBase4 &dimensions) {
00650 if (is_stereo() && default_stereo_camera) {
00651 return make_stereo_display_region(dimensions);
00652 } else {
00653 return make_mono_display_region(dimensions);
00654 }
00655 }
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671 DisplayRegion *GraphicsOutput::
00672 make_mono_display_region(const LVecBase4 &dimensions) {
00673 if (_side_by_side_stereo) {
00674 StereoDisplayRegion *dr = make_stereo_display_region(dimensions);
00675 dr->get_left_eye()->set_stereo_channel(Lens::SC_mono);
00676 dr->get_right_eye()->set_stereo_channel(Lens::SC_mono);
00677 return dr;
00678 }
00679
00680 return new DisplayRegion(this, dimensions);
00681 }
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 StereoDisplayRegion *GraphicsOutput::
00694 make_stereo_display_region(const LVecBase4 &dimensions) {
00695 PT(DisplayRegion) left, right;
00696
00697 if (_side_by_side_stereo) {
00698
00699
00700 PN_stdfloat left_l = _sbs_left_dimensions[0];
00701 PN_stdfloat left_b = _sbs_left_dimensions[2];
00702 PN_stdfloat left_w = _sbs_left_dimensions[1] - _sbs_left_dimensions[0];
00703 PN_stdfloat left_h = _sbs_left_dimensions[3] - _sbs_left_dimensions[2];
00704 LVecBase4 left_dimensions(dimensions[0] * left_w + left_l,
00705 dimensions[1] * left_w + left_l,
00706 dimensions[2] * left_h + left_b,
00707 dimensions[3] * left_h + left_b);
00708 left = new DisplayRegion(this, left_dimensions);
00709
00710 PN_stdfloat right_l = _sbs_right_dimensions[0];
00711 PN_stdfloat right_b = _sbs_right_dimensions[2];
00712 PN_stdfloat right_w = _sbs_right_dimensions[1] - _sbs_right_dimensions[0];
00713 PN_stdfloat right_h = _sbs_right_dimensions[3] - _sbs_right_dimensions[2];
00714 LVecBase4 right_dimensions(dimensions[0] * right_w + right_l,
00715 dimensions[1] * right_w + right_l,
00716 dimensions[2] * right_h + right_b,
00717 dimensions[3] * right_h + right_b);
00718 right = new DisplayRegion(this, right_dimensions);
00719
00720 if (_swap_eyes) {
00721 DisplayRegion *t = left;
00722 left = right;
00723 right = t;
00724 }
00725
00726 } else {
00727
00728
00729 left = new DisplayRegion(this, dimensions);
00730 right = new DisplayRegion(this, dimensions);
00731
00732
00733
00734
00735 if (get_clear_depth_active()) {
00736 right->set_clear_depth_active(true);
00737 }
00738 if (get_clear_stencil_active()) {
00739 right->set_clear_stencil_active(true);
00740 }
00741 }
00742
00743 PT(StereoDisplayRegion) stereo = new StereoDisplayRegion(this, dimensions,
00744 left, right);
00745
00746 return stereo;
00747 }
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758 bool GraphicsOutput::
00759 remove_display_region(DisplayRegion *display_region) {
00760 LightMutexHolder holder(_lock);
00761
00762 nassertr(display_region != _overlay_display_region, false);
00763
00764 if (display_region->is_stereo()) {
00765 StereoDisplayRegion *sdr;
00766 DCAST_INTO_R(sdr, display_region, false);
00767 do_remove_display_region(sdr->get_left_eye());
00768 do_remove_display_region(sdr->get_right_eye());
00769 }
00770
00771 return do_remove_display_region(display_region);
00772 }
00773
00774
00775
00776
00777
00778
00779
00780 void GraphicsOutput::
00781 remove_all_display_regions() {
00782 LightMutexHolder holder(_lock);
00783
00784 CDWriter cdata(_cycler, true);
00785 cdata->_active_display_regions_stale = true;
00786
00787 TotalDisplayRegions::iterator dri;
00788 for (dri = _total_display_regions.begin();
00789 dri != _total_display_regions.end();
00790 ++dri) {
00791 DisplayRegion *display_region = (*dri);
00792 if (display_region != _overlay_display_region) {
00793
00794 display_region->cleanup();
00795 display_region->_window = NULL;
00796 }
00797 }
00798 _total_display_regions.clear();
00799 _total_display_regions.push_back(_overlay_display_region);
00800 }
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821 void GraphicsOutput::
00822 set_overlay_display_region(DisplayRegion *display_region) {
00823 nassertv(display_region->get_window() == this);
00824 _overlay_display_region = display_region;
00825 }
00826
00827
00828
00829
00830
00831
00832
00833 int GraphicsOutput::
00834 get_num_display_regions() const {
00835 determine_display_regions();
00836 int result;
00837 {
00838 LightMutexHolder holder(_lock);
00839 result = _total_display_regions.size();
00840 }
00841 return result;
00842 }
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853 PT(DisplayRegion) GraphicsOutput::
00854 get_display_region(int n) const {
00855 determine_display_regions();
00856 PT(DisplayRegion) result;
00857 {
00858 LightMutexHolder holder(_lock);
00859 if (n >= 0 && n < (int)_total_display_regions.size()) {
00860 result = _total_display_regions[n];
00861 } else {
00862 result = NULL;
00863 }
00864 }
00865 return result;
00866 }
00867
00868
00869
00870
00871
00872
00873
00874 int GraphicsOutput::
00875 get_num_active_display_regions() const {
00876 determine_display_regions();
00877 CDReader cdata(_cycler);
00878 return cdata->_active_display_regions.size();
00879 }
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890 PT(DisplayRegion) GraphicsOutput::
00891 get_active_display_region(int n) const {
00892 determine_display_regions();
00893
00894 CDReader cdata(_cycler);
00895 if (n >= 0 && n < (int)cdata->_active_display_regions.size()) {
00896 return cdata->_active_display_regions[n];
00897 }
00898 return NULL;
00899 }
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934 GraphicsOutput *GraphicsOutput::
00935 make_texture_buffer(const string &name, int x_size, int y_size,
00936 Texture *tex, bool to_ram, FrameBufferProperties *fbp) {
00937
00938 FrameBufferProperties props;
00939 props.set_rgb_color(1);
00940 props.set_depth_bits(1);
00941
00942 if (fbp == NULL) {
00943 fbp = &props;
00944 }
00945
00946 int flags = GraphicsPipe::BF_refuse_window;
00947 if (textures_power_2 != ATS_none) {
00948 flags |= GraphicsPipe::BF_size_power_2;
00949 }
00950 if (tex != (Texture *)NULL &&
00951 tex->get_texture_type() == Texture::TT_cube_map) {
00952 flags |= GraphicsPipe::BF_size_square;
00953 }
00954
00955 GraphicsOutput *buffer = get_gsg()->get_engine()->
00956 make_output(get_gsg()->get_pipe(),
00957 name, get_child_sort(),
00958 *fbp, WindowProperties::size(x_size, y_size),
00959 flags, get_gsg(), get_host());
00960
00961 if (buffer != (GraphicsOutput *)NULL) {
00962 if (buffer->get_gsg() == (GraphicsStateGuardian *)NULL ||
00963 buffer->get_gsg()->get_prepared_objects() != get_gsg()->get_prepared_objects()) {
00964
00965
00966
00967 to_ram = true;
00968 }
00969
00970 buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_bind_or_copy);
00971 return buffer;
00972 }
00973
00974 return NULL;
00975 }
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999 GraphicsOutput *GraphicsOutput::
01000 make_cube_map(const string &name, int size, NodePath &camera_rig,
01001 DrawMask camera_mask, bool to_ram, FrameBufferProperties *fbp) {
01002 if (!to_ram) {
01003
01004
01005
01006 GraphicsStateGuardian *gsg = get_gsg();
01007 int max_dimension = gsg->get_max_cube_map_dimension();
01008 if (max_dimension == 0 || !gsg->get_supports_cube_map()) {
01009
01010 display_cat.warning()
01011 << "Cannot make dynamic cube map; GSG does not support cube maps.\n";
01012 return NULL;
01013 }
01014 if (max_dimension > 0) {
01015 size = min(max_dimension, size);
01016 }
01017 }
01018
01019
01020
01021
01022
01023
01024 camera_rig.node()->set_effect(CompassEffect::make(NodePath()));
01025
01026 PT(Texture) tex = new Texture(name);
01027 tex->setup_cube_map();
01028 tex->set_wrap_u(Texture::WM_clamp);
01029 tex->set_wrap_v(Texture::WM_clamp);
01030 GraphicsOutput *buffer;
01031
01032 buffer = make_texture_buffer(name, size, size, tex, to_ram, fbp);
01033
01034
01035
01036 buffer->set_clear_color_active(false);
01037 buffer->set_clear_depth_active(false);
01038 buffer->set_clear_stencil_active(false);
01039
01040 PT(Lens) lens = new PerspectiveLens;
01041 lens->set_fov(90.0f);
01042
01043 for (int i = 0; i < 6; i++) {
01044 PT(Camera) camera = new Camera(cube_faces[i]._name);
01045 camera->set_lens(lens);
01046 camera->set_camera_mask(camera_mask);
01047 NodePath camera_np = camera_rig.attach_new_node(camera);
01048 camera_np.look_at(cube_faces[i]._look_at, cube_faces[i]._up);
01049
01050 DisplayRegion *dr;
01051 dr = buffer->make_display_region();
01052
01053 dr->set_cube_map_index(i);
01054 dr->copy_clear_settings(*this);
01055 dr->set_camera(camera_np);
01056 }
01057
01058 return buffer;
01059 }
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078 NodePath GraphicsOutput::
01079 get_texture_card() {
01080 if (_texture_card == 0) {
01081 PT(GeomVertexData) vdata = create_texture_card_vdata(_x_size, _y_size);
01082 PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static);
01083 strip->set_shade_model(Geom::SM_uniform);
01084 strip->add_next_vertices(4);
01085 strip->close_primitive();
01086 _texture_card = new Geom(vdata);
01087 _texture_card->add_primitive(strip);
01088 }
01089
01090 PT(GeomNode) gnode = new GeomNode("texture card");
01091 gnode->add_geom(_texture_card);
01092 NodePath path(gnode);
01093
01094
01095
01096
01097
01098 CDReader cdata(_cycler);
01099 RenderTextures::const_iterator ri;
01100 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
01101 Texture *texture = (*ri)._texture;
01102 if ((texture->get_format() != Texture::F_depth_stencil)) {
01103 path.set_texture(texture, 0);
01104 break;
01105 }
01106 }
01107
01108 return path;
01109 }
01110
01111
01112
01113
01114
01115
01116
01117
01118 bool GraphicsOutput::
01119 share_depth_buffer(GraphicsOutput *graphics_output) {
01120 return false;
01121 }
01122
01123
01124
01125
01126
01127
01128 void GraphicsOutput::
01129 unshare_depth_buffer() {
01130 }
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140 bool GraphicsOutput::
01141 get_supports_render_texture() const {
01142 return false;
01143 }
01144
01145
01146
01147
01148
01149
01150
01151 bool GraphicsOutput::
01152 flip_ready() const {
01153 return _flip_ready;
01154 }
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165 GraphicsOutput *GraphicsOutput::
01166 get_host() {
01167 return this;
01168 }
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178 void GraphicsOutput::
01179 request_open() {
01180 }
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191 void GraphicsOutput::
01192 request_close() {
01193 }
01194
01195
01196
01197
01198
01199
01200
01201
01202 void GraphicsOutput::
01203 set_close_now() {
01204 }
01205
01206
01207
01208
01209
01210
01211
01212 void GraphicsOutput::
01213 reset_window(bool swapchain) {
01214 display_cat.info()
01215 << "Resetting " << get_type() << "\n";
01216 }
01217
01218
01219
01220
01221
01222
01223
01224
01225 void GraphicsOutput::
01226 clear_pipe() {
01227 _pipe = (GraphicsPipe *)NULL;
01228 }
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239 void GraphicsOutput::
01240 set_size_and_recalc(int x, int y) {
01241 _x_size = x;
01242 _y_size = y;
01243 _has_size = true;
01244
01245 _is_nonzero_size = (_x_size > 0 && _y_size > 0);
01246
01247 int fb_x_size = get_fb_x_size();
01248 int fb_y_size = get_fb_y_size();
01249
01250 TotalDisplayRegions::iterator dri;
01251 for (dri = _total_display_regions.begin();
01252 dri != _total_display_regions.end();
01253 ++dri) {
01254 (*dri)->compute_pixels_all_stages(fb_x_size, fb_y_size);
01255 }
01256
01257 if (_texture_card != 0) {
01258 _texture_card->set_vertex_data(create_texture_card_vdata(x, y));
01259 }
01260 }
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272 void GraphicsOutput::
01273 clear(Thread *current_thread) {
01274 if (is_any_clear_active()) {
01275 if (display_cat.is_spam()) {
01276 display_cat.spam()
01277 << "clear(): " << get_type() << " "
01278 << get_name() << " " << (void *)this << "\n";
01279 }
01280
01281 nassertv(_gsg != (GraphicsStateGuardian *)NULL);
01282
01283 DisplayRegionPipelineReader dr_reader(_overlay_display_region, current_thread);
01284 _gsg->prepare_display_region(&dr_reader);
01285 _gsg->clear(this);
01286 }
01287 }
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298 bool GraphicsOutput::
01299 begin_frame(FrameMode mode, Thread *current_thread) {
01300 return false;
01301 }
01302
01303
01304
01305
01306
01307
01308
01309
01310 void GraphicsOutput::
01311 end_frame(FrameMode mode, Thread *current_thread) {
01312 }
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323 void GraphicsOutput::
01324 change_scenes(DisplayRegionPipelineReader *new_dr) {
01325 int new_cube_map_index = new_dr->get_cube_map_index();
01326 if (new_cube_map_index != -1 &&
01327 new_cube_map_index != _cube_map_index) {
01328 int old_cube_map_index = _cube_map_index;
01329 DisplayRegion *old_cube_map_dr = _cube_map_dr;
01330 _cube_map_index = new_cube_map_index;
01331 _cube_map_dr = new_dr->get_object();
01332
01333 CDReader cdata(_cycler);
01334 RenderTextures::const_iterator ri;
01335 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
01336 RenderTextureMode rtm_mode = (*ri)._rtm_mode;
01337 Texture *texture = (*ri)._texture;
01338 if (rtm_mode != RTM_none) {
01339 if (rtm_mode == RTM_bind_or_copy) {
01340
01341
01342
01343
01344 select_cube_map(new_cube_map_index);
01345
01346 } else if (old_cube_map_index != -1) {
01347
01348
01349 nassertv(old_cube_map_dr != (DisplayRegion *)NULL);
01350 if (display_cat.is_debug()) {
01351 display_cat.debug()
01352 << "Copying texture for " << get_name() << " at scene change.\n";
01353 display_cat.debug()
01354 << "cube_map_index = " << old_cube_map_index << "\n";
01355 }
01356 RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type(),
01357 get_fb_properties());
01358 if (rtm_mode == RTM_copy_ram) {
01359 _gsg->framebuffer_copy_to_ram(texture, old_cube_map_index,
01360 old_cube_map_dr, buffer);
01361 } else {
01362 _gsg->framebuffer_copy_to_texture(texture, old_cube_map_index,
01363 old_cube_map_dr, buffer);
01364 }
01365 }
01366 }
01367 }
01368 }
01369 }
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380 void GraphicsOutput::
01381 select_cube_map(int) {
01382 }
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398 void GraphicsOutput::
01399 begin_flip() {
01400 }
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413 void GraphicsOutput::
01414 ready_flip() {
01415 }
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427 void GraphicsOutput::
01428 end_flip() {
01429 _flip_ready = false;
01430 }
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441 void GraphicsOutput::
01442 process_events() {
01443 }
01444
01445
01446
01447
01448
01449
01450 void GraphicsOutput::
01451 pixel_factor_changed() {
01452 if (_has_size) {
01453 set_size_and_recalc(_x_size, _y_size);
01454 }
01455 }
01456
01457
01458
01459
01460
01461
01462
01463 void GraphicsOutput::
01464 prepare_for_deletion() {
01465 CDWriter cdata(_cycler, true);
01466 cdata->_active = false;
01467
01468
01469
01470 RenderTextures::iterator ri;
01471 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
01472 if ((*ri)._rtm_mode == RTM_bind_or_copy) {
01473 _hold_textures.push_back((*ri)._texture);
01474 }
01475 }
01476 cdata->_textures.clear();
01477
01478 _delete_flag = true;
01479
01480
01481
01482
01483
01484 remove_all_display_regions();
01485 }
01486
01487
01488
01489
01490
01491
01492
01493 void GraphicsOutput::
01494 promote_to_copy_texture() {
01495 CDLockedReader cdata(_cycler);
01496 RenderTextures::const_iterator ri;
01497
01498 bool any_bind = false;
01499 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
01500 if ((*ri)._rtm_mode == RTM_bind_or_copy) {
01501 any_bind = true;
01502 break;
01503 }
01504 }
01505 if (any_bind) {
01506 CDWriter cdataw(((GraphicsOutput *)this)->_cycler, cdata, true);
01507 RenderTextures::iterator ri;
01508 for (ri = cdataw->_textures.begin(); ri != cdataw->_textures.end(); ++ri) {
01509 if ((*ri)._rtm_mode == RTM_bind_or_copy) {
01510 (*ri)._rtm_mode = RTM_copy_texture;
01511 }
01512 }
01513 }
01514 }
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526 bool GraphicsOutput::
01527 copy_to_textures() {
01528 bool okflag = true;
01529
01530 CDReader cdata(_cycler);
01531 RenderTextures::const_iterator ri;
01532 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
01533 RenderTextureMode rtm_mode = (*ri)._rtm_mode;
01534 if ((rtm_mode == RTM_none) || (rtm_mode == RTM_bind_or_copy)) {
01535 continue;
01536 }
01537
01538 Texture *texture = (*ri)._texture;
01539 PStatTimer timer(_copy_texture_pcollector);
01540
01541 if ((rtm_mode == RTM_copy_texture)||
01542 (rtm_mode == RTM_copy_ram)||
01543 ((rtm_mode == RTM_triggered_copy_texture)&&(_trigger_copy))||
01544 ((rtm_mode == RTM_triggered_copy_ram)&&(_trigger_copy))) {
01545 if (display_cat.is_debug()) {
01546 display_cat.debug()
01547 << "Copying texture for " << get_name() << " at frame end.\n";
01548 display_cat.debug()
01549 << "cube_map_index = " << _cube_map_index << "\n";
01550 }
01551 RenderTexturePlane plane = (*ri)._plane;
01552 RenderBuffer buffer(_gsg, DrawableRegion::get_renderbuffer_type(plane));
01553 if (plane == RTP_color) {
01554 buffer = _gsg->get_render_buffer(get_draw_buffer_type(),
01555 get_fb_properties());
01556 }
01557
01558 bool copied = false;
01559 if (_cube_map_dr != (DisplayRegion *)NULL) {
01560 if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
01561 copied =
01562 _gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
01563 _cube_map_dr, buffer);
01564 } else {
01565 copied =
01566 _gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
01567 _cube_map_dr, buffer);
01568 }
01569 } else {
01570 if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
01571 copied =
01572 _gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
01573 _overlay_display_region, buffer);
01574 } else {
01575 copied =
01576 _gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
01577 _overlay_display_region, buffer);
01578 }
01579 }
01580 if (!copied) {
01581 okflag = false;
01582 }
01583 }
01584 }
01585 _trigger_copy = false;
01586
01587 return okflag;
01588 }
01589
01590
01591
01592
01593
01594
01595 PT(GeomVertexData) GraphicsOutput::
01596 create_texture_card_vdata(int x, int y) {
01597 PN_stdfloat xhi = 1.0;
01598 PN_stdfloat yhi = 1.0;
01599
01600 if (Texture::get_textures_power_2() != ATS_none) {
01601 int xru = Texture::up_to_power_2(x);
01602 int yru = Texture::up_to_power_2(y);
01603 xhi = (x * 1.0f) / xru;
01604 yhi = (y * 1.0f) / yru;
01605 }
01606
01607 CPT(GeomVertexFormat) format = GeomVertexFormat::get_v3n3t2();
01608
01609 PT(GeomVertexData) vdata = new GeomVertexData
01610 ("card", format, Geom::UH_static);
01611
01612 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
01613 GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
01614 GeomVertexWriter normal(vdata, InternalName::get_normal());
01615
01616 vertex.add_data3(LVertex::rfu(-1.0f, 0.0f, 1.0f));
01617 vertex.add_data3(LVertex::rfu(-1.0f, 0.0f, -1.0f));
01618 vertex.add_data3(LVertex::rfu( 1.0f, 0.0f, 1.0f));
01619 vertex.add_data3(LVertex::rfu( 1.0f, 0.0f, -1.0f));
01620
01621 texcoord.add_data2( 0.0f, yhi);
01622 texcoord.add_data2( 0.0f, 0.0f);
01623 texcoord.add_data2( xhi, yhi);
01624 texcoord.add_data2( xhi, 0.0f);
01625
01626 normal.add_data3(LVector3::back());
01627 normal.add_data3(LVector3::back());
01628 normal.add_data3(LVector3::back());
01629 normal.add_data3(LVector3::back());
01630
01631 return vdata;
01632 }
01633
01634
01635
01636
01637
01638
01639
01640 DisplayRegion *GraphicsOutput::
01641 add_display_region(DisplayRegion *display_region) {
01642 LightMutexHolder holder(_lock);
01643 CDWriter cdata(_cycler, true);
01644 cdata->_active_display_regions_stale = true;
01645
01646 _total_display_regions.push_back(display_region);
01647
01648 return display_region;
01649 }
01650
01651
01652
01653
01654
01655
01656
01657 bool GraphicsOutput::
01658 do_remove_display_region(DisplayRegion *display_region) {
01659 nassertr(display_region != _overlay_display_region, false);
01660
01661 PT(DisplayRegion) drp = display_region;
01662 TotalDisplayRegions::iterator dri =
01663 find(_total_display_regions.begin(), _total_display_regions.end(), drp);
01664 if (dri != _total_display_regions.end()) {
01665
01666 CDWriter cdata(_cycler, true);
01667 display_region->cleanup();
01668 display_region->_window = NULL;
01669 _total_display_regions.erase(dri);
01670
01671 cdata->_active_display_regions_stale = true;
01672
01673 return true;
01674 }
01675
01676 return false;
01677 }
01678
01679
01680
01681
01682
01683
01684
01685 void GraphicsOutput::
01686 do_determine_display_regions(GraphicsOutput::CData *cdata) {
01687 cdata->_active_display_regions_stale = false;
01688
01689 cdata->_active_display_regions.clear();
01690 cdata->_active_display_regions.reserve(_total_display_regions.size());
01691
01692 int index = 0;
01693 TotalDisplayRegions::const_iterator dri;
01694 for (dri = _total_display_regions.begin();
01695 dri != _total_display_regions.end();
01696 ++dri) {
01697 DisplayRegion *display_region = (*dri);
01698 if (display_region->is_active()) {
01699 cdata->_active_display_regions.push_back(display_region);
01700 display_region->set_active_index(index);
01701 ++index;
01702 } else {
01703 display_region->set_active_index(-1);
01704 }
01705 }
01706
01707 stable_sort(cdata->_active_display_regions.begin(), cdata->_active_display_regions.end(), IndirectLess<DisplayRegion>());
01708 }
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719 unsigned int GraphicsOutput::
01720 parse_color_mask(const string &word) {
01721 unsigned int result = 0;
01722 vector_string components;
01723 tokenize(word, components, "|");
01724
01725 vector_string::const_iterator ci;
01726 for (ci = components.begin(); ci != components.end(); ++ci) {
01727 string w = downcase(*ci);
01728 if (w == "red" || w == "r") {
01729 result |= 0x001;
01730
01731 } else if (w == "green" || w == "g") {
01732 result |= 0x002;
01733
01734 } else if (w == "blue" || w == "b") {
01735 result |= 0x004;
01736
01737 } else if (w == "yellow" || w == "y") {
01738 result |= 0x003;
01739
01740 } else if (w == "magenta" || w == "m") {
01741 result |= 0x005;
01742
01743 } else if (w == "cyan" || w == "c") {
01744 result |= 0x006;
01745
01746 } else if (w == "alpha" || w == "a") {
01747 result |= 0x008;
01748
01749 } else if (w == "off") {
01750
01751 } else {
01752 display_cat.warning()
01753 << "Invalid color in red-blue-stereo-colors: " << (*ci) << "\n";
01754 }
01755 }
01756
01757 return result;
01758 }
01759
01760
01761
01762
01763
01764
01765 GraphicsOutput::CData::
01766 CData() {
01767
01768
01769
01770 _active = false;
01771 _one_shot_frame = -1;
01772 _active_display_regions_stale = false;
01773 }
01774
01775
01776
01777
01778
01779
01780 GraphicsOutput::CData::
01781 CData(const GraphicsOutput::CData ©) :
01782 _textures(copy._textures),
01783 _active(copy._active),
01784 _one_shot_frame(copy._one_shot_frame),
01785 _active_display_regions(copy._active_display_regions),
01786 _active_display_regions_stale(copy._active_display_regions_stale)
01787 {
01788 }
01789
01790
01791
01792
01793
01794
01795 CycleData *GraphicsOutput::CData::
01796 make_copy() const {
01797 return new CData(*this);
01798 }
01799
01800
01801
01802
01803
01804 ostream &
01805 operator << (ostream &out, GraphicsOutput::FrameMode fm) {
01806 switch (fm) {
01807 case GraphicsOutput::FM_render:
01808 return out << "render";
01809 case GraphicsOutput::FM_parasite:
01810 return out << "parasite";
01811 case GraphicsOutput::FM_refresh:
01812 return out << "refresh";
01813 }
01814
01815 return out << "(**invalid GraphicsOutput::FrameMode(" << (int)fm << ")**)";
01816 }