mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 09:23:03 -04:00
use new offscreen buffer mechanism
This commit is contained in:
parent
abd0db5458
commit
6f956e1fe7
@ -32,7 +32,7 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
NonlinearImager::
|
||||
NonlinearImager() {
|
||||
_gsg = (GraphicsStateGuardian *)NULL;
|
||||
_engine = (GraphicsEngine *)NULL;
|
||||
_stale = true;
|
||||
}
|
||||
|
||||
@ -45,6 +45,11 @@ NonlinearImager::
|
||||
~NonlinearImager() {
|
||||
remove_all_screens();
|
||||
remove_all_viewers();
|
||||
|
||||
if (_engine != (GraphicsEngine *)NULL) {
|
||||
_engine->remove_callback("", GraphicsEngine::CB_pre_frame,
|
||||
recompute_callback, (void *)this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -73,11 +78,12 @@ NonlinearImager::
|
||||
// screen.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int NonlinearImager::
|
||||
add_screen(ProjectionScreen *screen) {
|
||||
add_screen(ProjectionScreen *screen, const string &name) {
|
||||
_screens.push_back(Screen());
|
||||
Screen &new_screen = _screens.back();
|
||||
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_height = 256;
|
||||
new_screen._active = true;
|
||||
@ -162,6 +168,20 @@ get_screen(int index) const {
|
||||
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
|
||||
// Access: Published
|
||||
@ -176,8 +196,18 @@ get_screen(int index) const {
|
||||
void NonlinearImager::
|
||||
set_texture_size(int index, int width, int height) {
|
||||
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++) {
|
||||
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 {
|
||||
// If we've just made it active, it needs to be recomputed.
|
||||
_stale = true;
|
||||
@ -250,18 +286,19 @@ get_screen_active(int index) const {
|
||||
// camera are desired, you should use the
|
||||
// set_viewer_camera() interface.
|
||||
//
|
||||
// All viewers must share the same
|
||||
// GraphicsStateGuardian.
|
||||
// All viewers must share the same GraphicsEngine.
|
||||
//
|
||||
// The return value is the index of the new viewer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int NonlinearImager::
|
||||
add_viewer(DisplayRegion *dr) {
|
||||
GraphicsOutput *win = dr->get_window();
|
||||
GraphicsStateGuardian *gsg = win->get_gsg();
|
||||
nassertr(_viewers.empty() || (gsg == _gsg && win == _win), -1);
|
||||
_gsg = gsg;
|
||||
_win = win;
|
||||
GraphicsEngine *engine = dr->get_window()->get_gsg()->get_engine();
|
||||
nassertr(_viewers.empty() || (engine == _engine), -1);
|
||||
if (_engine == (GraphicsEngine *)NULL) {
|
||||
_engine = engine;
|
||||
_engine->add_callback("", GraphicsEngine::CB_pre_frame,
|
||||
recompute_callback, (void *)this);
|
||||
}
|
||||
|
||||
int previous_vi = find_viewer(dr);
|
||||
if (previous_vi >= 0) {
|
||||
@ -447,17 +484,11 @@ get_viewer(int index) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void NonlinearImager::
|
||||
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;
|
||||
for (vi = 0; vi < _viewers.size(); ++vi) {
|
||||
Viewer &viewer = _viewers[vi];
|
||||
|
||||
Screens::iterator si;
|
||||
for (si = _screens.begin(); si != _screens.end(); ++si) {
|
||||
Screen &screen = (*si);
|
||||
if (screen._active) {
|
||||
@ -476,25 +507,16 @@ recompute() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NonlinearImager::render
|
||||
// Access: Published
|
||||
// Description: Uses the DisplayRegion's GSG to render a scene for
|
||||
// each ProjectionScreen, and makes our DisplayRegion
|
||||
// ready to render the combined results. This will
|
||||
// destroy the contents of the frame buffer; it should
|
||||
// be done before any of the actual frame has started
|
||||
// rendering.
|
||||
// Function: NonlinearImager::recompute_callback
|
||||
// Access: Private, Static
|
||||
// Description: This function is added as a callback to the beginning
|
||||
// of the graphics engine's frame, to ensure that all
|
||||
// frames are up-to-date.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void NonlinearImager::
|
||||
render(GraphicsEngine *engine) {
|
||||
recompute_if_stale();
|
||||
|
||||
Screens::iterator si;
|
||||
for (si = _screens.begin(); si != _screens.end(); ++si) {
|
||||
if ((*si)._active) {
|
||||
render_screen(engine, *si);
|
||||
}
|
||||
}
|
||||
recompute_callback(void *data) {
|
||||
NonlinearImager *self = (NonlinearImager *)data;
|
||||
self->recompute_if_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -533,6 +555,8 @@ recompute_if_stale() {
|
||||
if (screen._active &&
|
||||
screen._meshes[vi]._last_screen != screen._screen->get_last_screen()) {
|
||||
recompute_screen(screen, vi);
|
||||
} else {
|
||||
screen._screen->recompute_if_stale();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -555,64 +579,32 @@ recompute_screen(NonlinearImager::Screen &screen, size_t vi) {
|
||||
return;
|
||||
}
|
||||
|
||||
screen._screen->recompute_if_stale();
|
||||
|
||||
Viewer &viewer = _viewers[vi];
|
||||
PT(PandaNode) mesh = screen._screen->make_flat_mesh(viewer._viewer);
|
||||
if (mesh != (PandaNode *)NULL) {
|
||||
screen._meshes[vi]._mesh = viewer._internal_scene.attach_new_node(mesh);
|
||||
}
|
||||
|
||||
if (screen._texture == (Texture *)NULL ||
|
||||
screen._texture->_pbuffer == (PixelBuffer *)NULL ||
|
||||
screen._texture->_pbuffer->get_xsize() != screen._tex_width ||
|
||||
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);
|
||||
if (screen._buffer == (GraphicsOutput *)NULL) {
|
||||
GraphicsOutput *win = viewer._dr->get_window();
|
||||
GraphicsOutput *buffer = win->make_texture_buffer(screen._name, screen._tex_width, 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();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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 "displayRegion.h"
|
||||
#include "graphicsOutput.h"
|
||||
#include "camera.h"
|
||||
#include "texture.h"
|
||||
#include "pandaNode.h"
|
||||
@ -95,13 +96,14 @@ PUBLISHED:
|
||||
NonlinearImager();
|
||||
~NonlinearImager();
|
||||
|
||||
int add_screen(ProjectionScreen *screen);
|
||||
int add_screen(ProjectionScreen *screen, const string &name = string());
|
||||
int find_screen(ProjectionScreen *screen) const;
|
||||
void remove_screen(int index);
|
||||
void remove_all_screens();
|
||||
|
||||
int get_num_screens() 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_source_camera(int index, const NodePath &source_camera);
|
||||
|
||||
@ -122,7 +124,10 @@ PUBLISHED:
|
||||
DisplayRegion *get_viewer(int index) const;
|
||||
|
||||
void recompute();
|
||||
void render(GraphicsEngine *engine);
|
||||
|
||||
public:
|
||||
static void recompute_callback(void *data);
|
||||
void recompute_if_stale();
|
||||
|
||||
private:
|
||||
class Viewer {
|
||||
@ -146,7 +151,8 @@ private:
|
||||
class Screen {
|
||||
public:
|
||||
PT(ProjectionScreen) _screen;
|
||||
PT(Texture) _texture;
|
||||
string _name;
|
||||
PT(GraphicsOutput) _buffer;
|
||||
NodePath _source_camera;
|
||||
int _tex_width, _tex_height;
|
||||
bool _active;
|
||||
@ -156,14 +162,13 @@ private:
|
||||
};
|
||||
typedef pvector<Screen> Screens;
|
||||
|
||||
void recompute_if_stale();
|
||||
void recompute_screen(Screen &screen, size_t vi);
|
||||
void render_screen(GraphicsEngine *engine, Screen &screen);
|
||||
|
||||
Viewers _viewers;
|
||||
Screens _screens;
|
||||
GraphicsStateGuardian *_gsg;
|
||||
GraphicsOutput *_win;
|
||||
|
||||
GraphicsEngine *_engine;
|
||||
|
||||
bool _stale;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user