mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-18 12:43:44 -04:00
use new offscreen buffer mechanism
This commit is contained in:
parent
abd0db5458
commit
6f956e1fe7
@ -32,7 +32,7 @@
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
NonlinearImager::
|
NonlinearImager::
|
||||||
NonlinearImager() {
|
NonlinearImager() {
|
||||||
_gsg = (GraphicsStateGuardian *)NULL;
|
_engine = (GraphicsEngine *)NULL;
|
||||||
_stale = true;
|
_stale = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +45,11 @@ NonlinearImager::
|
|||||||
~NonlinearImager() {
|
~NonlinearImager() {
|
||||||
remove_all_screens();
|
remove_all_screens();
|
||||||
remove_all_viewers();
|
remove_all_viewers();
|
||||||
|
|
||||||
|
if (_engine != (GraphicsEngine *)NULL) {
|
||||||
|
_engine->remove_callback("", GraphicsEngine::CB_pre_frame,
|
||||||
|
recompute_callback, (void *)this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -73,11 +78,12 @@ NonlinearImager::
|
|||||||
// screen.
|
// screen.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int NonlinearImager::
|
int NonlinearImager::
|
||||||
add_screen(ProjectionScreen *screen) {
|
add_screen(ProjectionScreen *screen, const string &name) {
|
||||||
_screens.push_back(Screen());
|
_screens.push_back(Screen());
|
||||||
Screen &new_screen = _screens.back();
|
Screen &new_screen = _screens.back();
|
||||||
new_screen._screen = screen;
|
new_screen._screen = screen;
|
||||||
new_screen._texture = (Texture *)NULL;
|
new_screen._name = name;
|
||||||
|
new_screen._buffer = (GraphicsOutput *)NULL;
|
||||||
new_screen._tex_width = 256;
|
new_screen._tex_width = 256;
|
||||||
new_screen._tex_height = 256;
|
new_screen._tex_height = 256;
|
||||||
new_screen._active = true;
|
new_screen._active = true;
|
||||||
@ -162,6 +168,20 @@ get_screen(int index) const {
|
|||||||
return _screens[index]._screen;
|
return _screens[index]._screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: NonlinearImager::get_buffer
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the offscreen buffer that is automatically
|
||||||
|
// created for the nth projection screen. This may
|
||||||
|
// return NULL if the screen is inactive or if it has
|
||||||
|
// not been rendered yet.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
GraphicsOutput *NonlinearImager::
|
||||||
|
get_buffer(int index) const {
|
||||||
|
nassertr(index >= 0 && index < (int)_screens.size(), (GraphicsOutput *)NULL);
|
||||||
|
return _screens[index]._buffer;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: NonlinearImager::set_texture_size
|
// Function: NonlinearImager::set_texture_size
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -176,8 +196,18 @@ get_screen(int index) const {
|
|||||||
void NonlinearImager::
|
void NonlinearImager::
|
||||||
set_texture_size(int index, int width, int height) {
|
set_texture_size(int index, int width, int height) {
|
||||||
nassertv(index >= 0 && index < (int)_screens.size());
|
nassertv(index >= 0 && index < (int)_screens.size());
|
||||||
_screens[index]._tex_width = width;
|
|
||||||
_screens[index]._tex_height = height;
|
Screen &screen = _screens[index];
|
||||||
|
|
||||||
|
screen._tex_width = width;
|
||||||
|
screen._tex_height = height;
|
||||||
|
|
||||||
|
if (screen._buffer != (GraphicsOutput *)NULL) {
|
||||||
|
_engine->remove_window(screen._buffer);
|
||||||
|
screen._buffer = (GraphicsOutput *)NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_stale = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -216,7 +246,13 @@ set_screen_active(int index, bool active) {
|
|||||||
for (size_t vi = 0; vi < screen._meshes.size(); vi++) {
|
for (size_t vi = 0; vi < screen._meshes.size(); vi++) {
|
||||||
screen._meshes[vi]._mesh.remove_node();
|
screen._meshes[vi]._mesh.remove_node();
|
||||||
}
|
}
|
||||||
screen._texture.clear();
|
|
||||||
|
// Also remove its buffer.
|
||||||
|
if (screen._buffer != (GraphicsOutput *)NULL) {
|
||||||
|
_engine->remove_window(screen._buffer);
|
||||||
|
screen._buffer = (GraphicsOutput *)NULL;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// If we've just made it active, it needs to be recomputed.
|
// If we've just made it active, it needs to be recomputed.
|
||||||
_stale = true;
|
_stale = true;
|
||||||
@ -250,18 +286,19 @@ get_screen_active(int index) const {
|
|||||||
// camera are desired, you should use the
|
// camera are desired, you should use the
|
||||||
// set_viewer_camera() interface.
|
// set_viewer_camera() interface.
|
||||||
//
|
//
|
||||||
// All viewers must share the same
|
// All viewers must share the same GraphicsEngine.
|
||||||
// GraphicsStateGuardian.
|
|
||||||
//
|
//
|
||||||
// The return value is the index of the new viewer.
|
// The return value is the index of the new viewer.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int NonlinearImager::
|
int NonlinearImager::
|
||||||
add_viewer(DisplayRegion *dr) {
|
add_viewer(DisplayRegion *dr) {
|
||||||
GraphicsOutput *win = dr->get_window();
|
GraphicsEngine *engine = dr->get_window()->get_gsg()->get_engine();
|
||||||
GraphicsStateGuardian *gsg = win->get_gsg();
|
nassertr(_viewers.empty() || (engine == _engine), -1);
|
||||||
nassertr(_viewers.empty() || (gsg == _gsg && win == _win), -1);
|
if (_engine == (GraphicsEngine *)NULL) {
|
||||||
_gsg = gsg;
|
_engine = engine;
|
||||||
_win = win;
|
_engine->add_callback("", GraphicsEngine::CB_pre_frame,
|
||||||
|
recompute_callback, (void *)this);
|
||||||
|
}
|
||||||
|
|
||||||
int previous_vi = find_viewer(dr);
|
int previous_vi = find_viewer(dr);
|
||||||
if (previous_vi >= 0) {
|
if (previous_vi >= 0) {
|
||||||
@ -447,17 +484,11 @@ get_viewer(int index) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void NonlinearImager::
|
void NonlinearImager::
|
||||||
recompute() {
|
recompute() {
|
||||||
// First, force all the textures to clear.
|
|
||||||
Screens::iterator si;
|
|
||||||
for (si = _screens.begin(); si != _screens.end(); ++si) {
|
|
||||||
Screen &screen = (*si);
|
|
||||||
screen._texture.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t vi;
|
size_t vi;
|
||||||
for (vi = 0; vi < _viewers.size(); ++vi) {
|
for (vi = 0; vi < _viewers.size(); ++vi) {
|
||||||
Viewer &viewer = _viewers[vi];
|
Viewer &viewer = _viewers[vi];
|
||||||
|
|
||||||
|
Screens::iterator si;
|
||||||
for (si = _screens.begin(); si != _screens.end(); ++si) {
|
for (si = _screens.begin(); si != _screens.end(); ++si) {
|
||||||
Screen &screen = (*si);
|
Screen &screen = (*si);
|
||||||
if (screen._active) {
|
if (screen._active) {
|
||||||
@ -476,25 +507,16 @@ recompute() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: NonlinearImager::render
|
// Function: NonlinearImager::recompute_callback
|
||||||
// Access: Published
|
// Access: Private, Static
|
||||||
// Description: Uses the DisplayRegion's GSG to render a scene for
|
// Description: This function is added as a callback to the beginning
|
||||||
// each ProjectionScreen, and makes our DisplayRegion
|
// of the graphics engine's frame, to ensure that all
|
||||||
// ready to render the combined results. This will
|
// frames are up-to-date.
|
||||||
// destroy the contents of the frame buffer; it should
|
|
||||||
// be done before any of the actual frame has started
|
|
||||||
// rendering.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void NonlinearImager::
|
void NonlinearImager::
|
||||||
render(GraphicsEngine *engine) {
|
recompute_callback(void *data) {
|
||||||
recompute_if_stale();
|
NonlinearImager *self = (NonlinearImager *)data;
|
||||||
|
self->recompute_if_stale();
|
||||||
Screens::iterator si;
|
|
||||||
for (si = _screens.begin(); si != _screens.end(); ++si) {
|
|
||||||
if ((*si)._active) {
|
|
||||||
render_screen(engine, *si);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -533,6 +555,8 @@ recompute_if_stale() {
|
|||||||
if (screen._active &&
|
if (screen._active &&
|
||||||
screen._meshes[vi]._last_screen != screen._screen->get_last_screen()) {
|
screen._meshes[vi]._last_screen != screen._screen->get_last_screen()) {
|
||||||
recompute_screen(screen, vi);
|
recompute_screen(screen, vi);
|
||||||
|
} else {
|
||||||
|
screen._screen->recompute_if_stale();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -555,64 +579,32 @@ recompute_screen(NonlinearImager::Screen &screen, size_t vi) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
screen._screen->recompute_if_stale();
|
||||||
|
|
||||||
Viewer &viewer = _viewers[vi];
|
Viewer &viewer = _viewers[vi];
|
||||||
PT(PandaNode) mesh = screen._screen->make_flat_mesh(viewer._viewer);
|
PT(PandaNode) mesh = screen._screen->make_flat_mesh(viewer._viewer);
|
||||||
if (mesh != (PandaNode *)NULL) {
|
if (mesh != (PandaNode *)NULL) {
|
||||||
screen._meshes[vi]._mesh = viewer._internal_scene.attach_new_node(mesh);
|
screen._meshes[vi]._mesh = viewer._internal_scene.attach_new_node(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (screen._texture == (Texture *)NULL ||
|
if (screen._buffer == (GraphicsOutput *)NULL) {
|
||||||
screen._texture->_pbuffer == (PixelBuffer *)NULL ||
|
GraphicsOutput *win = viewer._dr->get_window();
|
||||||
screen._texture->_pbuffer->get_xsize() != screen._tex_width ||
|
GraphicsOutput *buffer = win->make_texture_buffer(screen._name, screen._tex_width, screen._tex_height);
|
||||||
screen._texture->_pbuffer->get_ysize() != screen._tex_height) {
|
|
||||||
PT(Texture) texture = new Texture;
|
|
||||||
texture->set_minfilter(Texture::FT_linear);
|
|
||||||
texture->set_magfilter(Texture::FT_linear);
|
|
||||||
texture->set_wrapu(Texture::WM_clamp);
|
|
||||||
texture->set_wrapv(Texture::WM_clamp);
|
|
||||||
texture->_pbuffer->set_xsize(screen._tex_width);
|
|
||||||
texture->_pbuffer->set_ysize(screen._tex_height);
|
|
||||||
|
|
||||||
screen._texture = texture;
|
if (buffer != (GraphicsOutput *)NULL) {
|
||||||
|
screen._buffer = buffer;
|
||||||
|
GraphicsLayer *layer = buffer->get_channel(0)->make_layer();
|
||||||
|
DisplayRegion *dr = layer->make_display_region();
|
||||||
|
dr->set_camera(screen._source_camera);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
screen._meshes[vi]._mesh.clear_texture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screen._buffer != (GraphicsOutput *)NULL) {
|
||||||
|
screen._meshes[vi]._mesh.set_texture(screen._buffer->get_texture());
|
||||||
}
|
}
|
||||||
|
|
||||||
screen._meshes[vi]._mesh.set_texture(screen._texture);
|
|
||||||
screen._meshes[vi]._last_screen = screen._screen->get_last_screen();
|
screen._meshes[vi]._last_screen = screen._screen->get_last_screen();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: NonlinearImager::render_screen
|
|
||||||
// Access: Private
|
|
||||||
// Description: Renders the scene just for the indicated screen, into
|
|
||||||
// the screen's own texture.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
void NonlinearImager::
|
|
||||||
render_screen(GraphicsEngine *engine, NonlinearImager::Screen &screen) {
|
|
||||||
if (screen._source_camera.is_empty()) {
|
|
||||||
distort_cat.error()
|
|
||||||
<< "No source camera specified for screen " << screen._screen->get_name()
|
|
||||||
<< "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
|
|
||||||
|
|
||||||
screen._screen->recompute_if_stale();
|
|
||||||
|
|
||||||
// Make a display region of the proper size and clear it to prepare for
|
|
||||||
// rendering the scene.
|
|
||||||
PT(DisplayRegion) scratch_region =
|
|
||||||
_win->make_scratch_display_region(screen._tex_width, screen._tex_height);
|
|
||||||
scratch_region->set_camera(screen._source_camera);
|
|
||||||
engine->render_subframe(_gsg, scratch_region, true);
|
|
||||||
|
|
||||||
// Copy the results of the render from the frame buffer into the
|
|
||||||
// screen's texture.
|
|
||||||
TextureContext *tc = screen._texture->prepare_now(_gsg->get_prepared_objects(), _gsg);
|
|
||||||
_gsg->copy_texture(tc, scratch_region,
|
|
||||||
_gsg->get_render_buffer(RenderBuffer::T_back));
|
|
||||||
|
|
||||||
// It might be nice if we didn't throw away the scratch region every
|
|
||||||
// time, which prevents us from preserving cull state from one frame
|
|
||||||
// to the next.
|
|
||||||
}
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "projectionScreen.h"
|
#include "projectionScreen.h"
|
||||||
#include "displayRegion.h"
|
#include "displayRegion.h"
|
||||||
|
#include "graphicsOutput.h"
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
#include "pandaNode.h"
|
#include "pandaNode.h"
|
||||||
@ -95,13 +96,14 @@ PUBLISHED:
|
|||||||
NonlinearImager();
|
NonlinearImager();
|
||||||
~NonlinearImager();
|
~NonlinearImager();
|
||||||
|
|
||||||
int add_screen(ProjectionScreen *screen);
|
int add_screen(ProjectionScreen *screen, const string &name = string());
|
||||||
int find_screen(ProjectionScreen *screen) const;
|
int find_screen(ProjectionScreen *screen) const;
|
||||||
void remove_screen(int index);
|
void remove_screen(int index);
|
||||||
void remove_all_screens();
|
void remove_all_screens();
|
||||||
|
|
||||||
int get_num_screens() const;
|
int get_num_screens() const;
|
||||||
ProjectionScreen *get_screen(int index) const;
|
ProjectionScreen *get_screen(int index) const;
|
||||||
|
GraphicsOutput *get_buffer(int index) const;
|
||||||
void set_texture_size(int index, int width, int height);
|
void set_texture_size(int index, int width, int height);
|
||||||
void set_source_camera(int index, const NodePath &source_camera);
|
void set_source_camera(int index, const NodePath &source_camera);
|
||||||
|
|
||||||
@ -122,7 +124,10 @@ PUBLISHED:
|
|||||||
DisplayRegion *get_viewer(int index) const;
|
DisplayRegion *get_viewer(int index) const;
|
||||||
|
|
||||||
void recompute();
|
void recompute();
|
||||||
void render(GraphicsEngine *engine);
|
|
||||||
|
public:
|
||||||
|
static void recompute_callback(void *data);
|
||||||
|
void recompute_if_stale();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Viewer {
|
class Viewer {
|
||||||
@ -146,7 +151,8 @@ private:
|
|||||||
class Screen {
|
class Screen {
|
||||||
public:
|
public:
|
||||||
PT(ProjectionScreen) _screen;
|
PT(ProjectionScreen) _screen;
|
||||||
PT(Texture) _texture;
|
string _name;
|
||||||
|
PT(GraphicsOutput) _buffer;
|
||||||
NodePath _source_camera;
|
NodePath _source_camera;
|
||||||
int _tex_width, _tex_height;
|
int _tex_width, _tex_height;
|
||||||
bool _active;
|
bool _active;
|
||||||
@ -156,14 +162,13 @@ private:
|
|||||||
};
|
};
|
||||||
typedef pvector<Screen> Screens;
|
typedef pvector<Screen> Screens;
|
||||||
|
|
||||||
void recompute_if_stale();
|
|
||||||
void recompute_screen(Screen &screen, size_t vi);
|
void recompute_screen(Screen &screen, size_t vi);
|
||||||
void render_screen(GraphicsEngine *engine, Screen &screen);
|
void render_screen(GraphicsEngine *engine, Screen &screen);
|
||||||
|
|
||||||
Viewers _viewers;
|
Viewers _viewers;
|
||||||
Screens _screens;
|
Screens _screens;
|
||||||
GraphicsStateGuardian *_gsg;
|
|
||||||
GraphicsOutput *_win;
|
GraphicsEngine *_engine;
|
||||||
|
|
||||||
bool _stale;
|
bool _stale;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user