graphicsOutput.cxx 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083
  1. // Filename: graphicsOutput.cxx
  2. // Created by: drose (06Feb04)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
  8. //
  9. // All use of this software is subject to the terms of the Panda 3d
  10. // Software license. You should have received a copy of this license
  11. // along with this source code; you will also find a current copy of
  12. // the license at http://etc.cmu.edu/panda3d/docs/license/ .
  13. //
  14. // To contact the maintainers of this program write to
  15. // [email protected] .
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. #include "graphicsOutput.h"
  19. #include "graphicsPipe.h"
  20. #include "graphicsEngine.h"
  21. #include "graphicsWindow.h"
  22. #include "config_display.h"
  23. #include "mutexHolder.h"
  24. #include "renderBuffer.h"
  25. #include "indirectLess.h"
  26. #include "pStatTimer.h"
  27. #include "configVariableBool.h"
  28. #include "camera.h"
  29. #include "displayRegion.h"
  30. #include "lens.h"
  31. #include "perspectiveLens.h"
  32. #include "pointerTo.h"
  33. #include "compassEffect.h"
  34. TypeHandle GraphicsOutput::_type_handle;
  35. PStatCollector GraphicsOutput::_make_current_pcollector("Draw:Make current");
  36. PStatCollector GraphicsOutput::_copy_texture_pcollector("Draw:Copy texture");
  37. struct CubeFaceDef {
  38. CubeFaceDef(const char *name, const LPoint3f &look_at, const LVector3f &up) :
  39. _name(name), _look_at(look_at), _up(up) { }
  40. const char *_name;
  41. LPoint3f _look_at;
  42. LVector3f _up;
  43. };
  44. static CubeFaceDef cube_faces[6] = {
  45. CubeFaceDef("positive_x", LPoint3f(1, 0, 0), LVector3f(0, -1, 0)),
  46. CubeFaceDef("negative_x", LPoint3f(-1, 0, 0), LVector3f(0, -1, 0)),
  47. CubeFaceDef("positive_y", LPoint3f(0, 1, 0), LVector3f(0, 0, 1)),
  48. CubeFaceDef("negative_y", LPoint3f(0, -1, 0), LVector3f(0, 0, -1)),
  49. CubeFaceDef("positive_z", LPoint3f(0, 0, 1), LVector3f(0, -1, 0)),
  50. CubeFaceDef("negative_z", LPoint3f(0, 0, -1), LVector3f(0, -1, 0))
  51. };
  52. ////////////////////////////////////////////////////////////////////
  53. // Function: GraphicsOutput::Constructor
  54. // Access: Protected
  55. // Description: Normally, the GraphicsOutput constructor is not
  56. // called directly; these are created instead via the
  57. // GraphicsEngine::make_window() function.
  58. ////////////////////////////////////////////////////////////////////
  59. GraphicsOutput::
  60. GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
  61. const string &name) {
  62. #ifdef DO_MEMORY_USAGE
  63. MemoryUsage::update_type(this, this);
  64. #endif
  65. _pipe = pipe;
  66. _gsg = gsg;
  67. _name = name;
  68. _x_size = 0;
  69. _y_size = 0;
  70. _has_size = false;
  71. _is_valid = false;
  72. _rtm_mode = RTM_none;
  73. _flip_ready = false;
  74. _needs_context = true;
  75. _cube_map_index = -1;
  76. _sort = 0;
  77. _internal_sort_index = 0;
  78. _active = true;
  79. _one_shot = false;
  80. _inverted = window_inverted;
  81. _delete_flag = false;
  82. int mode = gsg->get_properties().get_frame_buffer_mode();
  83. if ((mode & FrameBufferProperties::FM_buffer) == FrameBufferProperties::FM_single_buffer) {
  84. // Single buffered; we must draw into the front buffer.
  85. _draw_buffer_type = RenderBuffer::T_front;
  86. }
  87. // We start out with one DisplayRegion that covers the whole window,
  88. // which we may use internally for full-window operations like
  89. // clear() and get_screenshot().
  90. _default_display_region = make_display_region(0.0f, 1.0f, 0.0f, 1.0f);
  91. _default_display_region->set_active(false);
  92. _display_regions_stale = false;
  93. // By default, each new GraphicsOutput is set up to clear color and
  94. // depth.
  95. set_clear_color_active(true);
  96. set_clear_depth_active(true);
  97. switch (background_color.get_num_words()) {
  98. case 1:
  99. set_clear_color(Colorf(background_color[0], background_color[0], background_color[0], 0.0f));
  100. break;
  101. case 2:
  102. set_clear_color(Colorf(background_color[0], background_color[0], background_color[0], background_color[1]));
  103. break;
  104. case 3:
  105. set_clear_color(Colorf(background_color[0], background_color[1], background_color[2], 0.0f));
  106. break;
  107. case 4:
  108. set_clear_color(Colorf(background_color[0], background_color[1], background_color[2], background_color[3]));
  109. break;
  110. default:
  111. display_cat.warning()
  112. << "Invalid background-color specification: "
  113. << background_color.get_string_value() << "\n";
  114. }
  115. }
  116. ////////////////////////////////////////////////////////////////////
  117. // Function: GraphicsOutput::Copy Constructor
  118. // Access: Private
  119. // Description:
  120. ////////////////////////////////////////////////////////////////////
  121. GraphicsOutput::
  122. GraphicsOutput(const GraphicsOutput &) {
  123. nassertv(false);
  124. }
  125. ////////////////////////////////////////////////////////////////////
  126. // Function: GraphicsOutput::Copy Assignment Operator
  127. // Access: Private
  128. // Description:
  129. ////////////////////////////////////////////////////////////////////
  130. void GraphicsOutput::
  131. operator = (const GraphicsOutput &) {
  132. nassertv(false);
  133. }
  134. ////////////////////////////////////////////////////////////////////
  135. // Function: GraphicsOutput::Destructor
  136. // Access: Published, Virtual
  137. // Description:
  138. ////////////////////////////////////////////////////////////////////
  139. GraphicsOutput::
  140. ~GraphicsOutput() {
  141. // The window should be closed by the time we destruct.
  142. nassertv(!is_valid());
  143. // We shouldn't have a GraphicsPipe pointer anymore.
  144. nassertv(_pipe == (GraphicsPipe *)NULL);
  145. // We don't have to destruct our child display regions explicitly,
  146. // since they are all reference-counted and will go away when their
  147. // pointers do. However, we do need to zero out their pointers to
  148. // us.
  149. TotalDisplayRegions::iterator dri;
  150. for (dri = _total_display_regions.begin();
  151. dri != _total_display_regions.end();
  152. ++dri) {
  153. (*dri)->_window = NULL;
  154. }
  155. _total_display_regions.clear();
  156. _active_display_regions.clear();
  157. _default_display_region = NULL;
  158. }
  159. ////////////////////////////////////////////////////////////////////
  160. // Function: GraphicsOutput::setup_render_texture
  161. // Access: Published
  162. // Description: Creates a new Texture object, suitable for rendering
  163. // the contents of this buffer into, and stores it in
  164. // _texture. This also disassociates the previous
  165. // texture (if any).
  166. //
  167. // If tex is not NULL, it is the texture that will be
  168. // set up for rendering into; otherwise, a new Texture
  169. // object will be created (in which case you may call
  170. // get_texture() to retrieve the new texture pointer
  171. // later).
  172. //
  173. // If allow_bind is true, and this GraphicsOutput is an
  174. // offscreen graphics buffer that has not yet been
  175. // rendered into, it will attempt to set up the buffer
  176. // for rendering directly into the texture, avoiding the
  177. // cost of the copy-to-texture-memory each frame. This
  178. // is not supported by all graphics hardware, but if it
  179. // is not supported, this option is quietly ignored.
  180. //
  181. // If to_ram is true, the texture image will be
  182. // downloaded from the framebuffer memory into system
  183. // RAM each frame, which is more expensive but allows
  184. // the texture to subsequently be applied to any GSG.
  185. // Otherwise, the texture image remains in texture
  186. // memory only.
  187. //
  188. // Also see make_texture_buffer(), which is a
  189. // higher-level interface for preparing
  190. // render-to-a-texture mode.
  191. ////////////////////////////////////////////////////////////////////
  192. void GraphicsOutput::
  193. setup_render_texture(Texture *tex, bool allow_bind, bool to_ram) {
  194. MutexHolder holder(_lock);
  195. if (tex == (Texture *)NULL) {
  196. _texture = new Texture(get_name());
  197. _texture->set_wrap_u(Texture::WM_clamp);
  198. _texture->set_wrap_v(Texture::WM_clamp);
  199. } else {
  200. _texture = tex;
  201. _texture->clear_ram_image();
  202. }
  203. _texture->set_match_framebuffer_format(true);
  204. // Go ahead and tell the texture our anticipated size, even if it
  205. // might be inaccurate (particularly if this is a GraphicsWindow,
  206. // which has system-imposed restrictions on size).
  207. _texture->set_x_size(get_x_size());
  208. _texture->set_y_size(get_y_size());
  209. if (to_ram) {
  210. _rtm_mode = RTM_copy_ram;
  211. } else if (allow_bind) {
  212. _rtm_mode = RTM_bind_if_possible;
  213. } else {
  214. _rtm_mode = RTM_copy_texture;
  215. }
  216. nassertv(_gsg != (GraphicsStateGuardian *)NULL);
  217. set_inverted(_gsg->get_copy_texture_inverted());
  218. }
  219. ////////////////////////////////////////////////////////////////////
  220. // Function: GraphicsOutput::set_active
  221. // Access: Published
  222. // Description: Sets the active flag associated with the
  223. // GraphicsOutput. If the GraphicsOutput is marked
  224. // inactive, nothing is rendered.
  225. ////////////////////////////////////////////////////////////////////
  226. void GraphicsOutput::
  227. set_active(bool active) {
  228. _active = active;
  229. }
  230. ////////////////////////////////////////////////////////////////////
  231. // Function: GraphicsOutput::is_active
  232. // Access: Published, Virtual
  233. // Description: Returns true if the window is ready to be rendered
  234. // into, false otherwise.
  235. ////////////////////////////////////////////////////////////////////
  236. bool GraphicsOutput::
  237. is_active() const {
  238. return _active && is_valid();
  239. }
  240. ////////////////////////////////////////////////////////////////////
  241. // Function: GraphicsOutput::set_inverted
  242. // Access: Published
  243. // Description: Changes the current setting of the inverted flag.
  244. // When this is true, the scene is rendered into the
  245. // window upside-down and backwards, that is, inverted
  246. // as if viewed through a mirror placed on the floor.
  247. //
  248. // This is primarily intended to support DirectX (and a
  249. // few buggy OpenGL graphics drivers) that perform a
  250. // framebuffer-to-texture copy upside-down from the
  251. // usual OpenGL (and Panda) convention. Panda will
  252. // automatically set this flag for offscreen buffers on
  253. // hardware that is known to do this, to compensate when
  254. // rendering offscreen into a texture.
  255. ////////////////////////////////////////////////////////////////////
  256. void GraphicsOutput::
  257. set_inverted(bool inverted) {
  258. if (_inverted != inverted) {
  259. _inverted = inverted;
  260. if (_y_size != 0) {
  261. // All of our DisplayRegions need to recompute their pixel
  262. // positions now.
  263. TotalDisplayRegions::iterator dri;
  264. for (dri = _total_display_regions.begin();
  265. dri != _total_display_regions.end();
  266. ++dri) {
  267. (*dri)->compute_pixels(_x_size, _y_size);
  268. }
  269. }
  270. }
  271. }
  272. ////////////////////////////////////////////////////////////////////
  273. // Function: GraphicsOutput::set_sort
  274. // Access: Published
  275. // Description: Adjusts the sorting order of this particular
  276. // GraphicsOutput, relative to other GraphicsOutputs.
  277. ////////////////////////////////////////////////////////////////////
  278. void GraphicsOutput::
  279. set_sort(int sort) {
  280. if (_sort != sort) {
  281. if (_gsg != (GraphicsStateGuardian *)NULL &&
  282. _gsg->get_engine() != (GraphicsEngine *)NULL) {
  283. _gsg->get_engine()->set_window_sort(this, sort);
  284. }
  285. }
  286. }
  287. ////////////////////////////////////////////////////////////////////
  288. // Function: GraphicsOutput::remove_display_region
  289. // Access: Published
  290. // Description: Removes the indicated DisplayRegion from the window,
  291. // and destructs it if there are no other references.
  292. //
  293. // Returns true if the DisplayRegion is found and
  294. // removed, false if it was not a part of the window.
  295. ////////////////////////////////////////////////////////////////////
  296. bool GraphicsOutput::
  297. remove_display_region(DisplayRegion *display_region) {
  298. MutexHolder holder(_lock);
  299. nassertr(display_region != _default_display_region, false);
  300. PT(DisplayRegion) drp = display_region;
  301. TotalDisplayRegions::iterator dri =
  302. find(_total_display_regions.begin(), _total_display_regions.end(), drp);
  303. if (dri != _total_display_regions.end()) {
  304. // Let's aggressively clean up the display region too.
  305. display_region->cleanup();
  306. display_region->_window = NULL;
  307. _total_display_regions.erase(dri);
  308. if (display_region->is_active()) {
  309. _display_regions_stale = true;
  310. }
  311. return true;
  312. }
  313. return false;
  314. }
  315. ////////////////////////////////////////////////////////////////////
  316. // Function: GraphicsOutput::remove_all_display_regions
  317. // Access: Published
  318. // Description: Removes all display regions from the window, except
  319. // the default one that is created with the window.
  320. ////////////////////////////////////////////////////////////////////
  321. void GraphicsOutput::
  322. remove_all_display_regions() {
  323. MutexHolder holder(_lock);
  324. TotalDisplayRegions::iterator dri;
  325. for (dri = _total_display_regions.begin();
  326. dri != _total_display_regions.end();
  327. ++dri) {
  328. DisplayRegion *display_region = (*dri);
  329. if (display_region != _default_display_region) {
  330. // Let's aggressively clean up the display region too.
  331. display_region->cleanup();
  332. display_region->_window = NULL;
  333. }
  334. }
  335. _total_display_regions.clear();
  336. _total_display_regions.push_back(_default_display_region);
  337. _display_regions_stale = true;
  338. }
  339. ////////////////////////////////////////////////////////////////////
  340. // Function: GraphicsOutput::get_num_display_regions
  341. // Access: Published
  342. // Description: Returns the number of DisplayRegions that have
  343. // been created within the window, active or otherwise.
  344. ////////////////////////////////////////////////////////////////////
  345. int GraphicsOutput::
  346. get_num_display_regions() const {
  347. determine_display_regions();
  348. int result;
  349. {
  350. MutexHolder holder(_lock);
  351. result = _total_display_regions.size();
  352. }
  353. return result;
  354. }
  355. ////////////////////////////////////////////////////////////////////
  356. // Function: GraphicsOutput::get_display_region
  357. // Access: Published
  358. // Description: Returns the nth DisplayRegion of those that have been
  359. // created within the window. This may return NULL if n
  360. // is out of bounds; particularly likely if the number
  361. // of display regions has changed since the last call to
  362. // get_num_display_regions().
  363. ////////////////////////////////////////////////////////////////////
  364. PT(DisplayRegion) GraphicsOutput::
  365. get_display_region(int n) const {
  366. determine_display_regions();
  367. PT(DisplayRegion) result;
  368. {
  369. MutexHolder holder(_lock);
  370. if (n >= 0 && n < (int)_total_display_regions.size()) {
  371. result = _total_display_regions[n];
  372. } else {
  373. result = NULL;
  374. }
  375. }
  376. return result;
  377. }
  378. ////////////////////////////////////////////////////////////////////
  379. // Function: GraphicsOutput::get_num_active_display_regions
  380. // Access: Published
  381. // Description: Returns the number of active DisplayRegions that have
  382. // been created within the window.
  383. ////////////////////////////////////////////////////////////////////
  384. int GraphicsOutput::
  385. get_num_active_display_regions() const {
  386. determine_display_regions();
  387. int result;
  388. {
  389. MutexHolder holder(_lock);
  390. result = _active_display_regions.size();
  391. }
  392. return result;
  393. }
  394. ////////////////////////////////////////////////////////////////////
  395. // Function: GraphicsOutput::get_active_display_region
  396. // Access: Published
  397. // Description: Returns the nth active DisplayRegion of those that
  398. // have been created within the window. This may return
  399. // NULL if n is out of bounds; particularly likely if
  400. // the number of display regions has changed since the
  401. // last call to get_num_active_display_regions().
  402. ////////////////////////////////////////////////////////////////////
  403. PT(DisplayRegion) GraphicsOutput::
  404. get_active_display_region(int n) const {
  405. determine_display_regions();
  406. PT(DisplayRegion) result;
  407. {
  408. MutexHolder holder(_lock);
  409. if (n >= 0 && n < (int)_active_display_regions.size()) {
  410. result = _active_display_regions[n];
  411. } else {
  412. result = NULL;
  413. }
  414. }
  415. return result;
  416. }
  417. ////////////////////////////////////////////////////////////////////
  418. // Function: GraphicsOutput::make_texture_buffer
  419. // Access: Published
  420. // Description: Creates and returns an offscreen buffer for rendering
  421. // into, the result of which will be a texture suitable
  422. // for applying to geometry within the scene rendered
  423. // into this window.
  424. //
  425. // If tex is not NULL, it is the texture that will be
  426. // set up for rendering into; otherwise, a new Texture
  427. // object will be created. In either case, the target
  428. // texture can be retrieved from the return value with
  429. // buffer->get_texture() (assuming the return value is
  430. // not NULL).
  431. //
  432. // If to_ram is true, the buffer will be set up to
  433. // download its contents to the system RAM memory
  434. // associated with the Texture object, instead of
  435. // keeping it strictly within texture memory; this is
  436. // much slower, but it allows using the texture with any
  437. // GSG.
  438. //
  439. // This will attempt to be smart about maximizing render
  440. // performance while minimizing framebuffer waste. It
  441. // might return a GraphicsBuffer set to render directly
  442. // into a texture, if possible; or it might return a
  443. // ParasiteBuffer that renders into this window. The
  444. // return value is NULL if the buffer could not be
  445. // created for some reason.
  446. //
  447. // When you are done using the buffer, you should remove
  448. // it with a call to GraphicsEngine::remove_window() (or
  449. // set the one_shot flag so it removes itself after one
  450. // frame).
  451. ////////////////////////////////////////////////////////////////////
  452. GraphicsOutput *GraphicsOutput::
  453. make_texture_buffer(const string &name, int x_size, int y_size,
  454. Texture *tex, bool to_ram) {
  455. GraphicsStateGuardian *gsg = get_gsg();
  456. GraphicsEngine *engine = gsg->get_engine();
  457. GraphicsOutput *host = get_host();
  458. // The new buffer should be drawn before this buffer is drawn. If
  459. // the user requires more control than this, he can set the sort
  460. // value himself.
  461. int sort = get_sort() - 1;
  462. GraphicsOutput *buffer = NULL;
  463. if (show_buffers) {
  464. // If show_buffers is true, just go ahead and call make_buffer(),
  465. // since it all amounts to the same thing anyway--this will
  466. // actually create a new GraphicsWindow.
  467. buffer = engine->make_buffer(gsg, name, sort, x_size, y_size);
  468. buffer->setup_render_texture(tex, false, to_ram);
  469. return buffer;
  470. }
  471. bool allow_bind =
  472. (prefer_texture_buffer && support_render_texture &&
  473. gsg->get_supports_render_texture() && !to_ram);
  474. // If the user so indicated in the Config.prc file, try to create a
  475. // parasite buffer first. We can only do this if the requested size
  476. // fits within the available framebuffer size. Also, don't do this
  477. // if we want to try using render-to-a-texture mode, since using a
  478. // ParasiteButter will preclude that.
  479. if (prefer_parasite_buffer && !allow_bind &&
  480. (x_size <= host->get_x_size() && y_size <= host->get_y_size())) {
  481. buffer = engine->make_parasite(host, name, sort, x_size, y_size);
  482. if (buffer != (GraphicsOutput *)NULL) {
  483. buffer->setup_render_texture(tex, false, to_ram);
  484. return buffer;
  485. }
  486. }
  487. // Attempt to create a single-buffered offscreen buffer.
  488. if (prefer_single_buffer) {
  489. FrameBufferProperties sb_props = gsg->get_properties();
  490. int orig_mode = sb_props.get_frame_buffer_mode();
  491. int sb_mode = (orig_mode & ~FrameBufferProperties::FM_buffer) | FrameBufferProperties::FM_single_buffer;
  492. sb_props.set_frame_buffer_mode(sb_mode);
  493. if (sb_mode != orig_mode) {
  494. PT(GraphicsStateGuardian) sb_gsg =
  495. engine->make_gsg(gsg->get_pipe(), sb_props, gsg);
  496. if (sb_gsg != (GraphicsStateGuardian *)NULL) {
  497. buffer = engine->make_buffer(sb_gsg, name, sort, x_size, y_size);
  498. if (buffer != (GraphicsOutput *)NULL) {
  499. // Check the buffer for goodness.
  500. buffer->setup_render_texture(tex, allow_bind, to_ram);
  501. engine->open_windows();
  502. if (buffer->is_valid()) {
  503. return buffer;
  504. }
  505. // No good; delete the buffer and keep trying.
  506. bool removed = engine->remove_window(buffer);
  507. nassertr(removed, NULL);
  508. buffer = (GraphicsOutput *)NULL;
  509. }
  510. }
  511. }
  512. }
  513. // All right, attempt to create an offscreen buffer, using the same
  514. // GSG. This will be a double-buffered offscreen buffer, if the
  515. // source window is double-buffered.
  516. buffer = engine->make_buffer(gsg, name, sort, x_size, y_size);
  517. if (buffer != (GraphicsOutput *)NULL) {
  518. buffer->setup_render_texture(tex, allow_bind, to_ram);
  519. engine->open_windows();
  520. if (buffer->is_valid()) {
  521. return buffer;
  522. }
  523. bool removed = engine->remove_window(buffer);
  524. nassertr(removed, NULL);
  525. buffer = (GraphicsOutput *)NULL;
  526. }
  527. // Looks like we have to settle for a parasite buffer.
  528. if (x_size <= host->get_x_size() && y_size <= host->get_y_size()) {
  529. buffer = engine->make_parasite(host, name, sort, x_size, y_size);
  530. buffer->setup_render_texture(tex, false, to_ram);
  531. return buffer;
  532. }
  533. return NULL;
  534. }
  535. ////////////////////////////////////////////////////////////////////
  536. // Function: GraphicsOutput::make_cube_map
  537. // Access: Published
  538. // Description: This is similar to make_texture_buffer() in that it
  539. // allocates a separate buffer suitable for rendering to
  540. // a texture that can be assigned to geometry in this
  541. // window, but in this case, the buffer is set up to
  542. // render the six faces of a cube map.
  543. //
  544. // The buffer is automatically set up with six display
  545. // regions and six cameras, each of which are assigned
  546. // the indicated draw_mask and parented to the given
  547. // camera_rig node (which you should then put in your
  548. // scene to render the cube map from the appropriate
  549. // point of view).
  550. //
  551. // You may take the texture associated with the buffer
  552. // and apply it to geometry, particularly with
  553. // TexGenAttrib::M_world_cube_map also in effect, to
  554. // apply a reflection of everything seen by the camera
  555. // rig.
  556. ////////////////////////////////////////////////////////////////////
  557. GraphicsOutput *GraphicsOutput::
  558. make_cube_map(const string &name, int size, bool to_ram,
  559. NodePath &camera_rig, DrawMask camera_mask) {
  560. if (!to_ram) {
  561. // Check the limits imposed by the GSG. (However, if we're
  562. // rendering the texture to RAM only, these limits may be
  563. // irrelevant.)
  564. GraphicsStateGuardian *gsg = get_gsg();
  565. int max_dimension = gsg->get_max_cube_map_dimension();
  566. if (max_dimension == 0) {
  567. // The GSG doesn't support cube mapping; too bad for you.
  568. return NULL;
  569. }
  570. if (max_dimension > 0) {
  571. size = min(max_dimension, size);
  572. }
  573. }
  574. // Usually, we want the whole camera_rig to keep itself unrotated
  575. // with respect to the world coordinate space, so the user can apply
  576. // TexGenAttrib::M_world_cube_map to the objects on which the cube
  577. // map texture is applied. If for some reason the user doesn't want
  578. // this behavior, he can take this effect off again.
  579. camera_rig.node()->set_effect(CompassEffect::make(NodePath()));
  580. PT(Texture) tex = new Texture(name);
  581. tex->setup_cube_map();
  582. tex->set_wrap_u(Texture::WM_clamp);
  583. tex->set_wrap_v(Texture::WM_clamp);
  584. GraphicsOutput *buffer = make_texture_buffer(name, size, size, tex, to_ram);
  585. // We don't need to clear the overall buffer; instead, we'll clear
  586. // each display region.
  587. buffer->set_clear_color_active(false);
  588. buffer->set_clear_depth_active(false);
  589. PT(Lens) lens = new PerspectiveLens;
  590. lens->set_fov(90.0f);
  591. for (int i = 0; i < 6; i++) {
  592. PT(Camera) camera = new Camera(cube_faces[i]._name);
  593. camera->set_lens(lens);
  594. camera->set_camera_mask(camera_mask);
  595. NodePath camera_np = camera_rig.attach_new_node(camera);
  596. camera_np.look_at(cube_faces[i]._look_at, cube_faces[i]._up);
  597. DisplayRegion *dr = buffer->make_display_region();
  598. dr->set_cube_map_index(i);
  599. dr->copy_clear_settings(*this);
  600. dr->set_camera(camera_np);
  601. }
  602. return buffer;
  603. }
  604. ////////////////////////////////////////////////////////////////////
  605. // Function: GraphicsOutput::get_host
  606. // Access: Public, Virtual
  607. // Description: This is normally called only from within
  608. // make_texture_buffer(). When called on a
  609. // ParasiteBuffer, it returns the host of that buffer;
  610. // but when called on some other buffer, it returns the
  611. // buffer itself.
  612. ////////////////////////////////////////////////////////////////////
  613. GraphicsOutput *GraphicsOutput::
  614. get_host() {
  615. return this;
  616. }
  617. ////////////////////////////////////////////////////////////////////
  618. // Function: GraphicsOutput::request_open
  619. // Access: Public, Virtual
  620. // Description: This is called by the GraphicsEngine to request that
  621. // the window (or whatever) open itself or, in general,
  622. // make itself valid, at the next call to
  623. // process_events().
  624. ////////////////////////////////////////////////////////////////////
  625. void GraphicsOutput::
  626. request_open() {
  627. }
  628. ////////////////////////////////////////////////////////////////////
  629. // Function: GraphicsOutput::request_close
  630. // Access: Public, Virtual
  631. // Description: This is called by the GraphicsEngine to request that
  632. // the window (or whatever) close itself or, in general,
  633. // make itself invalid, at the next call to
  634. // process_events(). By that time we promise the gsg
  635. // pointer will be cleared.
  636. ////////////////////////////////////////////////////////////////////
  637. void GraphicsOutput::
  638. request_close() {
  639. }
  640. ////////////////////////////////////////////////////////////////////
  641. // Function: GraphicsOutput::set_close_now
  642. // Access: Public, Virtual
  643. // Description: This is called by the GraphicsEngine to insist that
  644. // the output be closed immediately. This is only
  645. // called from the window thread.
  646. ////////////////////////////////////////////////////////////////////
  647. void GraphicsOutput::
  648. set_close_now() {
  649. }
  650. ////////////////////////////////////////////////////////////////////
  651. // Function: GraphicsOutput::reset_window
  652. // Access: Protected, Virtual
  653. // Description: resets the window framebuffer from its derived
  654. // children. Does nothing here.
  655. ////////////////////////////////////////////////////////////////////
  656. void GraphicsOutput::
  657. reset_window(bool swapchain) {
  658. display_cat.info()
  659. << "Resetting " << get_type() << "\n";
  660. }
  661. ////////////////////////////////////////////////////////////////////
  662. // Function: GraphicsOutput::begin_frame
  663. // Access: Public, Virtual
  664. // Description: This function will be called within the draw thread
  665. // before beginning rendering for a given frame. It
  666. // should do whatever setup is required, and return true
  667. // if the frame should be rendered, or false if it
  668. // should be skipped.
  669. ////////////////////////////////////////////////////////////////////
  670. bool GraphicsOutput::
  671. begin_frame() {
  672. if (display_cat.is_spam()) {
  673. display_cat.spam()
  674. << "begin_frame(): " << get_type() << " "
  675. << get_name() << " " << (void *)this << "\n";
  676. }
  677. if (_gsg == (GraphicsStateGuardian *)NULL) {
  678. return false;
  679. }
  680. if (needs_context()) {
  681. if (!make_context()) {
  682. return false;
  683. }
  684. }
  685. // Okay, we already have a GSG, so activate it.
  686. make_current();
  687. if (_rtm_mode == RTM_bind_texture) {
  688. // Release the texture so we can render into the frame buffer.
  689. _gsg->framebuffer_release_texture(this, get_texture());
  690. }
  691. _cube_map_index = -1;
  692. return _gsg->begin_frame();
  693. }
  694. ////////////////////////////////////////////////////////////////////
  695. // Function: GraphicsOutput::clear
  696. // Access: Public
  697. // Description: Clears the entire framebuffer before rendering,
  698. // according to the settings of get_color_clear_active()
  699. // and get_depth_clear_active() (inherited from
  700. // DrawableRegion).
  701. //
  702. // This function is called only within the draw thread.
  703. ////////////////////////////////////////////////////////////////////
  704. void GraphicsOutput::
  705. clear() {
  706. if (is_any_clear_active()) {
  707. if (display_cat.is_spam()) {
  708. display_cat.spam()
  709. << "clear(): " << get_type() << " "
  710. << get_name() << " " << (void *)this << "\n";
  711. }
  712. nassertv(_gsg != (GraphicsStateGuardian *)NULL);
  713. DisplayRegionStack old_dr = _gsg->push_display_region(_default_display_region);
  714. _gsg->clear(this);
  715. _gsg->pop_display_region(old_dr);
  716. }
  717. }
  718. ////////////////////////////////////////////////////////////////////
  719. // Function: GraphicsOutput::end_frame
  720. // Access: Public, Virtual
  721. // Description: This function will be called within the draw thread
  722. // after rendering is completed for a given frame. It
  723. // should do whatever finalization is required.
  724. ////////////////////////////////////////////////////////////////////
  725. void GraphicsOutput::
  726. end_frame() {
  727. if (display_cat.is_spam()) {
  728. display_cat.spam()
  729. << "end_frame(): " << get_type() << " "
  730. << get_name() << " " << (void *)this << "\n";
  731. }
  732. nassertv(_gsg != (GraphicsStateGuardian *)NULL);
  733. _gsg->end_frame();
  734. // If _rtm_mode isn't RTM_none, it means we should copy or lock the
  735. // framebuffer to the GraphicsOutput's associated texture after the
  736. // frame has rendered.
  737. if (_rtm_mode != RTM_none) {
  738. PStatTimer timer(_copy_texture_pcollector);
  739. nassertv(has_texture());
  740. // If _rtm_mode is RTM_bind_texture, it means we should attempt to
  741. // lock the framebuffer directly to the texture memory, avoiding
  742. // the copy.
  743. if (_rtm_mode == RTM_bind_texture) {
  744. if (display_cat.is_debug()) {
  745. display_cat.debug()
  746. << "Locking texture for " << get_name() << " at frame end.\n";
  747. }
  748. if (!_gsg->framebuffer_bind_to_texture(this, get_texture())) {
  749. display_cat.warning()
  750. << "Lock-to-texture failed, resorting to copy.\n";
  751. _rtm_mode = RTM_copy_texture;
  752. }
  753. }
  754. if (_rtm_mode != RTM_bind_texture) {
  755. if (display_cat.is_debug()) {
  756. display_cat.debug()
  757. << "Copying texture for " << get_name() << " at frame end.\n";
  758. display_cat.debug()
  759. << "cube_map_index = " << _cube_map_index << "\n";
  760. }
  761. RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type());
  762. if (_rtm_mode == RTM_copy_ram) {
  763. _gsg->framebuffer_copy_to_ram(get_texture(), _cube_map_index,
  764. _default_display_region, buffer);
  765. } else {
  766. _gsg->framebuffer_copy_to_texture(get_texture(), _cube_map_index,
  767. _default_display_region, buffer);
  768. }
  769. }
  770. }
  771. // If we're not single-buffered, we're now ready to flip.
  772. if (!_gsg->get_properties().is_single_buffered()) {
  773. _flip_ready = true;
  774. }
  775. // In one-shot mode, we request the GraphicsEngine to delete the
  776. // window after we have rendered a frame.
  777. if (_one_shot) {
  778. // But when show-buffers mode is enabled, we want to keep the
  779. // window around until the user has a chance to see the texture.
  780. // So we don't do most of the following in show-buffers mode.
  781. if (!show_buffers) {
  782. _active = false;
  783. _delete_flag = true;
  784. // We have to be sure to remove all of the display regions
  785. // immediately, so that circular reference counts can be cleared
  786. // up (each display region keeps a pointer to a CullResult,
  787. // which can hold all sorts of pointers).
  788. remove_all_display_regions();
  789. // If we were rendering directly to texture, we can't delete the
  790. // buffer until the texture is gone too.
  791. if (_rtm_mode == RTM_bind_texture) {
  792. _hold_texture = _texture;
  793. }
  794. }
  795. // We have to be sure to clear the _texture pointer, though, or
  796. // we'll end up holding a reference to it forever.
  797. _texture = NULL;
  798. // And we need to stop trying to copy to the texture.
  799. _rtm_mode = RTM_none;
  800. }
  801. _cube_map_index = -1;
  802. }
  803. ////////////////////////////////////////////////////////////////////
  804. // Function: GraphicsOutput::change_scenes
  805. // Access: Public
  806. // Description: Called by the GraphicsEngine when the window is about
  807. // to change to another DisplayRegion. This exists
  808. // mainly to provide a callback for switching the cube
  809. // map face, if we are rendering to the different faces
  810. // of a cube map.
  811. ////////////////////////////////////////////////////////////////////
  812. void GraphicsOutput::
  813. change_scenes(DisplayRegion *new_dr) {
  814. int new_cube_map_index = new_dr->get_cube_map_index();
  815. if (new_cube_map_index != -1 &&
  816. new_cube_map_index != _cube_map_index) {
  817. int old_cube_map_index = _cube_map_index;
  818. _cube_map_index = new_cube_map_index;
  819. if (_rtm_mode != RTM_none) {
  820. if (_rtm_mode == RTM_bind_texture) {
  821. // In render-to-texture mode, switch the rendering backend to
  822. // the new cube map face, so that the subsequent frame will be
  823. // rendered to the new face.
  824. select_cube_map(new_cube_map_index);
  825. } else if (old_cube_map_index != -1) {
  826. // In copy-to-texture mode, copy the just-rendered framebuffer
  827. // to the old cube map face.
  828. if (display_cat.is_debug()) {
  829. display_cat.debug()
  830. << "Copying texture for " << get_name() << " at scene change.\n";
  831. display_cat.debug()
  832. << "cube_map_index = " << old_cube_map_index << "\n";
  833. }
  834. RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type());
  835. if (_rtm_mode == RTM_copy_ram) {
  836. _gsg->framebuffer_copy_to_ram(get_texture(), old_cube_map_index,
  837. _default_display_region, buffer);
  838. } else {
  839. _gsg->framebuffer_copy_to_texture(get_texture(), old_cube_map_index,
  840. _default_display_region, buffer);
  841. }
  842. }
  843. }
  844. }
  845. }
  846. ////////////////////////////////////////////////////////////////////
  847. // Function: GraphicsOutput::select_cube_map
  848. // Access: Public, Virtual
  849. // Description: Called internally when the window is in
  850. // render-to-a-texture mode and we are in the process of
  851. // rendering the six faces of a cube map. This should
  852. // do whatever needs to be done to switch the buffer to
  853. // the indicated face.
  854. ////////////////////////////////////////////////////////////////////
  855. void GraphicsOutput::
  856. select_cube_map(int) {
  857. }
  858. ////////////////////////////////////////////////////////////////////
  859. // Function: GraphicsOutput::make_context
  860. // Access: Public, Virtual
  861. // Description: If _needs_context is true, this will be called
  862. // in the draw thread prior to rendering into the
  863. // window. It should attempt to create a graphics
  864. // context, and return true if successful, false
  865. // otherwise. If it returns false the window will be
  866. // considered failed.
  867. ////////////////////////////////////////////////////////////////////
  868. bool GraphicsOutput::
  869. make_context() {
  870. _needs_context = false;
  871. return true;
  872. }
  873. ////////////////////////////////////////////////////////////////////
  874. // Function: GraphicsOutput::make_current
  875. // Access: Public, Virtual
  876. // Description: This function will be called within the draw thread
  877. // during begin_frame() to ensure the graphics context
  878. // is ready for drawing.
  879. ////////////////////////////////////////////////////////////////////
  880. void GraphicsOutput::
  881. make_current() {
  882. }
  883. ////////////////////////////////////////////////////////////////////
  884. // Function: GraphicsOutput::release_gsg
  885. // Access: Public
  886. // Description: Releases the current GSG pointer, if it is currently
  887. // held, and resets the GSG to NULL. The window will be
  888. // permanently unable to render; this is normally called
  889. // only just before destroying the window. This should
  890. // only be called from within the draw thread.
  891. ////////////////////////////////////////////////////////////////////
  892. void GraphicsOutput::
  893. release_gsg() {
  894. _gsg.clear();
  895. }
  896. ////////////////////////////////////////////////////////////////////
  897. // Function: GraphicsOutput::begin_flip
  898. // Access: Public, Virtual
  899. // Description: This function will be called within the draw thread
  900. // after end_frame() has been called on all windows, to
  901. // initiate the exchange of the front and back buffers.
  902. //
  903. // This should instruct the window to prepare for the
  904. // flip at the next video sync, but it should not wait.
  905. //
  906. // We have the two separate functions, begin_flip() and
  907. // end_flip(), to make it easier to flip all of the
  908. // windows at the same time.
  909. ////////////////////////////////////////////////////////////////////
  910. void GraphicsOutput::
  911. begin_flip() {
  912. }
  913. ////////////////////////////////////////////////////////////////////
  914. // Function: GraphicsOutput::end_flip
  915. // Access: Public, Virtual
  916. // Description: This function will be called within the draw thread
  917. // after begin_flip() has been called on all windows, to
  918. // finish the exchange of the front and back buffers.
  919. //
  920. // This should cause the window to wait for the flip, if
  921. // necessary.
  922. ////////////////////////////////////////////////////////////////////
  923. void GraphicsOutput::
  924. end_flip() {
  925. _flip_ready = false;
  926. }
  927. ////////////////////////////////////////////////////////////////////
  928. // Function: GraphicsOutput::process_events
  929. // Access: Public, Virtual
  930. // Description: Do whatever processing in the window thread is
  931. // appropriate for this output object each frame.
  932. //
  933. // This function is called only within the window
  934. // thread.
  935. ////////////////////////////////////////////////////////////////////
  936. void GraphicsOutput::
  937. process_events() {
  938. }
  939. ////////////////////////////////////////////////////////////////////
  940. // Function: GraphicsOutput::add_display_region
  941. // Access: Private
  942. // Description: Called by one of the make_display_region() methods to
  943. // add the new DisplayRegion to the list.
  944. ////////////////////////////////////////////////////////////////////
  945. DisplayRegion *GraphicsOutput::
  946. add_display_region(DisplayRegion *display_region) {
  947. MutexHolder holder(_lock);
  948. _total_display_regions.push_back(display_region);
  949. _display_regions_stale = true;
  950. return display_region;
  951. }
  952. ////////////////////////////////////////////////////////////////////
  953. // Function: GraphicsOutput::do_determine_display_regions
  954. // Access: Private
  955. // Description: Re-sorts the list of active DisplayRegions within
  956. // the window.
  957. ////////////////////////////////////////////////////////////////////
  958. void GraphicsOutput::
  959. do_determine_display_regions() {
  960. MutexHolder holder(_lock);
  961. _display_regions_stale = false;
  962. _active_display_regions.clear();
  963. _active_display_regions.reserve(_total_display_regions.size());
  964. TotalDisplayRegions::const_iterator dri;
  965. for (dri = _total_display_regions.begin();
  966. dri != _total_display_regions.end();
  967. ++dri) {
  968. DisplayRegion *display_region = (*dri);
  969. if (display_region->is_active()) {
  970. _active_display_regions.push_back(display_region);
  971. }
  972. }
  973. stable_sort(_active_display_regions.begin(), _active_display_regions.end(), IndirectLess<DisplayRegion>());
  974. }