571 lines
18 KiB
C++
571 lines
18 KiB
C++
// Filename: wglGraphicsBuffer.cxx
|
|
// Created by: drose (08Feb04)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
|
//
|
|
// All use of this software is subject to the terms of the Panda 3d
|
|
// Software license. You should have received a copy of this license
|
|
// along with this source code; you will also find a current copy of
|
|
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d-general@lists.sourceforge.net .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "wglGraphicsBuffer.h"
|
|
#include "wglGraphicsPipe.h"
|
|
#include "config_wgldisplay.h"
|
|
#include "glgsg.h"
|
|
#include "pStatTimer.h"
|
|
|
|
#include <wingdi.h>
|
|
|
|
TypeHandle wglGraphicsBuffer::_type_handle;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: wglGraphicsBuffer::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
wglGraphicsBuffer::
|
|
wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
|
|
const string &name,
|
|
int x_size, int y_size) :
|
|
GraphicsBuffer(pipe, gsg, name, x_size, y_size)
|
|
{
|
|
_pbuffer = (HPBUFFERARB)0;
|
|
_pbuffer_dc = (HDC)0;
|
|
|
|
// Since the pbuffer never gets flipped, we get screenshots from the
|
|
// same buffer we draw into.
|
|
_screenshot_buffer_type = _draw_buffer_type;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: wglGraphicsBuffer::Destructor
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
wglGraphicsBuffer::
|
|
~wglGraphicsBuffer() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: wglGraphicsBuffer::begin_frame
|
|
// Access: Public, Virtual
|
|
// Description: This function will be called within the draw thread
|
|
// before beginning rendering for a given frame. It
|
|
// should do whatever setup is required, and return true
|
|
// if the frame should be rendered, or false if it
|
|
// should be skipped.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool wglGraphicsBuffer::
|
|
begin_frame() {
|
|
if (_gsg == (GraphicsStateGuardian *)NULL) {
|
|
return false;
|
|
}
|
|
|
|
wglGraphicsStateGuardian *wglgsg;
|
|
DCAST_INTO_R(wglgsg, _gsg, false);
|
|
|
|
if (_pbuffer_dc) {
|
|
int flag = 0;
|
|
wglgsg->_wglQueryPbufferARB(_pbuffer, WGL_PBUFFER_LOST_ARB, &flag);
|
|
if (flag != 0) {
|
|
// The pbuffer was lost, due to a mode change or something
|
|
// silly like that. We must therefore recreate the pbuffer.
|
|
close_buffer();
|
|
if (!open_buffer()) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return GraphicsBuffer::begin_frame();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: wglGraphicsBuffer::select_cube_map
|
|
// Access: Public, Virtual
|
|
// Description: Called internally when the window is in
|
|
// render-to-a-texture mode and we are in the process of
|
|
// rendering the six faces of a cube map. This should
|
|
// do whatever needs to be done to switch the buffer to
|
|
// the indicated face.
|
|
////////////////////////////////////////////////////////////////////
|
|
void wglGraphicsBuffer::
|
|
select_cube_map(int cube_map_index) {
|
|
wglGraphicsStateGuardian *wglgsg;
|
|
DCAST_INTO_V(wglgsg, _gsg);
|
|
|
|
nassertv(wglgsg->_wglSetPbufferAttribARB != NULL);
|
|
|
|
static const int max_attrib_list = 64;
|
|
int iattrib_list[max_attrib_list];
|
|
int ni = 0;
|
|
|
|
iattrib_list[ni++] = WGL_CUBE_MAP_FACE_ARB;
|
|
iattrib_list[ni++] = WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + cube_map_index;
|
|
|
|
// Terminate the list.
|
|
nassertv(ni <= max_attrib_list);
|
|
iattrib_list[ni] = 0;
|
|
|
|
wglgsg->_wglSetPbufferAttribARB(_pbuffer, iattrib_list);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: wglGraphicsBuffer::make_current
|
|
// Access: Public, Virtual
|
|
// Description: This function will be called within the draw thread
|
|
// during begin_frame() to ensure the graphics context
|
|
// is ready for drawing.
|
|
////////////////////////////////////////////////////////////////////
|
|
void wglGraphicsBuffer::
|
|
make_current() {
|
|
PStatTimer timer(_make_current_pcollector);
|
|
|
|
wglGraphicsStateGuardian *wglgsg;
|
|
DCAST_INTO_V(wglgsg, _gsg);
|
|
|
|
wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// 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
|
|
// Description: Do whatever processing is necessary to ensure that
|
|
// the window responds to user events. Also, honor any
|
|
// requests recently made via request_properties()
|
|
//
|
|
// This function is called only within the window
|
|
// thread.
|
|
////////////////////////////////////////////////////////////////////
|
|
void wglGraphicsBuffer::
|
|
process_events() {
|
|
GraphicsBuffer::process_events();
|
|
|
|
MSG msg;
|
|
|
|
// Handle all the messages on the queue in a row. Some of these
|
|
// might be for another window, but they will get dispatched
|
|
// appropriately.
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
|
process_1_event();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: wglGraphicsBuffer::close_buffer
|
|
// Access: Protected, Virtual
|
|
// Description: Closes the buffer right now. Called from the window
|
|
// thread.
|
|
////////////////////////////////////////////////////////////////////
|
|
void wglGraphicsBuffer::
|
|
close_buffer() {
|
|
if (_gsg != (GraphicsStateGuardian *)NULL) {
|
|
wglGraphicsStateGuardian *wglgsg;
|
|
DCAST_INTO_V(wglgsg, _gsg);
|
|
|
|
if (_pbuffer_dc) {
|
|
wglgsg->_wglReleasePbufferDCARB(_pbuffer, _pbuffer_dc);
|
|
}
|
|
if (_pbuffer) {
|
|
wglgsg->_wglDestroyPbufferARB(_pbuffer);
|
|
}
|
|
}
|
|
_pbuffer_dc = 0;
|
|
_pbuffer = 0;
|
|
|
|
_is_valid = false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: wglGraphicsBuffer::open_buffer
|
|
// Access: Protected, Virtual
|
|
// Description: Opens the window right now. Called from the window
|
|
// thread. Returns true if the window is successfully
|
|
// opened, or false if there was a problem.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool wglGraphicsBuffer::
|
|
open_buffer() {
|
|
wglGraphicsStateGuardian *wglgsg;
|
|
DCAST_INTO_R(wglgsg, _gsg, false);
|
|
|
|
HDC twindow_dc = wglgsg->get_twindow_dc();
|
|
if (twindow_dc == 0) {
|
|
// If we couldn't make a window, we can't get a GL context.
|
|
return false;
|
|
}
|
|
|
|
wglMakeCurrent(twindow_dc, wglgsg->get_context(twindow_dc));
|
|
wglgsg->reset_if_new();
|
|
_needs_context = false;
|
|
|
|
// Now that we have fully made a window and used that window to
|
|
// create a rendering context, we can attempt to create a pbuffer.
|
|
// This might fail if the pbuffer extensions are not supported.
|
|
|
|
if (!make_pbuffer(twindow_dc)) {
|
|
wglMakeCurrent(0, 0);
|
|
return false;
|
|
}
|
|
|
|
_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_texture:
|
|
wgldisplay_cat.debug()
|
|
<< "pbuffer renders directly to texture.\n";
|
|
break;
|
|
|
|
case RTM_copy_texture:
|
|
case RTM_bind_if_possible:
|
|
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();
|
|
|
|
_is_valid = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: wglGraphicsBuffer::make_pbuffer
|
|
// Access: Private
|
|
// Description: Once the GL context has been fully realized, attempts
|
|
// to create an offscreen pbuffer if the graphics API
|
|
// supports it. Returns true if successful, false on
|
|
// failure.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool wglGraphicsBuffer::
|
|
make_pbuffer(HDC twindow_dc) {
|
|
wglGraphicsStateGuardian *wglgsg;
|
|
DCAST_INTO_R(wglgsg, _gsg, false);
|
|
|
|
if (!wglgsg->_supports_pbuffer) {
|
|
wgldisplay_cat.info()
|
|
<< "PBuffers not supported by GL implementation.\n";
|
|
return false;
|
|
}
|
|
|
|
int pbformat = wglgsg->get_pfnum();
|
|
|
|
if (wglgsg->_supports_pixel_format) {
|
|
bool got_pbuffer_format = false;
|
|
|
|
if (_rtm_mode == RTM_bind_if_possible &&
|
|
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);
|
|
if (new_pbformat != 0) {
|
|
pbformat = new_pbformat;
|
|
got_pbuffer_format = true;
|
|
_rtm_mode = RTM_bind_texture;
|
|
}
|
|
}
|
|
|
|
if (!got_pbuffer_format) {
|
|
// Failing that, just get a matching pbuffer format.
|
|
int new_pbformat = choose_pbuffer_format(twindow_dc, false);
|
|
if (new_pbformat != 0) {
|
|
pbformat = new_pbformat;
|
|
got_pbuffer_format = true;
|
|
}
|
|
}
|
|
|
|
if (wgldisplay_cat.is_debug()) {
|
|
FrameBufferProperties properties;
|
|
wglGraphicsPipe::get_properties_advanced(properties, wglgsg,
|
|
twindow_dc, pbformat);
|
|
wgldisplay_cat.debug()
|
|
<< "Chose pixfmt #" << pbformat << " for pbuffer = "
|
|
<< properties << "\n";
|
|
}
|
|
}
|
|
|
|
static const int max_attrib_list = 64;
|
|
int iattrib_list[max_attrib_list];
|
|
int ni = 0;
|
|
|
|
if (_rtm_mode == RTM_bind_texture) {
|
|
nassertr(_texture != (Texture *)NULL, false);
|
|
|
|
if (_gsg->get_properties().get_frame_buffer_mode() & FrameBufferProperties::FM_alpha) {
|
|
iattrib_list[ni++] = WGL_TEXTURE_FORMAT_ARB;
|
|
iattrib_list[ni++] = WGL_TEXTURE_RGBA_ARB;
|
|
} else {
|
|
iattrib_list[ni++] = WGL_TEXTURE_FORMAT_ARB;
|
|
iattrib_list[ni++] = WGL_TEXTURE_RGB_ARB;
|
|
}
|
|
|
|
if (_texture->uses_mipmaps()) {
|
|
iattrib_list[ni++] = WGL_MIPMAP_TEXTURE_ARB;
|
|
iattrib_list[ni++] = 1;
|
|
}
|
|
|
|
switch (_texture->get_texture_type()) {
|
|
case Texture::TT_cube_map:
|
|
iattrib_list[ni++] = WGL_TEXTURE_TARGET_ARB;
|
|
iattrib_list[ni++] = WGL_TEXTURE_CUBE_MAP_ARB;
|
|
break;
|
|
|
|
case Texture::TT_1d_texture:
|
|
iattrib_list[ni++] = WGL_TEXTURE_TARGET_ARB;
|
|
iattrib_list[ni++] = WGL_TEXTURE_1D_ARB;
|
|
break;
|
|
|
|
default:
|
|
iattrib_list[ni++] = WGL_TEXTURE_TARGET_ARB;
|
|
iattrib_list[ni++] = WGL_TEXTURE_2D_ARB;
|
|
}
|
|
}
|
|
|
|
// Terminate the list.
|
|
nassertr(ni <= max_attrib_list, false);
|
|
iattrib_list[ni] = 0;
|
|
|
|
_pbuffer = wglgsg->_wglCreatePbufferARB(twindow_dc, pbformat,
|
|
_x_size, _y_size, iattrib_list);
|
|
|
|
if (_pbuffer == 0) {
|
|
wgldisplay_cat.info()
|
|
<< "Attempt to create pbuffer failed.\n";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: wglGraphicsBuffer::choose_pbuffer_format
|
|
// Access: Private
|
|
// Description: Select a suitable pixel format that matches the GSG's
|
|
// existing format, and also is appropriate for a pixel
|
|
// buffer. Returns the selected pfnum if successful, or
|
|
// 0 on failure.
|
|
////////////////////////////////////////////////////////////////////
|
|
int wglGraphicsBuffer::
|
|
choose_pbuffer_format(HDC twindow_dc, bool draw_to_texture) {
|
|
if (wgldisplay_cat.is_debug()) {
|
|
wgldisplay_cat.debug()
|
|
<< "choose_pbuffer_format(twindow_dc, draw_to_texture = "
|
|
<< draw_to_texture << ")\n";
|
|
}
|
|
|
|
wglGraphicsStateGuardian *wglgsg;
|
|
DCAST_INTO_R(wglgsg, _gsg, false);
|
|
|
|
int pbformat = wglgsg->get_pfnum();
|
|
|
|
static const int max_attrib_list = 64;
|
|
int iattrib_list[max_attrib_list];
|
|
int ivalue_list[max_attrib_list];
|
|
int ni = 0;
|
|
|
|
int acceleration_i, pixel_type_i, double_buffer_i, stereo_i,
|
|
red_bits_i, green_bits_i, blue_bits_i, alpha_bits_i,
|
|
accum_red_bits_i, accum_green_bits_i, accum_blue_bits_i,
|
|
accum_alpha_bits_i, depth_bits_i,
|
|
stencil_bits_i, sample_buffers_i, multisamples_i;
|
|
|
|
iattrib_list[acceleration_i = ni++] = WGL_ACCELERATION_ARB;
|
|
iattrib_list[pixel_type_i = ni++] = WGL_PIXEL_TYPE_ARB;
|
|
iattrib_list[double_buffer_i = ni++] = WGL_DOUBLE_BUFFER_ARB;
|
|
iattrib_list[stereo_i = ni++] = WGL_STEREO_ARB;
|
|
iattrib_list[red_bits_i = ni++] = WGL_RED_BITS_ARB;
|
|
iattrib_list[green_bits_i = ni++] = WGL_GREEN_BITS_ARB;
|
|
iattrib_list[blue_bits_i = ni++] = WGL_BLUE_BITS_ARB;
|
|
iattrib_list[alpha_bits_i = ni++] = WGL_ALPHA_BITS_ARB;
|
|
iattrib_list[accum_red_bits_i = ni++] = WGL_ACCUM_RED_BITS_ARB;
|
|
iattrib_list[accum_green_bits_i = ni++] = WGL_ACCUM_GREEN_BITS_ARB;
|
|
iattrib_list[accum_blue_bits_i = ni++] = WGL_ACCUM_BLUE_BITS_ARB;
|
|
iattrib_list[accum_alpha_bits_i = ni++] = WGL_ACCUM_ALPHA_BITS_ARB;
|
|
iattrib_list[depth_bits_i = ni++] = WGL_DEPTH_BITS_ARB;
|
|
iattrib_list[stencil_bits_i = ni++] = WGL_STENCIL_BITS_ARB;
|
|
|
|
if (wglgsg->_supports_wgl_multisample) {
|
|
iattrib_list[sample_buffers_i = ni++] = WGL_SAMPLE_BUFFERS_ARB;
|
|
iattrib_list[multisamples_i = ni++] = WGL_SAMPLES_ARB;
|
|
}
|
|
|
|
// Terminate the list.
|
|
nassertr(ni <= max_attrib_list, false);
|
|
|
|
if (!wglgsg->_wglGetPixelFormatAttribivARB(twindow_dc, pbformat, 0,
|
|
ni, iattrib_list, ivalue_list)) {
|
|
if (wgldisplay_cat.is_debug()) {
|
|
wgldisplay_cat.debug()
|
|
<< "Could not query old format " << pbformat << ".\n";
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ni = 0;
|
|
float fattrib_list[max_attrib_list];
|
|
int nf = 0;
|
|
|
|
// Since we are trying to create a pbuffer, the pixel format we
|
|
// request (and subsequently use) must be "pbuffer capable".
|
|
iattrib_list[ni++] = WGL_DRAW_TO_PBUFFER_ARB;
|
|
iattrib_list[ni++] = true;
|
|
iattrib_list[ni++] = WGL_SUPPORT_OPENGL_ARB;
|
|
iattrib_list[ni++] = true;
|
|
|
|
if (draw_to_texture) {
|
|
// If we want to be able to render-to-texture, request that.
|
|
if (_gsg->get_properties().get_frame_buffer_mode() & FrameBufferProperties::FM_alpha) {
|
|
iattrib_list[ni++] = WGL_BIND_TO_TEXTURE_RGBA_ARB;
|
|
iattrib_list[ni++] = true;
|
|
} else {
|
|
iattrib_list[ni++] = WGL_BIND_TO_TEXTURE_RGB_ARB;
|
|
iattrib_list[ni++] = true;
|
|
}
|
|
}
|
|
|
|
// Match up the framebuffer bits.
|
|
iattrib_list[ni++] = WGL_RED_BITS_ARB;
|
|
iattrib_list[ni++] = ivalue_list[red_bits_i];
|
|
iattrib_list[ni++] = WGL_GREEN_BITS_ARB;
|
|
iattrib_list[ni++] = ivalue_list[green_bits_i];
|
|
iattrib_list[ni++] = WGL_BLUE_BITS_ARB;
|
|
iattrib_list[ni++] = ivalue_list[blue_bits_i];
|
|
iattrib_list[ni++] = WGL_ALPHA_BITS_ARB;
|
|
iattrib_list[ni++] = ivalue_list[alpha_bits_i];
|
|
|
|
iattrib_list[ni++] = WGL_ACCUM_RED_BITS_ARB;
|
|
iattrib_list[ni++] = ivalue_list[accum_red_bits_i];
|
|
iattrib_list[ni++] = WGL_ACCUM_GREEN_BITS_ARB;
|
|
iattrib_list[ni++] = ivalue_list[accum_green_bits_i];
|
|
iattrib_list[ni++] = WGL_ACCUM_BLUE_BITS_ARB;
|
|
iattrib_list[ni++] = ivalue_list[accum_blue_bits_i];
|
|
iattrib_list[ni++] = WGL_ACCUM_ALPHA_BITS_ARB;
|
|
iattrib_list[ni++] = ivalue_list[accum_alpha_bits_i];
|
|
|
|
iattrib_list[ni++] = WGL_DEPTH_BITS_ARB;
|
|
iattrib_list[ni++] = ivalue_list[depth_bits_i];
|
|
|
|
iattrib_list[ni++] = WGL_STENCIL_BITS_ARB;
|
|
iattrib_list[ni++] = ivalue_list[stencil_bits_i];
|
|
|
|
if (wglgsg->_supports_wgl_multisample) {
|
|
iattrib_list[ni++] = WGL_SAMPLE_BUFFERS_ARB;
|
|
iattrib_list[ni++] = ivalue_list[sample_buffers_i];
|
|
iattrib_list[ni++] = WGL_SAMPLES_ARB;
|
|
iattrib_list[ni++] = ivalue_list[multisamples_i];
|
|
}
|
|
|
|
// Match up properties.
|
|
iattrib_list[ni++] = WGL_DOUBLE_BUFFER_ARB;
|
|
iattrib_list[ni++] = ivalue_list[double_buffer_i];
|
|
iattrib_list[ni++] = WGL_STEREO_ARB;
|
|
iattrib_list[ni++] = ivalue_list[stereo_i];
|
|
|
|
// Terminate the lists.
|
|
nassertr(ni < max_attrib_list && nf < max_attrib_list, NULL);
|
|
iattrib_list[ni] = 0;
|
|
fattrib_list[nf] = 0;
|
|
|
|
// Now obtain a list of pixel formats that meet these minimum
|
|
// requirements.
|
|
static const unsigned int max_pformats = 32;
|
|
int pformat[max_pformats];
|
|
memset(pformat, 0, sizeof(pformat));
|
|
unsigned int nformats = 0;
|
|
if (!wglgsg->_wglChoosePixelFormatARB(twindow_dc, iattrib_list, fattrib_list,
|
|
max_pformats, pformat, &nformats)
|
|
|| nformats == 0) {
|
|
if (wgldisplay_cat.is_debug()) {
|
|
wgldisplay_cat.debug()
|
|
<< "No formats meet the criteria.\n";
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
nformats = min(nformats, max_pformats);
|
|
|
|
if (wgldisplay_cat.is_debug()) {
|
|
wgldisplay_cat.debug()
|
|
<< "Found " << nformats << " pbuffer formats: [";
|
|
for (unsigned int i = 0; i < nformats; i++) {
|
|
wgldisplay_cat.debug(false)
|
|
<< " " << pformat[i];
|
|
}
|
|
wgldisplay_cat.debug(false)
|
|
<< " ]\n";
|
|
}
|
|
|
|
// If one of the options is the original pixfmt, keep it.
|
|
bool found_pbformat = false;
|
|
for (unsigned int i = 0; i < nformats && !found_pbformat; i++) {
|
|
if (pformat[i] == pbformat) {
|
|
found_pbformat = true;
|
|
}
|
|
}
|
|
|
|
if (!found_pbformat) {
|
|
// Otherwise, pick any of them.
|
|
pbformat = pformat[0];
|
|
}
|
|
|
|
return pbformat;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: wglGraphicsBuffer::process_1_event
|
|
// Access: Private, Static
|
|
// Description: Handles one event from the message queue.
|
|
////////////////////////////////////////////////////////////////////
|
|
void wglGraphicsBuffer::
|
|
process_1_event() {
|
|
MSG msg;
|
|
|
|
if (!GetMessage(&msg, NULL, 0, 0)) {
|
|
// WM_QUIT received. We need a cleaner way to deal with this.
|
|
// DestroyAllWindows(false);
|
|
exit(msg.wParam); // this will invoke AtExitFn
|
|
}
|
|
|
|
// Translate virtual key messages
|
|
TranslateMessage(&msg);
|
|
// Call window_proc
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
|