*** empty log message ***

This commit is contained in:
Josh Yelon 2005-10-27 21:11:26 +00:00
parent 5c29aace8d
commit efc2a9ce26
10 changed files with 356 additions and 276 deletions

View File

@ -60,30 +60,36 @@ get_name() const {
return _name;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::count_textures
// Access: Published
// Description: If the GraphicsOutput is set to render into a
// texture, returns the number of textures that are
// being rendered into. Normally, the textures would
// be associated with different buffers - a color
// texture, a depth texture, and a stencil texture.
////////////////////////////////////////////////////////////////////
INLINE int GraphicsOutput::
count_textures() const {
return _textures.size();
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::has_texture
// Access: Published
// Description: Returns true if the GraphicsOutput is set to render
// into a texture, or false otherwise.
//
// Normally, this will only be true for a GraphicsBuffer
// object, and only when want_texture is passed in as
// true to the GraphicsBuffer constructor. If
// show-buffers is true, this may also be set for a
// GraphicsWindow, which is in this case serving in the
// place of a GraphicsBuffer.
// Description: Returns true if the GraphicsOutput is rendering
// into any textures at all.
////////////////////////////////////////////////////////////////////
INLINE bool GraphicsOutput::
has_texture() const {
return !(_texture.is_null());
return (_textures.size() > 0);
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::get_texture
// Access: Published
// Description: Returns the texture into which the GraphicsOutput
// renders, if has_texture() is true, or NULL if
// has_texture() is false.
// Description: Returns the nth texture into which the GraphicsOutput
// renders. Returns NULL if there is no such texture.
//
// If the texture is non-NULL, it may be applied to
// geometry to be rendered for any other windows or
@ -93,8 +99,26 @@ has_texture() const {
// the texture will be invalid.
////////////////////////////////////////////////////////////////////
INLINE Texture *GraphicsOutput::
get_texture() const {
return _texture;
get_texture(int i) const {
if ((i < 0) || (i >= ((int)_textures.size()))) {
return (Texture *)NULL;
}
return _textures[i]._texture;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::get_rtm_mode
// Access: Published
// Description: Returns the RenderTextureMode associated with the
// nth texture. Returns RTM_none if there is no such
// texture.
////////////////////////////////////////////////////////////////////
INLINE GraphicsOutput::RenderTextureMode GraphicsOutput::
get_rtm_mode(int i) const {
if ((i < 0) || (i >= ((int)_textures.size()))) {
return RTM_none;
}
return _textures[i]._rtm_mode;
}
////////////////////////////////////////////////////////////////////
@ -225,7 +249,12 @@ INLINE bool GraphicsOutput::
get_delete_flag() const {
// We only delete the window or buffer automatically when it is
// no longer associated with a texture.
return _delete_flag && !_hold_texture.is_valid_pointer();
for (int i=0; i<(int)_hold_textures.size(); i++) {
if (_hold_textures[i].is_valid_pointer()) {
return false;
}
}
return _delete_flag;
}
////////////////////////////////////////////////////////////////////

View File

@ -80,7 +80,6 @@ GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
_y_size = 0;
_has_size = false;
_is_valid = false;
_rtm_mode = RTM_none;
_flip_ready = false;
_needs_context = true;
_cube_map_index = -1;
@ -187,12 +186,24 @@ GraphicsOutput::
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::setup_render_texture
// Function: GraphicsOutput::clear_render_textures
// Access: Published
// Description: If the GraphicsOutput is currently rendering to
// a texture, then all textures are dissociated from
// the GraphicsOuput.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
clear_render_textures() {
MutexHolder holder(_lock);
_textures.clear();
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::add_render_texture
// Access: Published
// Description: Creates a new Texture object, suitable for rendering
// the contents of this buffer into, and stores it in
// _texture. This also disassociates the previous
// texture (if any).
// the contents of this buffer into, and appends it to
// the list of render textures.
//
// If tex is not NULL, it is the texture that will be
// set up for rendering into; otherwise, a new Texture
@ -200,66 +211,84 @@ GraphicsOutput::
// get_texture() to retrieve the new texture pointer
// later).
//
// If allow_bind is true, and this GraphicsOutput is an
// offscreen graphics buffer that has not yet been
// rendered into, it will attempt to set up the buffer
// for rendering directly into the texture, avoiding the
// cost of the copy-to-texture-memory each frame. This
// is not supported by all graphics hardware, but if it
// is not supported, this option is quietly ignored.
//
// If to_ram is true, the texture image will be
// downloaded from the framebuffer memory into system
// RAM each frame, which is more expensive but allows
// the texture to subsequently be applied to any GSG.
// Otherwise, the texture image remains in texture
// memory only.
//
// Also see make_texture_buffer(), which is a
// higher-level interface for preparing
// render-to-a-texture mode.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
setup_render_texture(Texture *tex, RenderTextureMode mode) {
add_render_texture(Texture *tex, RenderTextureMode mode) {
if (mode == RTM_none) {
return;
}
MutexHolder holder(_lock);
_rtm_mode = mode;
if (tex == (Texture *)NULL) {
_texture = new Texture(get_name());
_texture->set_wrap_u(Texture::WM_clamp);
_texture->set_wrap_v(Texture::WM_clamp);
tex = new Texture(get_name());
tex->set_wrap_u(Texture::WM_clamp);
tex->set_wrap_v(Texture::WM_clamp);
} else {
_texture = tex;
_texture->clear_ram_image();
tex->clear_ram_image();
}
_texture->set_match_framebuffer_format(true);
tex->set_match_framebuffer_format(true);
// Go ahead and tell the texture our anticipated size, even if it
// might be inaccurate (particularly if this is a GraphicsWindow,
// which has system-imposed restrictions on size).
_texture->set_x_size(get_x_size());
_texture->set_y_size(get_y_size());
tex->set_x_size(get_x_size());
tex->set_y_size(get_y_size());
RenderTexture result;
result._texture = tex;
result._rtm_mode = mode;
_textures.push_back(result);
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
set_inverted(_gsg->get_copy_texture_inverted());
// Sanity check that we don't have two textures of the same type.
int count_stencil_textures = 0;
int count_depth_textures = 0;
int count_color_textures = 0;
for (int i=0; i<count_textures(); i++) {
Texture::Format fmt = get_texture(i)->get_format();
if (fmt == Texture::F_depth_component) {
count_depth_textures += 1;
} else if (fmt == Texture::F_stencil_index) {
count_stencil_textures += 1;
} else {
count_color_textures += 1;
}
}
if ((count_color_textures > 1)||
(count_depth_textures > 1)||
(count_stencil_textures > 1)) {
display_cat.error() <<
"Currently, each GraphicsOutput can only render to one color texture, "
"one depth texture, and one stencil texture at a time. RTM aborted.\n";
clear_render_textures();
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::setup_render_texture
// Access: Published
// Description:
// Description: This is a deprecated interface that made sense back
// when GraphicsOutputs could only render into one
// texture at a time. From now on, use
// clear_render_textures and add_render_texture
// instead.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
setup_render_texture(Texture *tex, bool allow_bind, bool to_ram) {
display_cat.warning() <<
"Using deprecated setup_render_texture interface.\n";
clear_render_textures();
if (to_ram) {
setup_render_texture(tex, RTM_copy_ram);
add_render_texture(tex, RTM_copy_ram);
} else if (allow_bind) {
setup_render_texture(tex, RTM_bind_or_copy);
add_render_texture(tex, RTM_bind_or_copy);
} else {
setup_render_texture(tex, RTM_copy_texture);
add_render_texture(tex, RTM_copy_texture);
}
}
@ -577,7 +606,20 @@ get_texture_card() {
PT(GeomNode) gnode = new GeomNode("texture card");
gnode->add_geom(_texture_card);
NodePath path(gnode);
path.set_texture(get_texture(), 0);
// The texture card, by default, is textured with the first
// render-to-texture output texture. Depth and stencil
// textures are ignored. The user can freely alter the
// card's texture attrib.
for (int i=0; i<count_textures(); i++) {
Texture *texture = get_texture(i);
if ((texture->get_format() != Texture::F_depth_component) &&
(texture->get_format() != Texture::F_stencil_index)) {
path.set_texture(texture, 0);
break;
}
}
return path;
}
@ -635,7 +677,7 @@ make_texture_buffer(const string &name, int x_size, int y_size,
// host window size. If the user requests this, we have to use a
// parasite buffer.
buffer = engine->make_parasite(host, name, sort, x_size, y_size);
buffer->setup_render_texture(tex, false, to_ram);
buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
return buffer;
}
@ -644,7 +686,7 @@ make_texture_buffer(const string &name, int x_size, int y_size,
// since it all amounts to the same thing anyway--this will
// actually create a new GraphicsWindow.
buffer = engine->make_buffer(gsg, name, sort, x_size, y_size);
buffer->setup_render_texture(tex, false, to_ram);
buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
return buffer;
}
@ -661,7 +703,7 @@ make_texture_buffer(const string &name, int x_size, int y_size,
(x_size <= host->get_x_size() && y_size <= host->get_y_size())) {
buffer = engine->make_parasite(host, name, sort, x_size, y_size);
if (buffer != (GraphicsOutput *)NULL) {
buffer->setup_render_texture(tex, false, to_ram);
buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
return buffer;
}
}
@ -680,7 +722,11 @@ make_texture_buffer(const string &name, int x_size, int y_size,
buffer = engine->make_buffer(sb_gsg, name, sort, x_size, y_size);
if (buffer != (GraphicsOutput *)NULL) {
// Check the buffer for goodness.
buffer->setup_render_texture(tex, allow_bind, to_ram);
if (allow_bind) {
buffer->add_render_texture(tex, RTM_bind_or_copy);
} else {
buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
}
engine->open_windows();
if (buffer->is_valid()) {
return buffer;
@ -700,7 +746,11 @@ make_texture_buffer(const string &name, int x_size, int y_size,
// source window is double-buffered.
buffer = engine->make_buffer(gsg, name, sort, x_size, y_size);
if (buffer != (GraphicsOutput *)NULL) {
buffer->setup_render_texture(tex, allow_bind, to_ram);
if (allow_bind) {
buffer->add_render_texture(tex, RTM_bind_or_copy);
} else {
buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
}
engine->open_windows();
if (buffer->is_valid()) {
return buffer;
@ -714,7 +764,7 @@ make_texture_buffer(const string &name, int x_size, int y_size,
// Looks like we have to settle for a parasite buffer.
if (x_size <= host->get_x_size() && y_size <= host->get_y_size()) {
buffer = engine->make_parasite(host, name, sort, x_size, y_size);
buffer->setup_render_texture(tex, false, to_ram);
buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
return buffer;
}
@ -926,10 +976,7 @@ begin_frame() {
// Okay, we already have a GSG, so activate it.
make_current();
if (_rtm_mode == RTM_bind_or_copy) {
// Release the texture so we can render into the frame buffer.
_gsg->framebuffer_release_texture(this, get_texture());
}
begin_render_texture();
_cube_map_index = -1;
_cube_map_dr = NULL;
@ -982,33 +1029,24 @@ end_frame() {
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
_gsg->end_frame();
// If _rtm_mode isn't RTM_none, it means we should copy or lock the
// framebuffer to the GraphicsOutput's associated texture after the
// frame has rendered.
if (_rtm_mode != RTM_none) {
// Handle all render-to-texture operations that use bind-to-texture
end_render_texture();
// Handle all render-to-texture operations that use copy-to-texture
for (int i=0; i<count_textures(); i++) {
RenderTextureMode rtm_mode = get_rtm_mode(i);
if ((rtm_mode == RTM_none)||(rtm_mode == RTM_bind_or_copy)) {
continue;
}
Texture *texture = get_texture(i);
PStatTimer timer(_copy_texture_pcollector);
nassertv(has_texture());
// If _rtm_mode is one of the bind-modes, it means we should attempt
// to lock the framebuffer directly to the texture memory, avoiding
// the copy.
if (_rtm_mode == RTM_bind_or_copy) {
if (display_cat.is_debug()) {
display_cat.debug()
<< "Locking texture for " << get_name() << " at frame end.\n";
}
if (!_gsg->framebuffer_bind_to_texture(this, get_texture())) {
display_cat.warning()
<< "Lock-to-texture failed, resorting to copy.\n";
_rtm_mode = RTM_copy_texture;
}
}
if ((_rtm_mode == RTM_copy_texture)||
(_rtm_mode == RTM_copy_ram)||
((_rtm_mode == RTM_triggered_copy_texture)&&(_trigger_copy))||
((_rtm_mode == RTM_triggered_copy_ram)&&(_trigger_copy))) {
_trigger_copy = false;
if ((rtm_mode == RTM_copy_texture)||
(rtm_mode == RTM_copy_ram)||
((rtm_mode == RTM_triggered_copy_texture)&&(_trigger_copy))||
((rtm_mode == RTM_triggered_copy_ram)&&(_trigger_copy))) {
if (display_cat.is_debug()) {
display_cat.debug()
<< "Copying texture for " << get_name() << " at frame end.\n";
@ -1017,30 +1055,31 @@ end_frame() {
}
RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type());
if (_cube_map_dr != (DisplayRegion *)NULL) {
if ((_rtm_mode == RTM_copy_ram)||(_rtm_mode == RTM_triggered_copy_ram)) {
_gsg->framebuffer_copy_to_ram(get_texture(), _cube_map_index,
if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
_gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
_cube_map_dr, buffer);
} else {
_gsg->framebuffer_copy_to_texture(get_texture(), _cube_map_index,
_gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
_cube_map_dr, buffer);
}
} else {
if ((_rtm_mode == RTM_copy_ram)||(_rtm_mode == RTM_triggered_copy_ram)) {
_gsg->framebuffer_copy_to_ram(get_texture(), _cube_map_index,
if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
_gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
_default_display_region, buffer);
} else {
_gsg->framebuffer_copy_to_texture(get_texture(), _cube_map_index,
_gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
_default_display_region, buffer);
}
}
}
}
_trigger_copy = false;
// If we're not single-buffered, we're now ready to flip.
if (!_gsg->get_properties().is_single_buffered()) {
_flip_ready = true;
}
// In one-shot mode, we request the GraphicsEngine to delete the
// window after we have rendered a frame.
if (_one_shot) {
@ -1059,23 +1098,53 @@ end_frame() {
// If we were rendering directly to texture, we can't delete the
// buffer until the texture is gone too.
if (_rtm_mode == RTM_bind_or_copy) {
_hold_texture = _texture;
for (int i=0; i<count_textures(); i++) {
if (get_rtm_mode(i) == RTM_bind_or_copy) {
_hold_textures.push_back(get_texture(i));
}
}
}
// We have to be sure to clear the _texture pointer, though, or
// we'll end up holding a reference to it forever.
_texture = NULL;
// And we need to stop trying to copy to the texture.
_rtm_mode = RTM_none;
// We have to be sure to clear the _textures pointers, though, or
// we'll end up holding a reference to the textures forever.
clear_render_textures();
}
_cube_map_index = -1;
_cube_map_dr = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::begin_render_texture
// Access: Public, Virtual
// Description: If the GraphicsOutput supports direct render-to-texture,
// and if any setup needs to be done during begin_frame,
// then the setup code should go here. Any textures that
// can not be rendered to directly should be reflagged
// as RTM_copy_texture.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
begin_render_texture() {
for (int i=0; i<count_textures(); i++) {
if (get_rtm_mode(i) == RTM_bind_or_copy) {
_textures[i]._rtm_mode = RTM_copy_texture;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::end_render_texture
// Access: Public, Virtual
// Description: If the GraphicsOutput supports direct render-to-texture,
// and if any setup needs to be done during end_frame,
// then the setup code should go here. Any textures that
// could not be rendered to directly should be reflagged
// as RTM_copy_texture.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
end_render_texture() {
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::change_scenes
// Access: Public
@ -1095,31 +1164,35 @@ change_scenes(DisplayRegion *new_dr) {
_cube_map_index = new_cube_map_index;
_cube_map_dr = new_dr;
if (_rtm_mode != RTM_none) {
if (_rtm_mode == RTM_bind_or_copy) {
// In render-to-texture mode, switch the rendering backend to
// the new cube map face, so that the subsequent frame will be
// rendered to the new face.
select_cube_map(new_cube_map_index);
} else if (old_cube_map_index != -1) {
// In copy-to-texture mode, copy the just-rendered framebuffer
// to the old cube map face.
nassertv(old_cube_map_dr != (DisplayRegion *)NULL);
if (display_cat.is_debug()) {
display_cat.debug()
<< "Copying texture for " << get_name() << " at scene change.\n";
display_cat.debug()
<< "cube_map_index = " << old_cube_map_index << "\n";
}
RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type());
if (_rtm_mode == RTM_copy_ram) {
_gsg->framebuffer_copy_to_ram(get_texture(), old_cube_map_index,
old_cube_map_dr, buffer);
} else {
_gsg->framebuffer_copy_to_texture(get_texture(), old_cube_map_index,
old_cube_map_dr, buffer);
for (int i=0; i<count_textures(); i++) {
Texture *texture = get_texture(i);
RenderTextureMode rtm_mode = get_rtm_mode(i);
if (rtm_mode != RTM_none) {
if (rtm_mode == RTM_bind_or_copy) {
// In render-to-texture mode, switch the rendering backend to
// the new cube map face, so that the subsequent frame will be
// rendered to the new face.
select_cube_map(new_cube_map_index);
} else if (old_cube_map_index != -1) {
// In copy-to-texture mode, copy the just-rendered framebuffer
// to the old cube map face.
nassertv(old_cube_map_dr != (DisplayRegion *)NULL);
if (display_cat.is_debug()) {
display_cat.debug()
<< "Copying texture for " << get_name() << " at scene change.\n";
display_cat.debug()
<< "cube_map_index = " << old_cube_map_index << "\n";
}
RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type());
if (rtm_mode == RTM_copy_ram) {
_gsg->framebuffer_copy_to_ram(texture, old_cube_map_index,
old_cube_map_dr, buffer);
} else {
_gsg->framebuffer_copy_to_texture(texture, old_cube_map_index,
old_cube_map_dr, buffer);
}
}
}
}

View File

@ -84,11 +84,14 @@ PUBLISHED:
INLINE GraphicsPipe *get_pipe() const;
INLINE const string &get_name() const;
INLINE bool has_texture() const;
INLINE Texture *get_texture() const;
void setup_render_texture(Texture *tex, RenderTextureMode mode);
INLINE int count_textures() const;
INLINE bool has_texture() const;
INLINE Texture *get_texture(int i=0) const;
INLINE RenderTextureMode get_rtm_mode(int i=0) const;
void clear_render_textures();
void add_render_texture(Texture *tex, RenderTextureMode mode);
void setup_render_texture(Texture *tex, bool allow_bind, bool to_ram);
INLINE int get_x_size() const;
INLINE int get_y_size() const;
INLINE bool has_size() const;
@ -157,10 +160,13 @@ public:
// It is an error to call any of the following methods from any
// thread other than the draw thread. These methods are normally
// called by the GraphicsEngine.
virtual bool begin_frame();
void clear();
virtual bool begin_frame();
virtual void end_frame();
virtual void begin_render_texture();
virtual void end_render_texture();
void change_scenes(DisplayRegion *new_dr);
virtual void select_cube_map(int cube_map_index);
@ -182,11 +188,15 @@ public:
protected:
class RenderTexture {
public:
PT(Texture) _texture;
RenderTextureMode _rtm_mode;
};
PT(GraphicsStateGuardian) _gsg;
PT(GraphicsPipe) _pipe;
string _name;
PT(Texture) _texture;
RenderTextureMode _rtm_mode;
pvector<RenderTexture> _textures;
bool _flip_ready;
bool _needs_context;
int _cube_map_index;
@ -211,12 +221,12 @@ protected:
bool _inverted;
bool _delete_flag;
// This weak pointer is used to keep track of whether the buffer's
// bound Texture has been deleted or not. Until it has, we don't
// auto-close the buffer (since that would deallocate the memory
// associated with the texture).
WPT(Texture) _hold_texture;
// These weak pointers are used to keep track of whether the
// buffer's bound Texture has been deleted or not. Until they have,
// we don't auto-close the buffer (since that would deallocate the
// memory associated with the texture).
pvector<WPT(Texture)> _hold_textures;
protected:
Mutex _lock;
// protects _display_regions.

View File

@ -971,39 +971,6 @@ end_draw_primitives() {
_vertex_data = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::framebuffer_bind_to_texture
// Access: Public, Virtual
// Description: Works in lieu of copy_texture() to bind the primary
// render buffer of the framebuffer to the indicated
// texture (which must have been created via
// GraphicsOutput::setup_render_texture()).
//
// If supported by the graphics backend, this will make
// the framebuffer memory directly accessible within the
// texture, but the frame cannot be rendered again until
// framebuffer_release_texture() is called.
//
// The return value is true if successful, false on
// failure.
////////////////////////////////////////////////////////////////////
bool GraphicsStateGuardian::
framebuffer_bind_to_texture(GraphicsOutput *, Texture *) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::framebuffer_release_texture
// Access: Public, Virtual
// Description: Undoes a previous call to
// framebuffer_bind_to_texture(). The framebuffer may
// again be rendered into, and the contents of the
// texture is undefined.
////////////////////////////////////////////////////////////////////
void GraphicsStateGuardian::
framebuffer_release_texture(GraphicsOutput *, Texture *) {
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::do_issue_color_scale
// Access: Public, Virtual

View File

@ -191,9 +191,6 @@ public:
virtual void draw_points(const GeomPoints *primitive);
virtual void end_draw_primitives();
virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex);
virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex);
INLINE bool reset_if_new();
INLINE void mark_new();
virtual void reset();

View File

@ -202,10 +202,7 @@ public:
(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb)=0;
virtual bool framebuffer_copy_to_ram
(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb)=0;
virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex)=0;
virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex)=0;
virtual CoordinateSystem get_internal_coordinate_system() const=0;
virtual void bind_light(PointLight *light_obj, const NodePath &light,

View File

@ -89,6 +89,75 @@ begin_frame() {
return GraphicsBuffer::begin_frame();
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsStateGuardian::begin_render_texture
// Access: Public, Virtual
// Description: If the GraphicsOutput supports direct render-to-texture,
// and if any setup needs to be done during begin_frame,
// then the setup code should go here. Any textures that
// can not be rendered to directly should be reflagged
// as RTM_copy_texture.
////////////////////////////////////////////////////////////////////
void wglGraphicsBuffer::
begin_render_texture() {
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_V(wglgsg, _gsg);
if (_gsg->get_properties().is_single_buffered()) {
wglgsg->_wglReleaseTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
} else {
wglgsg->_wglReleaseTexImageARB(_pbuffer, WGL_BACK_LEFT_ARB);
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::end_render_texture
// Access: Public, Virtual
// Description: If the GraphicsOutput supports direct render-to-texture,
// and if any setup needs to be done during end_frame,
// then the setup code should go here. Any textures that
// could not be rendered to directly should be reflagged
// as RTM_copy_texture.
////////////////////////////////////////////////////////////////////
void wglGraphicsBuffer::
end_render_texture() {
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_V(wglgsg, _gsg);
// Find the color texture, if there is one. That one can be bound to
// the framebuffer. All others must be marked RTM_copy_to_texture.
int tex_index = -1;
for (int i=0; i<count_textures(); i++) {
if (get_rtm_mode(i) == RTM_bind_or_copy) {
if ((get_texture(i)->get_format() != Texture::F_depth_component)&&
(get_texture(i)->get_format() != Texture::F_stencil_index)&&
(tex_index < 0)) {
tex_index = i;
} else {
_textures[i]._rtm_mode = RTM_copy_texture;
}
}
}
if (tex_index >= 0) {
Texture *tex = get_texture(tex_index);
TextureContext *tc = tex->prepare_now(_gsg->get_prepared_objects(), _gsg);
nassertv(tc != (TextureContext *)NULL);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
GLenum target = wglgsg->get_texture_target(tex->get_texture_type());
if (target == GL_NONE) {
_textures[tex_index]._rtm_mode = RTM_copy_texture;
return;
}
GLP(BindTexture)(target, gtc->_index);
if (_gsg->get_properties().is_single_buffered()) {
wglgsg->_wglBindTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
} else {
wglgsg->_wglBindTexImageARB(_pbuffer, WGL_BACK_LEFT_ARB);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsBuffer::select_cube_map
// Access: Public, Virtual
@ -231,29 +300,6 @@ open_buffer() {
}
_pbuffer_dc = wglgsg->_wglGetPbufferDCARB(_pbuffer);
if (wgldisplay_cat.is_debug()) {
wgldisplay_cat.debug()
<< "Created PBuffer " << _pbuffer << ", DC " << _pbuffer_dc << "\n";
switch (_rtm_mode) {
case RTM_bind_or_copy:
wgldisplay_cat.debug()
<< "pbuffer renders directly to texture.\n";
break;
case RTM_copy_texture:
wgldisplay_cat.debug()
<< "pbuffer copies indirectly into texture.\n";
break;
case RTM_copy_ram:
wgldisplay_cat.debug()
<< "pbuffer copies indirectly into system RAM.\n";
break;
default:
break;
}
}
wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc));
wglgsg->report_my_gl_errors();
@ -286,9 +332,15 @@ make_pbuffer(HDC twindow_dc) {
if (wglgsg->_supports_pixel_format) {
bool got_pbuffer_format = false;
bool any_binds = false;
for (int i=0; i<count_textures(); i++) {
if (get_rtm_mode(i) == RTM_bind_or_copy) {
any_binds = true;
}
}
if ((_rtm_mode == RTM_bind_or_copy) &&
wglgsg->_supports_render_texture) {
if (any_binds && wglgsg->_supports_render_texture) {
// First, try to get a pbuffer format that supports
// render-to-texture.
int new_pbformat = choose_pbuffer_format(twindow_dc, true);
@ -299,8 +351,13 @@ make_pbuffer(HDC twindow_dc) {
}
if (!got_pbuffer_format) {
// Failing that, just get a matching pbuffer format.
_rtm_mode = RTM_copy_texture;
// Failing that, just get a matching pbuffer format,
// and disable RTM_bind_or_copy.
for (int i=0; i<count_textures(); i++) {
if (get_rtm_mode(i) == RTM_bind_or_copy) {
_textures[i]._rtm_mode = RTM_copy_texture;
}
}
int new_pbformat = choose_pbuffer_format(twindow_dc, false);
if (new_pbformat != 0) {
pbformat = new_pbformat;
@ -322,8 +379,18 @@ make_pbuffer(HDC twindow_dc) {
int iattrib_list[max_attrib_list];
int ni = 0;
if (_rtm_mode == RTM_bind_or_copy) {
nassertr(_texture != (Texture *)NULL, false);
// Find the texture to bind to the color buffer.
Texture *bindtexture = NULL;
for (int i=0; i<count_textures(); i++) {
if ((get_rtm_mode(i) == RTM_bind_or_copy)&&
(get_texture(i)->get_format() != Texture::F_depth_component)&&
(get_texture(i)->get_format() != Texture::F_stencil_index)) {
bindtexture = get_texture(i);
break;
}
}
if (bindtexture != 0) {
if (_gsg->get_properties().get_frame_buffer_mode() & FrameBufferProperties::FM_alpha) {
iattrib_list[ni++] = WGL_TEXTURE_FORMAT_ARB;
@ -333,12 +400,12 @@ make_pbuffer(HDC twindow_dc) {
iattrib_list[ni++] = WGL_TEXTURE_RGB_ARB;
}
if (_texture->uses_mipmaps()) {
if (bindtexture->uses_mipmaps()) {
iattrib_list[ni++] = WGL_MIPMAP_TEXTURE_ARB;
iattrib_list[ni++] = 1;
}
switch (_texture->get_texture_type()) {
switch (bindtexture->get_texture_type()) {
case Texture::TT_cube_map:
iattrib_list[ni++] = WGL_TEXTURE_TARGET_ARB;
iattrib_list[ni++] = WGL_TEXTURE_CUBE_MAP_ARB;
@ -353,7 +420,7 @@ make_pbuffer(HDC twindow_dc) {
iattrib_list[ni++] = WGL_TEXTURE_TARGET_ARB;
iattrib_list[ni++] = WGL_TEXTURE_2D_ARB;
}
}
}
// Terminate the list.
nassertr(ni <= max_attrib_list, false);

View File

@ -52,6 +52,9 @@ public:
virtual void make_current();
virtual void release_gsg();
virtual void begin_render_texture();
virtual void end_render_texture();
virtual void process_events();
protected:

View File

@ -63,66 +63,6 @@ wglGraphicsStateGuardian::
}
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsStateGuardian::framebuffer_bind_to_texture
// Access: Public, Virtual
// Description: Works in lieu of copy_texture() to bind the primary
// render buffer of the framebuffer to the indicated
// texture (which must have been created via
// GraphicsOutput::setup_render_texture()).
//
// If supported by the graphics backend, this will make
// the framebuffer memory directly accessible within the
// texture, but the frame cannot be rendered again until
// framebuffer_release_texture() is called.
//
// The return value is true if successful, false on
// failure.
////////////////////////////////////////////////////////////////////
bool wglGraphicsStateGuardian::
framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex) {
wglGraphicsBuffer *buffer;
DCAST_INTO_R(buffer, win, false);
TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
nassertr(tc != (TextureContext *)NULL, false);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
GLenum target = get_texture_target(tex->get_texture_type());
if (target == GL_NONE) {
// Invalid texture, can't bind it.
return false;
}
GLP(BindTexture)(target, gtc->_index);
if (get_properties().is_single_buffered()) {
_wglBindTexImageARB(buffer->_pbuffer, WGL_FRONT_LEFT_ARB);
} else {
_wglBindTexImageARB(buffer->_pbuffer, WGL_BACK_LEFT_ARB);
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsStateGuardian::framebuffer_release_texture
// Access: Public, Virtual
// Description: Undoes a previous call to
// framebuffer_bind_to_texture(). The framebuffer may
// again be rendered into, and the contents of the
// texture is undefined.
////////////////////////////////////////////////////////////////////
void wglGraphicsStateGuardian::
framebuffer_release_texture(GraphicsOutput *win, Texture *) {
wglGraphicsBuffer *buffer;
DCAST_INTO_V(buffer, win);
if (get_properties().is_single_buffered()) {
_wglReleaseTexImageARB(buffer->_pbuffer, WGL_FRONT_LEFT_ARB);
} else {
_wglReleaseTexImageARB(buffer->_pbuffer, WGL_BACK_LEFT_ARB);
}
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsStateGuardian::reset
// Access: Public, Virtual

View File

@ -43,9 +43,6 @@ public:
INLINE bool made_context() const;
INLINE HGLRC get_context(HDC hdc);
virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex);
virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex);
virtual void reset();
INLINE HDC get_twindow_dc();