*** empty log message ***

This commit is contained in:
Josh Yelon 2006-04-05 16:47:19 +00:00
parent 9d3d749a54
commit 6d0692fec6
37 changed files with 639 additions and 719 deletions

View File

@ -20,6 +20,8 @@ class BufferViewer(DirectObject):
self.cullsort = 10000
self.cards = []
self.cardindex = 0
self.cardmaker = CardMaker("cubemaker")
self.cardmaker.setFrame(-1,1,-1,1)
self.task = 0
self.window = 0
self.dirty = 1
@ -39,7 +41,7 @@ class BufferViewer(DirectObject):
# started.
self.enable(self.enabled)
def isValidTextureSet(self, list):
def isValidTextureSet(self, x):
"""Access: private. Returns true if the parameter is a
list of GraphicsOutput and Texture, or the keyword 'all'."""
if (isinstance(x, list)):
@ -270,10 +272,18 @@ class BufferViewer(DirectObject):
for itex in range(win.countTextures()):
tex = win.getTexture(itex)
if (include.has_key(tex)) and (exclude.has_key(tex)==0):
card = win.getTextureCard()
card.setTexture(tex)
cards.append(card)
if (tex.getTextureType() == Texture.TTCubeMap):
for face in range(6):
self.cardmaker.setUvRangeCube(face)
card = NodePath(self.cardmaker.generate())
card.setTexture(tex)
cards.append(card)
else:
card = win.getTextureCard()
card.setTexture(tex)
cards.append(card)
wins.append(win)
exclude[tex] = 1
self.cards = cards
if (len(cards)==0):
self.task = 0

View File

@ -88,3 +88,7 @@ egg-object-type-direct-widget <Scalar> collide-mask { 0x80000000 } <Collide> {
# Define a new cull bin that will render on top of everything else.
cull-bin gui-popup 60 unsorted
# Paranoid clock. This fixes flaky hardware clocks.
paranoid-clock 1

View File

@ -64,6 +64,7 @@ PUBLISHED:
INLINE bool has_mode(int bit) const;
INLINE bool is_single_buffered() const;
INLINE bool is_stereo() const;
bool subsumes(const FrameBufferProperties &prop) const;
INLINE void set_frame_buffer_mode(int frameBuffer_mode);

View File

@ -450,7 +450,6 @@ remove_all_windows() {
_windows.clear();
_app.do_release(this);
_app.do_close(this);
terminate_threads();
}
@ -922,7 +921,6 @@ cull_and_draw_together(const GraphicsEngine::Windows &wlist) {
for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
GraphicsOutput *win = (*wi);
if (win->is_active() && win->get_gsg()->is_active()) {
win->get_gsg()->set_current_properties(&win->get_fb_properties());
if (win->begin_frame(GraphicsOutput::FM_render)) {
win->clear();
@ -1088,7 +1086,6 @@ draw_bins(const GraphicsEngine::Windows &wlist) {
for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
GraphicsOutput *win = (*wi);
if (win->is_active() && win->get_gsg()->is_active()) {
win->get_gsg()->set_current_properties(&win->get_fb_properties());
if (win->begin_frame(GraphicsOutput::FM_render)) {
win->clear();
@ -1149,7 +1146,6 @@ make_contexts(const GraphicsEngine::Windows &wlist) {
Windows::const_iterator wi;
for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
GraphicsOutput *win = (*wi);
win->get_gsg()->set_current_properties(&win->get_fb_properties());
if (win->begin_frame(GraphicsOutput::FM_refresh)) {
win->end_frame(GraphicsOutput::FM_refresh);
}
@ -1599,27 +1595,6 @@ terminate_threads() {
thread->_cv_mutex.lock();
}
// Now tell them to release their windows' graphics contexts.
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
RenderThread *thread = (*ti).second;
while (thread->_thread_state != TS_wait) {
thread->_cv_done.wait();
}
thread->_thread_state = TS_do_release;
thread->_cv_start.signal();
thread->_cv_mutex.release();
}
// Grab the mutex again to wait for the above to complete.
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
RenderThread *thread = (*ti).second;
thread->_cv_mutex.lock();
while (thread->_thread_state != TS_wait) {
thread->_cv_done.wait();
}
}
// Now tell them to close their windows and terminate.
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
RenderThread *thread = (*ti).second;
@ -1776,30 +1751,6 @@ remove_window(GraphicsOutput *window) {
Windows::iterator wi;
wi = _cdraw.find(ptwin);
if (wi != _cdraw.end()) {
// The window is on our _cdraw list, meaning its GSG operations are
// serviced by this thread (cull and draw in the same operation).
// Move it to the pending release thread so we can release the GSG
// when the thread next runs. We can't do this immediately,
// because we might not have been called from the subthread.
_pending_release.push_back(ptwin);
_cdraw.erase(wi);
}
wi = _draw.find(ptwin);
if (wi != _draw.end()) {
// The window is on our _draw list, meaning its GSG operations are
// serviced by this thread (draw performed on this thread).
// Move it to the pending release thread so we can release the GSG
// when the thread next runs. We can't do this immediately,
// because we might not have been called from the subthread.
_pending_release.push_back(ptwin);
_draw.erase(wi);
}
wi = _window.find(ptwin);
if (wi != _window.end()) {
// The window is on our _window list, meaning its open/close
@ -1924,22 +1875,6 @@ do_flip(GraphicsEngine *engine) {
engine->flip_windows(_draw);
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::WindowRenderer::do_release
// Access: Public
// Description: Releases the rendering contexts for all windows on
// the _draw list.
////////////////////////////////////////////////////////////////////
void GraphicsEngine::WindowRenderer::
do_release(GraphicsEngine *) {
MutexHolder holder(_wl_lock);
Windows::iterator wi;
for (wi = _draw.begin(); wi != _draw.end(); ++wi) {
GraphicsOutput *win = (*wi);
win->release_gsg();
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::WindowRenderer::do_close
// Access: Public
@ -1982,16 +1917,6 @@ void GraphicsEngine::WindowRenderer::
do_pending(GraphicsEngine *engine) {
MutexHolder holder(_wl_lock);
if (!_pending_release.empty()) {
// Release any GSG's that were waiting.
Windows::iterator wi;
for (wi = _pending_release.begin(); wi != _pending_release.end(); ++wi) {
GraphicsOutput *win = (*wi);
win->release_gsg();
}
_pending_release.clear();
}
if (!_pending_close.empty()) {
// Close any windows that were pending closure, but only if their
// associated GSG has already been released.
@ -2128,7 +2053,6 @@ thread_main() {
case TS_do_release:
do_pending(_engine);
do_release(_engine);
break;
case TS_do_windows:

View File

@ -294,7 +294,6 @@ private:
Windows _window; // window stage, i.e. process windowing events
// These are not kept sorted.
Windows _pending_release; // moved from _draw, pending release_gsg.
Windows _pending_close; // moved from _window, pending close.
GSGs _gsgs; // draw stage

View File

@ -106,12 +106,27 @@ get_texture(int i) const {
return _textures[i]._texture;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::get_texture_plane
// Access: Published
// Description: Returns the RenderTexturePlane associated with the
// nth render-texture. Returns 0 if there is no such
// texture.
////////////////////////////////////////////////////////////////////
INLINE GraphicsOutput::RenderTexturePlane GraphicsOutput::
get_texture_plane(int i) const {
if ((i < 0) || (i >= ((int)_textures.size()))) {
return (RenderTexturePlane)0;
}
return _textures[i]._plane;
}
////////////////////////////////////////////////////////////////////
// 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.
// nth render-texture. Returns RTM_none if there is
// no such texture.
////////////////////////////////////////////////////////////////////
INLINE GraphicsOutput::RenderTextureMode GraphicsOutput::
get_rtm_mode(int i) const {

View File

@ -218,23 +218,49 @@ clear_render_textures() {
//
// If tex is not NULL, it is the texture that will be
// set up for rendering into; otherwise, a new Texture
// object will be created (in which case you may call
// get_texture() to retrieve the new texture pointer
// later).
// object will be created, in which case you may call
// get_texture() to retrieve the new texture pointer.
//
// You can specify a bitplane to attach the texture to.
// the legal choices are:
//
// * RTP_depth
// * RTP_stencil
// * RTP_color
// * RTP_aux_rgba_0
// * RTP_aux_rgba_1
// * RTP_aux_rgba_2
// * RTP_aux_rgba_3
//
// If you do not specify a bitplane to attach the
// texture to, this routine will use a default based
// on the texture's format:
//
// * F_depth_component attaches to RTP_depth
// * F_stencil_index attaches to RTP_stencil
// * all other formats attach to RTP_color.
//
// The texture's format will be changed to match
// the format of the bitplane to which it is attached.
// For example, if you pass in an F_rgba texture and
// order that it be attached to RTP_depth, it will turn
// into an F_depth_component texture.
//
// Also see make_texture_buffer(), which is a
// higher-level interface for preparing
// render-to-a-texture mode.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
add_render_texture(Texture *tex, RenderTextureMode mode) {
add_render_texture(Texture *tex, RenderTextureMode mode,
RenderTexturePlane plane) {
if (mode == RTM_none) {
return;
}
MutexHolder holder(_lock);
throw_event("render-texture-targets-changed");
// Create texture if necessary.
if (tex == (Texture *)NULL) {
tex = new Texture(get_name());
tex->set_wrap_u(Texture::WM_clamp);
@ -242,13 +268,45 @@ add_render_texture(Texture *tex, RenderTextureMode mode) {
} else {
tex->clear_ram_image();
}
tex->set_match_framebuffer_format(true);
// Choose a default bitplane.
if (plane == RTP_COUNT) {
if (tex->get_format()==Texture::F_depth_component) {
plane = RTP_depth;
} else if (tex->get_format()==Texture::F_stencil_index) {
plane = RTP_stencil;
} else {
plane = RTP_color;
}
}
// Set the texture's format to match the bitplane.
// (And validate the bitplane, while we're at it).
if (plane == RTP_depth) {
tex->set_format(Texture::F_depth_component);
tex->set_match_framebuffer_format(true);
} else if (plane == RTP_stencil) {
tex->set_format(Texture::F_stencil_index);
tex->set_match_framebuffer_format(true);
} else if ((plane == RTP_color)||
(plane == RTP_aux_rgba_0)||
(plane == RTP_aux_rgba_1)||
(plane == RTP_aux_rgba_2)||
(plane == RTP_aux_rgba_3)) {
tex->set_format(Texture::F_rgba);
tex->set_match_framebuffer_format(true);
} else {
display_cat.error() <<
"add_render_texture: invalid bitplane specified.\n";
return;
}
// 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).
tex->set_x_size(get_x_size());
tex->set_y_size(get_y_size());
tex->set_x_size(Texture::up_to_power_2(get_x_size()));
tex->set_y_size(Texture::up_to_power_2(get_y_size()));
if ((mode == RTM_bind_or_copy)&&(support_render_texture==0)) {
mode = RTM_copy_texture;
@ -259,36 +317,15 @@ add_render_texture(Texture *tex, RenderTextureMode mode) {
}
}
RenderTexture result;
result._texture = tex;
result._plane = plane;
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();
}
}
////////////////////////////////////////////////////////////////////
@ -778,21 +815,6 @@ make_cube_map(const string &name, int size, NodePath &camera_rig,
tex->set_wrap_v(Texture::WM_clamp);
GraphicsOutput *buffer;
// I'll remove this permanently in a few days.
// if (show_buffers) {
// // If show_buffers is true, we'd like to create a window with the
// // six buffers spread out and all visible at once, for the user's
// // convenience.
// buffer = make_texture_buffer(name, size * 3, size * 2, tex, to_ram);
// tex->set_x_size(size);
// tex->set_y_size(size);
//
// } else {
// // In the normal case, the six buffers are stacked on top of each
// // other like pancakes.
// buffer = make_texture_buffer(name, size, size, tex, to_ram);
// }
buffer = make_texture_buffer(name, size, size, tex, to_ram);
// We don't need to clear the overall buffer; instead, we'll clear
@ -811,13 +833,6 @@ make_cube_map(const string &name, int size, NodePath &camera_rig,
camera_np.look_at(cube_faces[i]._look_at, cube_faces[i]._up);
DisplayRegion *dr;
// I'll remove this permanently in a few days. - Josh
// if (show_buffers) {
// const ShowBuffersCubeMapRegions &r = cube_map_regions[i];
// dr = buffer->make_display_region(r.l, r.r, r.b, r.t);
// } else {
// dr = buffer->make_display_region();
// }
dr = buffer->make_display_region();
dr->set_cube_map_index(i);
@ -1093,21 +1108,6 @@ void GraphicsOutput::
select_cube_map(int) {
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::release_gsg
// Access: Public
// Description: Releases the current GSG pointer, if it is currently
// held, and resets the GSG to NULL. The window will be
// permanently unable to render; this is normally called
// only just before destroying the window. This should
// only be called from within the draw thread.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
release_gsg() {
_gsg.clear();
_active = false;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::begin_flip
// Access: Public, Virtual

View File

@ -82,6 +82,28 @@ PUBLISHED:
RTM_triggered_copy_ram,
};
// It seems awkward to have this type, and also
// RenderBuffer::Type. However, the fact that RenderBuffer::Type
// is a bitmask makes it awfully awkward to work with.
enum RenderTexturePlane {
RTP_color,
RTP_depth,
RTP_stencil,
RTP_aux_rgba_0,
RTP_aux_rgba_1,
RTP_aux_rgba_2,
RTP_aux_rgba_3,
RTP_aux_hrgba_0,
RTP_aux_hrgba_1,
RTP_aux_hrgba_2,
RTP_aux_hrgba_3,
RTP_aux_float_0,
RTP_aux_float_1,
RTP_aux_float_2,
RTP_aux_float_3,
RTP_COUNT
};
// There are many reasons to call begin_frame/end_frame.
enum FrameMode {
FM_render, // We are rendering a frame.
@ -98,9 +120,11 @@ PUBLISHED:
INLINE int count_textures() const;
INLINE bool has_texture() const;
INLINE Texture *get_texture(int i=0) const;
INLINE RenderTexturePlane get_texture_plane(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 add_render_texture(Texture *tex, RenderTextureMode mode,
RenderTexturePlane bitplane=RTP_COUNT);
void setup_render_texture(Texture *tex, bool allow_bind, bool to_ram);
INLINE int get_x_size() const;
@ -200,8 +224,6 @@ public:
void change_scenes(DisplayRegion *new_dr);
virtual void select_cube_map(int cube_map_index);
virtual void release_gsg();
// These methods will be called within the app (main) thread.
virtual void begin_flip();
virtual void end_flip();
@ -226,6 +248,7 @@ protected:
class RenderTexture {
public:
PT(Texture) _texture;
RenderTexturePlane _plane;
RenderTextureMode _rtm_mode;
};
PT(GraphicsStateGuardian) _gsg;

View File

@ -185,6 +185,8 @@ public:
virtual void end_scene();
virtual void end_frame();
void set_current_properties(FrameBufferProperties *properties);
virtual bool depth_offset_decals();
virtual CPT(RenderState) begin_decal_base_first();
virtual CPT(RenderState) begin_decal_nested();
@ -244,8 +246,6 @@ protected:
virtual void bind_clip_plane(const NodePath &plane, int plane_id);
virtual void end_bind_clip_planes();
void set_current_properties(FrameBufferProperties *properties);
virtual void free_pointers();
virtual void close_gsg();
void panic_deactivate();

View File

@ -38,16 +38,19 @@ public:
T_aux_rgba_1 = 0x00000002,
T_aux_rgba_2 = 0x00000004,
T_aux_rgba_3 = 0x00000008,
T_aux_rgba_ALL = 0x0000000F,
T_aux_hrgba_0 = 0x00000010,
T_aux_hrgba_1 = 0x00000020,
T_aux_hrgba_2 = 0x00000040,
T_aux_hrgba_0 = 0x00000010, // These can't really be implemented until
T_aux_hrgba_1 = 0x00000020, // we have support for hrgba textures.
T_aux_hrgba_2 = 0x00000040, // I've just added the bits for the future.
T_aux_hrgba_3 = 0x00000080,
T_aux_hrgba_ALL = 0x000000F0,
T_aux_float_0 = 0x00000100,
T_aux_float_1 = 0x00000200,
T_aux_float_2 = 0x00000400,
T_aux_float_0 = 0x00000100, // These can't really be implemented until
T_aux_float_1 = 0x00000200, // we have support for float textures.
T_aux_float_2 = 0x00000400, // I've just added the bits for the future.
T_aux_float_3 = 0x00000800,
T_aux_float_ALL = 0x00000F00,
T_aux_undef_0 = 0x00001000,
T_aux_undef_1 = 0x00002000,

View File

@ -95,6 +95,7 @@ begin_frame(FrameMode mode) {
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
return _gsg->begin_frame();
}
@ -328,20 +329,6 @@ select_cube_map(int cube_map_index) {
}
}
////////////////////////////////////////////////////////////////////
// Function: wdxGraphicsBuffer8::release_gsg
// Access: Public, Virtual
// Description: Releases the current GSG pointer, if it is currently
// held, and resets the GSG to NULL. The window will be
// permanently unable to render; this is normally called
// only just before destroying the window. This should
// only be called from within the draw thread.
////////////////////////////////////////////////////////////////////
void wdxGraphicsBuffer8::
release_gsg() {
GraphicsBuffer::release_gsg();
}
////////////////////////////////////////////////////////////////////
// Function: wdxGraphicsBuffer8::process_events
// Access: Public, Virtual
@ -398,6 +385,9 @@ close_buffer() {
this -> _new_z_stencil_surface -> Release ( );
this -> _new_z_stencil_surface = NULL;
}
_gsg.clear();
_active = false;
}
_cube_map_index = -1;

View File

@ -48,7 +48,6 @@ public:
virtual void end_frame(FrameMode mode);
virtual void select_cube_map(int cube_map_index);
virtual void release_gsg();
virtual void process_events();

View File

@ -98,7 +98,8 @@ begin_frame(FrameMode mode) {
if (mode == FM_render) {
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
bool return_val = _gsg->begin_frame();
_dxgsg->set_render_target();
return return_val;
@ -251,6 +252,10 @@ verify_window_sizes(int numsizes, int *dimen) {
void wdxGraphicsWindow8::
close_window() {
wdxdisplay8_cat.debug() << "wdx closed window\n";
if (_gsg != (GraphicsStateGuardian*)NULL) {
_gsg.clear();
_active = false;
}
_dxgsg->release_swap_chain(&_wcontext);
WinGraphicsWindow::close_window();
}

View File

@ -93,6 +93,7 @@ begin_frame(FrameMode mode) {
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
return _gsg->begin_frame();
}
@ -364,20 +365,6 @@ select_cube_map(int cube_map_index) {
}
}
////////////////////////////////////////////////////////////////////
// Function: wdxGraphicsBuffer9::release_gsg
// Access: Public, Virtual
// Description: Releases the current GSG pointer, if it is currently
// held, and resets the GSG to NULL. The window will be
// permanently unable to render; this is normally called
// only just before destroying the window. This should
// only be called from within the draw thread.
////////////////////////////////////////////////////////////////////
void wdxGraphicsBuffer9::
release_gsg() {
GraphicsBuffer::release_gsg();
}
////////////////////////////////////////////////////////////////////
// Function: wdxGraphicsBuffer9::process_events
// Access: Public, Virtual
@ -434,6 +421,9 @@ close_buffer() {
this -> _new_z_stencil_surface -> Release ( );
this -> _new_z_stencil_surface = NULL;
}
_gsg.clear();
_active = false;
}
_cube_map_index = -1;

View File

@ -48,8 +48,6 @@ public:
virtual void end_frame(FrameMode mode);
virtual void select_cube_map(int cube_map_index);
virtual void release_gsg();
virtual void process_events();
protected:

View File

@ -119,6 +119,7 @@ begin_frame(FrameMode mode) {
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
bool return_val = _gsg->begin_frame();
_dxgsg->set_render_target();
return return_val;
@ -252,6 +253,10 @@ verify_window_sizes(int numsizes, int *dimen) {
void wdxGraphicsWindow9::
close_window() {
wdxdisplay9_cat.debug() << "wdx closed window\n";
if (_gsg != (GraphicsStateGuardian *)NULL) {
_gsg.clear();
_active = false;
}
_dxgsg->release_swap_chain(&_wcontext);
WinGraphicsWindow::close_window();
}

View File

@ -40,17 +40,10 @@ CLP(GraphicsBuffer)(GraphicsPipe *pipe,
_fbo = 0;
_rb_size_x = 0;
_rb_size_y = 0;
for (int i=0; i<SLOT_COUNT; i++) {
for (int i=0; i<RTP_COUNT; i++) {
_rb[i] = 0;
_tex[i] = 0;
}
_attach_point[SLOT_depth] = GL_DEPTH_ATTACHMENT_EXT;
_attach_point[SLOT_stencil] = GL_STENCIL_ATTACHMENT_EXT;
_attach_point[SLOT_color] = GL_COLOR_ATTACHMENT0_EXT;
_slot_format[SLOT_depth] = GL_DEPTH_COMPONENT;
_slot_format[SLOT_stencil] = GL_STENCIL_INDEX;
_slot_format[SLOT_color] = GL_RGBA;
}
////////////////////////////////////////////////////////////////////
@ -77,9 +70,6 @@ begin_frame(FrameMode mode) {
return false;
}
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_R(glgsg, _gsg, false);
if (!_host->begin_frame(FM_parasite)) {
return false;
}
@ -88,33 +78,52 @@ begin_frame(FrameMode mode) {
if (mode == FM_render) {
rebuild_bitplanes();
clear_cube_map_selection();
// Verify that the frame buffer is ready for rendering.
GLenum status = glgsg->_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
GLCAT.error() << "EXT_framebuffer_object reports non-framebuffer-completeness.\n";
switch(status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT\n"; break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT\n"; break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT\n"; break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_FORMATS_EXT\n"; break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT\n"; break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT\n"; break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
GLCAT.error() << "FRAMEBUFFER_UNSUPPORTED_EXT\n"; break;
default:
GLCAT.error() << "OTHER PROBLEM\n"; break;
}
glgsg->bind_fbo(0);
if (!check_fbo()) {
return false;
}
}
_gsg->set_current_properties(&get_fb_properties());
return true;
}
////////////////////////////////////////////////////////////////////
// Function: glGraphicsBuffer::check_fbo
// Access: Private
// Description: Calls 'glCheckFramebufferStatus'. On error,
// prints out an appropriate error message and unbinds
// the fbo. Returns true for OK or false for error.
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsBuffer)::
check_fbo() {
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_R(glgsg, _gsg, false);
GLenum status = glgsg->_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
GLCAT.error() << "EXT_framebuffer_object reports non-framebuffer-completeness.\n";
switch(status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT\n"; break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT\n"; break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT\n"; break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_FORMATS_EXT\n"; break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT\n"; break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT\n"; break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
GLCAT.error() << "FRAMEBUFFER_UNSUPPORTED_EXT\n"; break;
default:
GLCAT.error() << "OTHER PROBLEM\n"; break;
}
glgsg->bind_fbo(0);
return false;
}
return true;
}
@ -151,26 +160,45 @@ rebuild_bitplanes() {
_host->get_y_size());
}
}
int desired_x = _x_size;
int desired_y = _y_size;
int bitplane_x = _x_size;
int bitplane_y = _y_size;
if (!glgsg->get_supports_tex_non_pow2()) {
desired_x = Texture::up_to_power_2(desired_x);
desired_y = Texture::up_to_power_2(desired_y);
bitplane_x = Texture::up_to_power_2(bitplane_x);
bitplane_y = Texture::up_to_power_2(bitplane_y);
}
bool rb_resize = false;
if ((bitplane_x != _rb_size_x)||
(bitplane_y != _rb_size_y)) {
_rb_size_x = bitplane_x;
_rb_size_y = bitplane_y;
rb_resize = true;
}
// Scan the textures list and determine what should be attached.
// These variables indicate what should be bound to each bitplane.
Texture *attach[SLOT_COUNT];
for (int i=0; i<SLOT_COUNT; i++) {
attach[i] = 0;
Texture *attach[RTP_COUNT];
attach[RTP_color] = 0;
attach[RTP_depth] = 0;
attach[RTP_stencil] = 0;
for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
attach[RTP_aux_rgba_0+i] = 0;
}
for (int i=0; i<_fb_properties.get_aux_hrgba(); i++) {
attach[RTP_aux_hrgba_0+i] = 0;
}
for (int i=0; i<_fb_properties.get_aux_float(); i++) {
attach[RTP_aux_float_0+i] = 0;
}
// Sort the textures list into appropriate slots.
for (int i=0; i<count_textures(); i++) {
if (get_rtm_mode(i) != RTM_bind_or_copy) {
continue;
}
Texture *tex = get_texture(i);
Texture::Format fmt = tex->get_format();
RenderTexturePlane plane = get_texture_plane(i);
// If it's a not a 2D texture or a cube map, punt it.
if ((tex->get_texture_type() != Texture::TT_2d_texture)&&
(tex->get_texture_type() != Texture::TT_cube_map)) {
@ -178,106 +206,123 @@ rebuild_bitplanes() {
continue;
}
// Identify right attachment point.
int slot = SLOT_COUNT;
if (fmt == Texture::F_depth_component) {
slot = SLOT_depth;
} else if (fmt == Texture::F_stencil_index) {
slot = SLOT_stencil;
} else if ((fmt == Texture::F_rgba)||(fmt == Texture::F_rgb)) {
slot = SLOT_color;
} else {
_textures[i]._rtm_mode = RTM_copy_texture;
continue;
}
// If there's already a texture bound to this slot,
// then punt this texture.
if (attach[slot]) {
// If I can't find an appropriate slot, or if there's
// already a texture bound to this slot, then punt
// this texture.
if (attach[plane]) {
_textures[i]._rtm_mode = RTM_copy_texture;
continue;
}
// Assign the texture to this slot.
attach[slot] = tex;
attach[plane] = tex;
}
// For all slots, update the slot.
for (int slot=0; slot<SLOT_COUNT; slot++) {
if (slot == SLOT_stencil) continue;
Texture *tex = attach[slot];
if (tex) {
// If the texture is already bound to the slot, and it's
// the right size, then no update of this slot is needed.
if ((_tex[slot] == tex)&&
(tex->get_x_size() == desired_x)&&
(tex->get_y_size() == desired_y)) {
continue;
}
// Bind the texture to the slot.
tex->set_x_size(desired_x);
tex->set_y_size(desired_y);
TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg);
nassertv(tc != (TextureContext *)NULL);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
if (tex->get_texture_type() == Texture::TT_2d_texture) {
glgsg->upload_blank_image(tex, gtc);
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, _attach_point[slot],
GL_TEXTURE_2D, gtc->_index, 0);
} else {
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, _attach_point[slot],
GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, gtc->_index, 0);
}
_tex[slot] = tex;
// If there was a renderbuffer bound to this slot, delete it.
if (_rb[slot] != 0) {
glgsg->_glDeleteRenderbuffers(1, &(_rb[slot]));
_rb[slot] = 0;
}
} else {
// If a renderbuffer is already attached to the slot, and it's
// the right size, then no update of this slot is needed.
if ((_rb[slot] != 0)&&
(_rb_size_x == desired_x)&&
(_rb_size_y == desired_y)) {
continue;
}
// If there's no renderbuffer for this slot, create one.
if (_rb[slot] == 0) {
glgsg->_glGenRenderbuffers(1, &(_rb[slot]));
}
// Resize the renderbuffer appropriately.
glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rb[slot]);
glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, _slot_format[slot],
desired_x, desired_y);
glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
// Bind the renderbuffer to the slot.
glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, _attach_point[slot],
GL_RENDERBUFFER_EXT, _rb[slot]);
// Toss any texture that was connected to the slot.
_tex[slot] = 0;
}
}
// These record the size of all nonzero renderbuffers.
_rb_size_x = desired_x;
_rb_size_y = desired_y;
bind_slot(rb_resize, attach, RTP_depth,
GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_COMPONENT, Texture::F_depth_component);
//bind_slot(rb_resize, attach, RTP_stencil,
// GL_STENCIL_ATTACHMENT_EXT, GL_STENCIL_INDEX, Texture::F_stencil_index);
bind_slot(rb_resize, attach, RTP_color,
GL_COLOR_ATTACHMENT0_EXT, GL_RGBA, Texture::F_rgba);
int next = GL_COLOR_ATTACHMENT1_EXT;
for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
bind_slot(rb_resize, attach, (RenderTexturePlane)(RTP_aux_rgba_0+i),
next, GL_RGBA, Texture::F_rgba);
next += 1;
}
for (int i=0; i<_fb_properties.get_aux_hrgba(); i++) {
bind_slot(rb_resize, attach, (RenderTexturePlane)(RTP_aux_hrgba_0+i),
next, GL_RGBA, Texture::F_rgba);
next += 1;
}
for (int i=0; i<_fb_properties.get_aux_float(); i++) {
bind_slot(rb_resize, attach, (RenderTexturePlane)(RTP_aux_float_0+i),
next, GL_RGBA, Texture::F_rgba);
next += 1;
}
glgsg->report_my_gl_errors();
}
////////////////////////////////////////////////////////////////////
// Function: glGraphicsBuffer::bind_slot
// Access: Private
// Description: Attaches either a texture or a renderbuffer to the
// specified bitplane.
////////////////////////////////////////////////////////////////////
void CLP(GraphicsBuffer)::
bind_slot(bool rb_resize, Texture **attach, RenderTexturePlane slot,
GLenum attachpoint, GLenum texformat, Texture::Format fmt) {
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
Texture *tex = attach[slot];
if (tex) {
// If the texture is already bound to the slot, and it's
// the right size, then no update of this slot is needed.
if ((_tex[slot] == tex)&&
(tex->get_x_size() == _rb_size_x)&&
(tex->get_y_size() == _rb_size_y)) {
return;
}
// Bind the texture to the slot.
tex->set_x_size(_rb_size_x);
tex->set_y_size(_rb_size_y);
tex->set_format(fmt);
TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg);
nassertv(tc != (TextureContext *)NULL);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
glgsg->apply_texture(tc);
if (tex->get_texture_type() == Texture::TT_2d_texture) {
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint,
GL_TEXTURE_2D, gtc->_index, 0);
} else {
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint,
GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, gtc->_index, 0);
}
_tex[slot] = tex;
// If there was a renderbuffer bound to this slot, delete it.
if (_rb[slot] != 0) {
glgsg->_glDeleteRenderbuffers(1, &(_rb[slot]));
_rb[slot] = 0;
}
} else {
// If a renderbuffer is already attached to the slot, and it's
// the right size, then no update of this slot is needed.
if ((_rb[slot] != 0)&&(!rb_resize)) {
return;
}
// If there's no renderbuffer for this slot, create one.
if (_rb[slot] == 0) {
glgsg->_glGenRenderbuffers(1, &(_rb[slot]));
}
// Resize the renderbuffer appropriately.
glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rb[slot]);
glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, texformat,
_rb_size_x, _rb_size_y);
glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
// Bind the renderbuffer to the slot.
glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, attachpoint,
GL_RENDERBUFFER_EXT, _rb[slot]);
// Toss any texture that was connected to the slot.
_tex[slot] = 0;
}
}
////////////////////////////////////////////////////////////////////
// Function: glGraphicsBuffer::generate_mipmaps
// Access: Private
@ -292,7 +337,7 @@ generate_mipmaps() {
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
for (int slot=0; slot<SLOT_COUNT; slot++) {
for (int slot=0; slot<RTP_COUNT; slot++) {
Texture *tex = _tex[slot];
if ((tex != 0) && (tex->uses_mipmaps())) {
glgsg->_state._texture = 0;
@ -395,7 +440,7 @@ close_buffer() {
DCAST_INTO_V(glgsg, _gsg);
// Delete the renderbuffers.
for (int i=0; i<SLOT_COUNT; i++) {
for (int i=0; i<RTP_COUNT; i++) {
if (_rb[i] != 0) {
glgsg->_glDeleteRenderbuffers(1, &(_rb[i]));
_rb[i] = 0;
@ -408,5 +453,9 @@ close_buffer() {
// Delete the FBO itself.
nassertv(_fbo != 0);
glgsg->_glDeleteFramebuffers(1, &_fbo);
// Release the Gsg
_gsg.clear();
_active = false;
}

View File

@ -25,21 +25,15 @@
//
// The glGraphicsBuffer is based on the OpenGL
// EXT_framebuffer_object and ARB_draw_buffers extensions.
// This design has three significant advantages over the
// wglGraphicsBuffer and glxGraphicsBuffer.
// This design has significant advantages over the
// older wglGraphicsBuffer and glxGraphicsBuffer.
//
// As you might expect, this type of buffer can export
// its color buffer as a texture. But it can also export
// its depth buffer, its stencil buffer, and any number
// of auxiliary buffers. This is the biggest advantage:
// it can render to many textures at the same time.
//
// There is also a speed advantage. When using a
// glGraphicsBuffer, it is not necessary to call the
// extremely expensive wglMakeCurrent on buffer switches.
//
// The glGraphicsBuffer can also track the size of a host
// window, and automatically resize itself to match.
// * Can export depth and stencil.
// * Supports auxiliary bitplanes.
// * Supports non-power-of-two padding.
// * Supports tracking of host window size.
// * Faster than pbuffers.
// * Can render onto a texture without clearing it first.
//
// If either of the necessary OpenGL extensions is not
// available, then the glGraphicsBuffer will not be
@ -69,24 +63,18 @@ protected:
private:
void bind_slot(bool rb_resize, Texture **attach, RenderTexturePlane plane,
GLenum attachpoint, GLenum texformat, Texture::Format fmt);
bool check_fbo();
void generate_mipmaps();
void rebuild_bitplanes();
enum {
SLOT_color,
SLOT_depth,
SLOT_stencil,
SLOT_COUNT
};
GLuint _fbo;
int _rb_size_x;
int _rb_size_y;
GLuint _rb[SLOT_COUNT];
PT(Texture) _tex[SLOT_COUNT];
GLenum _attach_point[SLOT_COUNT];
GLenum _slot_format[SLOT_COUNT];
PT(Texture) _tex[RTP_COUNT];
GLuint _rb[RTP_COUNT];
public:
static TypeHandle get_class_type() {
return _type_handle;

View File

@ -3024,24 +3024,15 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
nassertv(tc != (TextureContext *)NULL);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
apply_texture(tc);
if (z >= 0) {
// Copy to a cube map face. This doesn't seem to work too well
// with CopyTexSubImage2D, so we always use CopyTexImage2D.
GLP(BindTexture)(GL_TEXTURE_CUBE_MAP_ARB, gtc->_index);
GLP(CopyTexImage2D)(GL_TEXTURE_CUBE_MAP_POSITIVE_X + z, 0,
get_internal_image_format(tex),
xo, yo, w, h, 0);
} else {
// If the texture has never been uploaded before, create it. We
// cannot use glCopyTexImage2D to create a texture that may be
// larger than the screen, so use glTexImage2D with arbitrary
// data.
GLP(BindTexture)(GL_TEXTURE_2D, gtc->_index);
upload_blank_image(tex, gtc);
// Copy the pixel data from the frame buffer.
GLP(CopyTexSubImage2D)(GL_TEXTURE_2D, 0, 0, 0, xo, yo, w, h);
}
@ -6375,11 +6366,14 @@ bool CLP(GraphicsStateGuardian)::
upload_texture(CLP(TextureContext) *gtc) {
Texture *tex = gtc->get_texture();
CPTA_uchar image = tex->get_ram_image();
if (image.is_null()) {
return false;
}
Texture::CompressionMode image_compression = tex->get_ram_image_compression();
Texture::CompressionMode image_compression;
if (image.is_null()) {
image_compression = Texture::CM_off;
} else {
image_compression = tex->get_ram_image_compression();
}
int width = tex->get_x_size();
int height = tex->get_y_size();
int depth = tex->get_z_size();
@ -6409,71 +6403,75 @@ upload_texture(CLP(TextureContext) *gtc) {
return false;
}
int texel_size = tex->get_num_components() * tex->get_component_width();
if (!image.is_null()) {
// If it doesn't fit, we have to reduce it on-the-fly. This is kind
// of expensive and it doesn't look great; it would have been better
// if the user had specified max-texture-dimension to reduce the
// texture at load time instead. Of course, the user doesn't always
// know ahead of time what the hardware limits are.
if (max_dimension > 0 && image_compression == Texture::CM_off) {
if (width > max_dimension) {
int byte_chunk = texel_size;
int stride = 1;
int new_width = width;
while (new_width > max_dimension) {
stride <<= 1;
new_width >>= 1;
// If it doesn't fit, we have to reduce it on-the-fly. This is kind
// of expensive and it doesn't look great; it would have been better
// if the user had specified max-texture-dimension to reduce the
// texture at load time instead. Of course, the user doesn't always
// know ahead of time what the hardware limits are.
if (max_dimension > 0 && image_compression == Texture::CM_off) {
if (width > max_dimension) {
int texel_size = tex->get_num_components() * tex->get_component_width();
int byte_chunk = texel_size;
int stride = 1;
int new_width = width;
while (new_width > max_dimension) {
stride <<= 1;
new_width >>= 1;
}
GLCAT.info()
<< "Reducing width of " << tex->get_name()
<< " from " << width << " to " << new_width << "\n";
image = reduce_image(image, byte_chunk, stride);
width = new_width;
}
GLCAT.info()
<< "Reducing width of " << tex->get_name()
<< " from " << width << " to " << new_width << "\n";
image = reduce_image(image, byte_chunk, stride);
width = new_width;
}
if (height > max_dimension) {
int byte_chunk = width * texel_size;
int stride = 1;
int new_height = height;
while (new_height > max_dimension) {
stride <<= 1;
new_height >>= 1;
if (height > max_dimension) {
int texel_size = tex->get_num_components() * tex->get_component_width();
int byte_chunk = width * texel_size;
int stride = 1;
int new_height = height;
while (new_height > max_dimension) {
stride <<= 1;
new_height >>= 1;
}
GLCAT.info()
<< "Reducing height of " << tex->get_name()
<< " from " << height << " to " << new_height << "\n";
image = reduce_image(image, byte_chunk, stride);
height = new_height;
}
GLCAT.info()
<< "Reducing height of " << tex->get_name()
<< " from " << height << " to " << new_height << "\n";
image = reduce_image(image, byte_chunk, stride);
height = new_height;
}
if (depth > max_dimension) {
int byte_chunk = height * width * texel_size;
int stride = 1;
int new_depth = depth;
while (new_depth > max_dimension) {
stride <<= 1;
new_depth >>= 1;
if (depth > max_dimension) {
int texel_size = tex->get_num_components() * tex->get_component_width();
int byte_chunk = height * width * texel_size;
int stride = 1;
int new_depth = depth;
while (new_depth > max_dimension) {
stride <<= 1;
new_depth >>= 1;
}
GLCAT.info()
<< "Reducing depth of " << tex->get_name()
<< " from " << depth << " to " << new_depth << "\n";
image = reduce_image(image, byte_chunk, stride);
depth = new_depth;
}
GLCAT.info()
<< "Reducing depth of " << tex->get_name()
<< " from " << depth << " to " << new_depth << "\n";
image = reduce_image(image, byte_chunk, stride);
depth = new_depth;
}
}
if (!_supports_bgr) {
// If the GL doesn't claim to support BGR, we may have to reverse
// the component ordering of the image.
image = fix_component_ordering(image, external_format, tex);
}
if (!_supports_bgr) {
// If the GL doesn't claim to support BGR, we may have to reverse
// the component ordering of the image.
image = fix_component_ordering(image, external_format, tex);
}
#ifndef NDEBUG
if (image_compression == Texture::CM_off) {
int wanted_size =
compute_gl_image_size(width, height, depth, external_format, component_type);
nassertr(wanted_size == (int)image.size(), false);
}
if (image_compression == Texture::CM_off) {
int wanted_size =
compute_gl_image_size(width, height, depth, external_format, component_type);
nassertr(wanted_size == (int)image.size(), false);
}
#endif // NDEBUG
}
GLP(PixelStorei)(GL_UNPACK_ALIGNMENT, 1);
@ -6541,7 +6539,9 @@ upload_texture(CLP(TextureContext) *gtc) {
gtc->_depth = depth;
#ifdef DO_PSTATS
gtc->update_data_size_bytes(get_texture_memory_size(tex));
if (!image.is_null()) {
gtc->update_data_size_bytes(get_texture_memory_size(tex));
}
#endif
report_my_gl_errors();
@ -6552,59 +6552,6 @@ upload_texture(CLP(TextureContext) *gtc) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::upload_blank_image
// Access: Private
// Description: Uploads a blank, non-mipmapped image to the specified
// texture object. This is usually used to prepare the
// texture for render-to-texture operations.
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsStateGuardian)::
upload_blank_image(Texture *tex, CLP(TextureContext) *gtc)
{
GLint internal_format = get_internal_image_format(tex);
if ((gtc->_already_applied == false)||
(gtc->_internal_format != internal_format)||
(gtc->_width != tex->get_x_size())||
(gtc->_height != tex->get_y_size())||
(gtc->_depth != 1)) {
GLP(BindTexture)(GL_TEXTURE_2D, gtc->_index);
char *image = new char[tex->get_x_size() * tex->get_y_size()];
memset(image, 128, tex->get_x_size() * tex->get_y_size());
switch (tex->get_format()) {
case Texture::F_depth_component:
GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
tex->get_x_size(), tex->get_y_size(), 0,
GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, image);
break;
case Texture::F_stencil_index:
GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
tex->get_x_size(), tex->get_y_size(), 0,
GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, image);
break;
default:
GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
tex->get_x_size(), tex->get_y_size(), 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
break;
}
delete image;
gtc->_already_applied = true;
gtc->_internal_format = internal_format;
gtc->_width = tex->get_x_size();
gtc->_height = tex->get_y_size();
gtc->_depth = 1;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::upload_texture_image
@ -6622,7 +6569,7 @@ upload_texture_image(CLP(TextureContext) *gtc,
Texture::CompressionMode image_compression) {
// Make sure the error stack is cleared out before we begin.
report_my_gl_errors();
if (target == GL_NONE) {
// Unsupported target (e.g. 3-d texturing on GL 1.1).
return false;
@ -6633,6 +6580,7 @@ upload_texture_image(CLP(TextureContext) *gtc,
PStatTimer timer(_load_texture_pcollector);
Texture *tex = gtc->get_texture();
CPTA_uchar image = tex->get_ram_image();
if (GLCAT.is_debug()) {
if (image_compression != Texture::CM_off) {
@ -6644,33 +6592,11 @@ upload_texture_image(CLP(TextureContext) *gtc,
}
}
int num_ram_mipmap_levels = 1;
int num_ram_mipmap_levels = 0;
bool load_ram_mipmaps = false;
if (uses_mipmaps) {
num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
if (num_ram_mipmap_levels == 1) {
// No RAM mipmap levels available. Should we generate some?
if (!_supports_generate_mipmap ||
(!auto_generate_mipmaps && image_compression == Texture::CM_off)) {
// Yes, the GL won't generate them, so we need to.
tex->generate_ram_mipmap_images();
num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
}
}
if (num_ram_mipmap_levels != 1) {
// We will load the mipmap levels from RAM. Don't ask the GL to
// generate them.
if (_supports_generate_mipmap) {
GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, false);
}
load_ram_mipmaps = true;
} else {
// We don't have mipmap levels in RAM. Ask the GL to generate
// them if it can.
if (image.is_null()) {
if (uses_mipmaps) {
if (_supports_generate_mipmap) {
GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, true);
} else {
@ -6679,10 +6605,46 @@ upload_texture_image(CLP(TextureContext) *gtc,
uses_mipmaps = false;
}
}
} else {
num_ram_mipmap_levels = 1;
if (uses_mipmaps) {
num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
if (num_ram_mipmap_levels == 1) {
// No RAM mipmap levels available. Should we generate some?
if (!_supports_generate_mipmap ||
(!auto_generate_mipmaps && image_compression == Texture::CM_off)) {
// Yes, the GL won't generate them, so we need to.
tex->generate_ram_mipmap_images();
num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
}
}
if (num_ram_mipmap_levels != 1) {
// We will load the mipmap levels from RAM. Don't ask the GL to
// generate them.
if (_supports_generate_mipmap) {
GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, false);
}
load_ram_mipmaps = true;
} else {
// We don't have mipmap levels in RAM. Ask the GL to generate
// them if it can.
if (_supports_generate_mipmap) {
GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, true);
} else {
// If it can't, do without mipmaps.
GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
uses_mipmaps = false;
}
}
}
}
int highest_level = 0;
if (!gtc->_already_applied ||
gtc->_internal_format != internal_format ||
gtc->_width != width ||
@ -6690,6 +6652,24 @@ upload_texture_image(CLP(TextureContext) *gtc,
gtc->_depth != depth) {
// We need to reload a new image.
if (num_ram_mipmap_levels == 0) {
int *blank_image = new int[width * height];
int color = 0xFF808080;
switch (z) {
case 0: color = 0xFF0000FF; break;
case 1: color = 0xFF00FF00; break;
case 2: color = 0xFFFF0000; break;
case 3: color = 0xFF00FFFF; break;
case 4: color = 0xFFFFFF00; break;
case 5: color = 0xFFFF00FF; break;
}
for (int i=0; i<width * height; i++) blank_image[i]=color;
GLP(TexImage2D)(target, 0, internal_format,
width, height, 0,
external_format, GL_UNSIGNED_BYTE, blank_image);
delete blank_image;
}
for (int n = 0; n < num_ram_mipmap_levels; ++n) {
const unsigned char *image = tex->get_ram_mipmap_image(n);
if (image == (const unsigned char *)NULL) {

View File

@ -274,7 +274,6 @@ protected:
void specify_texture(Texture *tex);
void apply_texture(TextureContext *tc);
bool upload_texture(CLP(TextureContext) *gtc);
bool upload_blank_image(Texture *tex, CLP(TextureContext) *gtc);
bool upload_texture_image(CLP(TextureContext) *gtc, bool uses_mipmaps,
GLenum target, GLint internal_format,
int width, int height, int depth,
@ -372,8 +371,6 @@ public:
bool _supports_draw_range_elements;
PFNGLDRAWRANGEELEMENTSPROC _glDrawRangeElements;
bool _supports_depth_texture;
PFNGLTEXIMAGE3DPROC _glTexImage3D;
PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D;

View File

@ -97,6 +97,8 @@ begin_frame(FrameMode mode) {
// begin_render_texture();
clear_cube_map_selection();
}
_gsg()->set_current_properties(&get_fb_properties());
return _gsg->begin_frame();
}
@ -128,21 +130,6 @@ end_frame(FrameMode mode) {
}
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsBuffer::release_gsg
// Access: Public
// Description: Releases the current GSG pointer, if it is currently
// held, and resets the GSG to NULL. The window will be
// permanently unable to render; this is normally called
// only just before destroying the window. This should
// only be called from within the draw thread.
////////////////////////////////////////////////////////////////////
void glxGraphicsBuffer::
release_gsg() {
glXMakeCurrent(_display, None, NULL);
GraphicsBuffer::release_gsg();
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsBuffer::close_buffer
// Access: Protected, Virtual
@ -151,6 +138,12 @@ release_gsg() {
////////////////////////////////////////////////////////////////////
void glxGraphicsBuffer::
close_buffer() {
if (_gsg != (GraphicsStateGuardian *)NULL) {
glXMakeCurrent(_display, None, NULL);
_gsg.clear();
_active = false;
}
if (_pbuffer != None) {
glXDestroyPbuffer(_display, _pbuffer);
_pbuffer = None;

View File

@ -45,7 +45,6 @@ public:
virtual bool begin_frame(FrameMode mode);
virtual void end_frame(FrameMode mode);
virtual void release_gsg();
protected:
virtual void close_buffer();

View File

@ -105,20 +105,6 @@ move_pointer(int device, int x, int y) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsWindow::release_gsg
// Access: Public
// Description: Releases the current GSG pointer, if it is currently
// held, and resets the GSG to NULL. The window will be
// permanently unable to render; this is normally called
// only just before destroying the window. This should
// only be called from within the draw thread.
////////////////////////////////////////////////////////////////////
void glxGraphicsWindow::
release_gsg() {
glXMakeCurrent(_display, None, NULL);
GraphicsWindow::release_gsg();
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsWindow::begin_frame
@ -157,6 +143,8 @@ begin_frame(FrameMode mode) {
// begin_render_texture();
clear_cube_map_selection();
}
_gsg()->set_current_properties(&get_fb_properties());
return _gsg->begin_frame();
}
@ -375,8 +363,7 @@ process_events() {
// In this case, the default case, the app does not intend
// to service the request, so we do by closing the window.
// TODO: don't call release_gsg() in the window thread.
release_gsg();
// TODO: don't release the gsg in the window thread.
close_window();
properties.set_open(false);
system_changed_properties(properties);
@ -493,6 +480,12 @@ set_properties_now(WindowProperties &properties) {
////////////////////////////////////////////////////////////////////
void glxGraphicsWindow::
close_window() {
if (_gsg != (GraphicsStateGuardian *)NULL) {
glXMakeCurrent(_display, None, NULL);
_gsg.clear();
_active = false;
}
if (_ic != (XIC)NULL) {
XDestroyIC(_ic);
_ic = (XIC)NULL;

View File

@ -41,8 +41,6 @@ public:
virtual ~glxGraphicsWindow();
virtual bool move_pointer(int device, int x, int y);
virtual void release_gsg();
virtual bool begin_frame(FrameMode mode);
virtual void end_frame(FrameMode mode);
virtual void begin_flip();

View File

@ -931,6 +931,7 @@ set_ram_image(PTA_uchar image, Texture::CompressionMode compression,
////////////////////////////////////////////////////////////////////
void Texture::
clear_ram_image() {
++_modified;
_ram_image_compression = CM_off;
_ram_images.clear();
}

View File

@ -60,103 +60,6 @@ set_has_3d_uvs(bool flag) {
_has_3d_uvs = flag;
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::set_uv_range
// Access: Public
// Description: Sets the range of UV's that will be applied to the
// vertices. If set_has_uvs() is true (as it is by
// default), the vertices will be generated with the
// indicated range of UV's, which will be useful if a
// texture is applied.
////////////////////////////////////////////////////////////////////
INLINE void CardMaker::
set_uv_range(const TexCoord3f &ll, const TexCoord3f &lr, const TexCoord3f &ur, const TexCoord3f &ul) {
_ll_tex = ll;
_lr_tex = lr;
_ur_tex = ur;
_ul_tex = ul;
_has_uvs = true;
_has_3d_uvs = true;
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::set_uv_range
// Access: Public
// Description: Sets the range of UV's that will be applied to the
// vertices. If set_has_uvs() is true (as it is by
// default), the vertices will be generated with the
// indicated range of UV's, which will be useful if a
// texture is applied.
////////////////////////////////////////////////////////////////////
INLINE void CardMaker::
set_uv_range(const TexCoordf &ll, const TexCoordf &lr, const TexCoordf &ur, const TexCoordf &ul) {
_ll_tex.set(ll[0], ll[1], 0.0f);
_lr_tex.set(lr[0], lr[1], 0.0f);
_ur_tex.set(ur[0], ur[1], 0.0f);
_ul_tex.set(ul[0], ul[1], 0.0f);
_has_uvs = true;
_has_3d_uvs = false;
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::set_uv_range
// Access: Public
// Description: Sets the range of UV's that will be applied to the
// vertices. If set_has_uvs() is true (as it is by
// default), the vertices will be generated with the
// indicated range of UV's, which will be useful if a
// texture is applied.
////////////////////////////////////////////////////////////////////
INLINE void CardMaker::
set_uv_range(const TexCoordf &ll, const TexCoordf &ur) {
_ll_tex.set(ll[0], ll[1], 0.0f);
_lr_tex.set(ur[0], ll[1], 0.0f);
_ur_tex.set(ur[0], ur[1], 0.0f);
_ul_tex.set(ll[0], ur[1], 0.0f);
_has_uvs = true;
_has_3d_uvs = false;
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::set_uv_range
// Access: Public
// Description: Sets the range of UV's that will be applied to the
// vertices. If set_has_uvs() is true (as it is by
// default), the vertices will be generated with the
// indicated range of UV's, which will be useful if a
// texture is applied.
////////////////////////////////////////////////////////////////////
INLINE void CardMaker::
set_uv_range(const LVector4f &x, const LVector4f &y, const LVector4f &z) {
_ll_tex.set(x[0], y[0], z[0]);
_lr_tex.set(x[1], y[1], z[1]);
_ur_tex.set(x[2], y[2], z[2]);
_ul_tex.set(x[3], y[3], z[3]);
_has_uvs = true;
_has_3d_uvs = true;
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::set_uv_range_cube
// Access: Public
// Description: Sets the range of UV's that will be applied to the
// vertices appropriately for a cube-map face.
////////////////////////////////////////////////////////////////////
INLINE void CardMaker::
set_uv_range_cube(int face) {
LVector4f varya(-1, 1, 1, -1);
LVector4f varyb(-1, -1, 1, 1);
LVector4f fixed( 1, 1, 1, 1);
switch(face) {
case 0: set_uv_range( fixed, -varyb, varya); break; // positive_x
case 1: set_uv_range(-fixed, -varyb, -varya); break; // negative_x
case 2: set_uv_range(-varya, fixed, varyb); break; // positive_y
case 3: set_uv_range(-varya, -fixed, -varyb); break; // negative_y
case 4: set_uv_range(-varya, -varyb, fixed); break; // positive_z
case 5: set_uv_range( varya, -varyb, -fixed); break; // negative_z
}
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::set_frame
// Access: Public

View File

@ -159,6 +159,103 @@ generate() {
return gnode.p();
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::set_uv_range
// Access: Public
// Description: Sets the range of UV's that will be applied to the
// vertices. If set_has_uvs() is true (as it is by
// default), the vertices will be generated with the
// indicated range of UV's, which will be useful if a
// texture is applied.
////////////////////////////////////////////////////////////////////
INLINE void CardMaker::
set_uv_range(const TexCoord3f &ll, const TexCoord3f &lr, const TexCoord3f &ur, const TexCoord3f &ul) {
_ll_tex = ll;
_lr_tex = lr;
_ur_tex = ur;
_ul_tex = ul;
_has_uvs = true;
_has_3d_uvs = true;
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::set_uv_range
// Access: Public
// Description: Sets the range of UV's that will be applied to the
// vertices. If set_has_uvs() is true (as it is by
// default), the vertices will be generated with the
// indicated range of UV's, which will be useful if a
// texture is applied.
////////////////////////////////////////////////////////////////////
INLINE void CardMaker::
set_uv_range(const TexCoordf &ll, const TexCoordf &lr, const TexCoordf &ur, const TexCoordf &ul) {
_ll_tex.set(ll[0], ll[1], 0.0f);
_lr_tex.set(lr[0], lr[1], 0.0f);
_ur_tex.set(ur[0], ur[1], 0.0f);
_ul_tex.set(ul[0], ul[1], 0.0f);
_has_uvs = true;
_has_3d_uvs = false;
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::set_uv_range
// Access: Public
// Description: Sets the range of UV's that will be applied to the
// vertices. If set_has_uvs() is true (as it is by
// default), the vertices will be generated with the
// indicated range of UV's, which will be useful if a
// texture is applied.
////////////////////////////////////////////////////////////////////
INLINE void CardMaker::
set_uv_range(const TexCoordf &ll, const TexCoordf &ur) {
_ll_tex.set(ll[0], ll[1], 0.0f);
_lr_tex.set(ur[0], ll[1], 0.0f);
_ur_tex.set(ur[0], ur[1], 0.0f);
_ul_tex.set(ll[0], ur[1], 0.0f);
_has_uvs = true;
_has_3d_uvs = false;
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::set_uv_range
// Access: Public
// Description: Sets the range of UV's that will be applied to the
// vertices. If set_has_uvs() is true (as it is by
// default), the vertices will be generated with the
// indicated range of UV's, which will be useful if a
// texture is applied.
////////////////////////////////////////////////////////////////////
INLINE void CardMaker::
set_uv_range(const LVector4f &x, const LVector4f &y, const LVector4f &z) {
_ll_tex.set(x[0], y[0], z[0]);
_lr_tex.set(x[1], y[1], z[1]);
_ur_tex.set(x[2], y[2], z[2]);
_ul_tex.set(x[3], y[3], z[3]);
_has_uvs = true;
_has_3d_uvs = true;
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::set_uv_range_cube
// Access: Public
// Description: Sets the range of UV's that will be applied to the
// vertices appropriately for a cube-map face.
////////////////////////////////////////////////////////////////////
INLINE void CardMaker::
set_uv_range_cube(int face) {
LVector4f varya(-1, 1, 1, -1);
LVector4f varyb(-1, -1, 1, 1);
LVector4f fixed( 1, 1, 1, 1);
switch(face) {
case 0: set_uv_range( fixed, -varyb, -varya); break; // positive_x
case 1: set_uv_range(-fixed, -varyb, varya); break; // negative_x
case 2: set_uv_range( varya, fixed, varyb); break; // positive_y
case 3: set_uv_range( varya, -fixed, -varyb); break; // negative_y
case 4: set_uv_range( varya, -varyb, fixed); break; // positive_z
case 5: set_uv_range(-varya, -varyb, -fixed); break; // negative_z
}
}
////////////////////////////////////////////////////////////////////
// Function: CardMaker::rescale_source_geometry
// Access: Private

View File

@ -38,13 +38,14 @@ PUBLISHED:
INLINE ~CardMaker();
void reset();
INLINE void set_uv_range(const TexCoordf &ll, const TexCoordf &ur);
INLINE void set_uv_range(const TexCoordf &ll, const TexCoordf &lr, const TexCoordf &ur, const TexCoordf &ul);
INLINE void set_uv_range(const TexCoord3f &ll, const TexCoord3f &lr, const TexCoord3f &ur, const TexCoord3f &ul);
INLINE void set_uv_range(const LVector4f &x, const LVector4f &y, const LVector4f &z);
void set_uv_range(const TexCoordf &ll, const TexCoordf &ur);
void set_uv_range(const TexCoordf &ll, const TexCoordf &lr, const TexCoordf &ur, const TexCoordf &ul);
void set_uv_range(const TexCoord3f &ll, const TexCoord3f &lr, const TexCoord3f &ur, const TexCoord3f &ul);
void set_uv_range(const LVector4f &x, const LVector4f &y, const LVector4f &z);
void set_uv_range_cube(int face);
INLINE void set_has_uvs(bool flag);
INLINE void set_has_3d_uvs(bool flag);
INLINE void set_uv_range_cube(int face);
INLINE void set_frame(float left, float right, float bottom, float top);
INLINE void set_frame(const LVecBase4f &frame);

View File

@ -76,6 +76,7 @@ begin_frame(FrameMode mode) {
// begin_render_texture();
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
return _gsg->begin_frame();
}

View File

@ -82,6 +82,7 @@ begin_frame(FrameMode mode) {
// begin_render_texture();
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
return _gsg->begin_frame();
}
@ -113,20 +114,6 @@ end_frame(FrameMode mode) {
clear_cube_map_selection();
}
}
////////////////////////////////////////////////////////////////////
// Function: osxGraphicsBuffer::release_gsg
// Access: Public
// Description: Releases the current GSG pointer, if it is currently
// held, and resets the GSG to NULL. The window will be
// permanently unable to render; this is normally called
// only just before destroying the window. This should
// only be called from within the draw thread.
////////////////////////////////////////////////////////////////////
void osxGraphicsBuffer::
release_gsg() {
//osxMakeCurrent(_display, None, NULL);
GraphicsBuffer::release_gsg();
}
////////////////////////////////////////////////////////////////////
// Function: osxGraphicsBuffer::close_buffer
@ -136,7 +123,11 @@ release_gsg() {
////////////////////////////////////////////////////////////////////
void osxGraphicsBuffer::
close_buffer() {
if (_gsg != (GraphicsStateGuardian *)NULL) {
//osxMakeCurrent(_display, None, NULL);
_gsg.clear();
_active = false;
}
_is_valid = false;
}

View File

@ -45,8 +45,6 @@ public:
virtual bool begin_frame(FrameMode mode);
virtual void end_frame(FrameMode mode);
virtual void release_gsg();
protected:
virtual void close_buffer();

View File

@ -568,8 +568,8 @@ bool osxGraphicsWindow::begin_frame(FrameMode mode)
_gsg->reset_if_new();
_gsg->reset_if_new();
_gsg->set_current_properties(&get_fb_properties());
return _gsg->begin_frame();
}
@ -590,22 +590,6 @@ void osxGraphicsWindow::end_frame(FrameMode mode)
trigger_flip();
}
////////////////////////////////////////////////////////////////////
// Function: osxGraphicsWindow::release_gsg
// Access: Public, Virtual
// Description: Releases the current GSG pointer, if it is currently
// held, and resets the GSG to NULL. The window will be
// permanently unable to render; this is normally called
// only just before destroying the window. This should
// only be called from within the draw thread.
////////////////////////////////////////////////////////////////////
void osxGraphicsWindow::release_gsg()
{
ReleaseSystemResources();
GraphicsWindow::release_gsg();
}
////////////////////////////////////////////////////////////////////
// Function: osxGraphicsWindow::begin_flip
// Access: Public, Virtual
@ -632,11 +616,12 @@ void osxGraphicsWindow::begin_flip()
// Description: Closes the window right now. Called from the window
// thread.
////////////////////////////////////////////////////////////////////
void osxGraphicsWindow::close_window() {
ReleaseSystemResources();
GraphicsWindow::close_window();
void osxGraphicsWindow::close_window()
{
ReleaseSystemResources();
_gsg.clear();
_active = false;
GraphicsWindow::close_window();
}
//////////////////////////////////////////////////////////

View File

@ -50,7 +50,6 @@ public:
virtual bool move_pointer(int device, int x, int y);
// virtual void make_current();
virtual void release_gsg();
virtual bool begin_frame(FrameMode mode);
virtual void end_frame(FrameMode mode);
virtual void begin_flip();

View File

@ -91,13 +91,15 @@ begin_frame(FrameMode mode) {
}
}
}
wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc));
if (mode == FM_render) {
begin_render_texture();
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
return _gsg->begin_frame();
}
@ -228,20 +230,6 @@ select_cube_map(int cube_map_index) {
wglgsg->_wglSetPbufferAttribARB(_pbuffer, iattrib_list);
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsBuffer::release_gsg
// Access: Public, Virtual
// Description: Releases the current GSG pointer, if it is currently
// held, and resets the GSG to NULL. The window will be
// permanently unable to render; this is normally called
// only just before destroying the window. This should
// only be called from within the draw thread.
////////////////////////////////////////////////////////////////////
void wglGraphicsBuffer::
release_gsg() {
GraphicsBuffer::release_gsg();
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsBuffer::process_events
// Access: Public, Virtual
@ -284,7 +272,11 @@ close_buffer() {
if (_pbuffer) {
wglgsg->_wglDestroyPbufferARB(_pbuffer);
}
_gsg.clear();
_active = false;
}
_pbuffer_dc = 0;
_pbuffer = 0;

View File

@ -53,7 +53,6 @@ public:
virtual void end_frame(FrameMode mode);
virtual void select_cube_map(int cube_map_index);
virtual void release_gsg();
virtual void process_events();

View File

@ -168,7 +168,7 @@ begin_frame(FrameMode mode) {
if (_gsg == (GraphicsStateGuardian *)NULL) {
return false;
}
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_R(wglgsg, _gsg, false);
@ -181,6 +181,7 @@ begin_frame(FrameMode mode) {
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
return _gsg->begin_frame();
}
@ -213,21 +214,6 @@ end_frame(FrameMode mode) {
}
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsWindow::release_gsg
// Access: Public, Virtual
// Description: Releases the current GSG pointer, if it is currently
// held, and resets the GSG to NULL. The window will be
// permanently unable to render; this is normally called
// only just before destroying the window. This should
// only be called from within the draw thread.
////////////////////////////////////////////////////////////////////
void wglGraphicsWindow::
release_gsg() {
wglMakeCurrent(_hdc, NULL);
GraphicsWindow::release_gsg();
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsWindow::begin_flip
// Access: Public, Virtual
@ -268,6 +254,11 @@ begin_flip() {
////////////////////////////////////////////////////////////////////
void wglGraphicsWindow::
close_window() {
if (_gsg != (GraphicsStateGuardian *)NULL) {
wglMakeCurrent(_hdc, NULL);
_gsg.clear();
_active = false;
}
ReleaseDC(_hWnd, _hdc);
_hdc = (HDC)0;
WinGraphicsWindow::close_window();

View File

@ -40,7 +40,6 @@ public:
virtual bool begin_frame(FrameMode mode);
virtual void end_frame(FrameMode mode);
virtual void release_gsg();
virtual void begin_flip();
protected: