278 lines
7.8 KiB
C++
278 lines
7.8 KiB
C++
/**
|
|
* PANDA 3D SOFTWARE
|
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
*
|
|
* All use of this software is subject to the terms of the revised BSD
|
|
* license. You should have received a copy of this license along
|
|
* with this source code in a file named "LICENSE."
|
|
*
|
|
* @file callbackGraphicsWindow.cxx
|
|
* @author drose
|
|
* @date 2011-01-06
|
|
*/
|
|
|
|
#include "callbackGraphicsWindow.h"
|
|
|
|
TypeHandle CallbackGraphicsWindow::_type_handle;
|
|
TypeHandle CallbackGraphicsWindow::WindowCallbackData::_type_handle;
|
|
TypeHandle CallbackGraphicsWindow::EventsCallbackData::_type_handle;
|
|
TypeHandle CallbackGraphicsWindow::PropertiesCallbackData::_type_handle;
|
|
TypeHandle CallbackGraphicsWindow::RenderCallbackData::_type_handle;
|
|
|
|
/**
|
|
* Use GraphicsEngine::make_output() to construct a CallbackGraphicsWindow.
|
|
*/
|
|
CallbackGraphicsWindow::
|
|
CallbackGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
|
|
const std::string &name,
|
|
const FrameBufferProperties &fb_prop,
|
|
const WindowProperties &win_prop,
|
|
int flags,
|
|
GraphicsStateGuardian *gsg) :
|
|
GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, nullptr)
|
|
{
|
|
#ifdef DO_MEMORY_USAGE
|
|
MemoryUsage::update_type(this, this);
|
|
#endif
|
|
|
|
// Let's ensure that these properties are set to *something* initially.
|
|
_properties.set_origin(0, 0);
|
|
_properties.set_size(0, 0);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
CallbackGraphicsWindow::
|
|
~CallbackGraphicsWindow() {
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns a writable reference to the nth input device (mouse). This is
|
|
* intended to be used for the window implementation to record mouse and
|
|
* keyboard input information for the Panda system.
|
|
*/
|
|
GraphicsWindowInputDevice &CallbackGraphicsWindow::
|
|
get_input_device(int device) {
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertr(device >= 0 && device < (int)_input_devices.size(), _input_devices[0]);
|
|
return _input_devices[device];
|
|
}
|
|
|
|
/**
|
|
* Adds a new input device (mouse) to the window with the indicated name.
|
|
* Returns the index of the new device.
|
|
*/
|
|
int CallbackGraphicsWindow::
|
|
create_input_device(const std::string &name) {
|
|
GraphicsWindowInputDevice device =
|
|
GraphicsWindowInputDevice::pointer_and_keyboard(this, name);
|
|
return add_input_device(device);
|
|
}
|
|
|
|
/**
|
|
* 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 CallbackGraphicsWindow::
|
|
begin_frame(FrameMode mode, Thread *current_thread) {
|
|
bool result = false;
|
|
if (_render_callback != nullptr) {
|
|
RenderCallbackData data(this, RCT_begin_frame, mode);
|
|
_render_callback->do_callback(&data);
|
|
result = data.get_render_flag();
|
|
} else {
|
|
result = GraphicsWindow::begin_frame(mode, current_thread);
|
|
}
|
|
|
|
if (!result) {
|
|
return false;
|
|
}
|
|
|
|
_gsg->reset_if_new();
|
|
_gsg->set_current_properties(&get_fb_properties());
|
|
|
|
return _gsg->begin_frame(current_thread);
|
|
}
|
|
|
|
/**
|
|
* This function will be called within the draw thread after rendering is
|
|
* completed for a given frame. It should do whatever finalization is
|
|
* required.
|
|
*/
|
|
void CallbackGraphicsWindow::
|
|
end_frame(FrameMode mode, Thread *current_thread) {
|
|
if (_render_callback != nullptr) {
|
|
// In case the callback or the application hosting the OpenGL context
|
|
// wants to do more rendering, let's give it a blank slate.
|
|
_gsg->set_state_and_transform(RenderState::make_empty(), _gsg->get_internal_transform());
|
|
_gsg->clear_before_callback();
|
|
|
|
RenderCallbackData data(this, RCT_end_frame, mode);
|
|
_render_callback->do_callback(&data);
|
|
} else {
|
|
GraphicsWindow::end_frame(mode, current_thread);
|
|
}
|
|
|
|
_gsg->end_frame(current_thread);
|
|
|
|
if (mode == FM_render) {
|
|
trigger_flip();
|
|
clear_cube_map_selection();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will be called within the draw thread after end_frame() has
|
|
* been called on all windows, to initiate the exchange of the front and back
|
|
* buffers.
|
|
*
|
|
* This should instruct the window to prepare for the flip at the next video
|
|
* sync, but it should not wait.
|
|
*
|
|
* We have the two separate functions, begin_flip() and end_flip(), to make it
|
|
* easier to flip all of the windows at the same time.
|
|
*/
|
|
void CallbackGraphicsWindow::
|
|
begin_flip() {
|
|
if (_render_callback != nullptr) {
|
|
RenderCallbackData data(this, RCT_begin_flip, FM_render);
|
|
_render_callback->do_callback(&data);
|
|
} else {
|
|
GraphicsWindow::begin_flip();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will be called within the draw thread after begin_flip() has
|
|
* been called on all windows, to finish the exchange of the front and back
|
|
* buffers.
|
|
*
|
|
* This should cause the window to wait for the flip, if necessary.
|
|
*/
|
|
void CallbackGraphicsWindow::
|
|
end_flip() {
|
|
if (_render_callback != nullptr) {
|
|
RenderCallbackData data(this, RCT_end_flip, FM_render);
|
|
_render_callback->do_callback(&data);
|
|
} else {
|
|
GraphicsWindow::end_flip();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 CallbackGraphicsWindow::
|
|
process_events() {
|
|
if (_events_callback != nullptr) {
|
|
EventsCallbackData data(this);
|
|
_events_callback->do_callback(&data);
|
|
} else {
|
|
GraphicsWindow::process_events();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Applies the requested set of properties to the window, if possible, for
|
|
* instance to request a change in size or minimization status.
|
|
*/
|
|
void CallbackGraphicsWindow::
|
|
set_properties_now(WindowProperties &properties) {
|
|
if (_properties_callback != nullptr) {
|
|
PropertiesCallbackData data(this, properties);
|
|
_properties_callback->do_callback(&data);
|
|
} else {
|
|
GraphicsWindow::set_properties_now(properties);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 CallbackGraphicsWindow::
|
|
open_window() {
|
|
// In this case, we assume the callback has handled the window opening.
|
|
|
|
// We also assume the callback has given us an accurate
|
|
// FramebufferProperties, but we do go ahead and assume some certain minimum
|
|
// properties.
|
|
_fb_properties.set_rgb_color(1);
|
|
|
|
if (_fb_properties.get_color_bits() == 0) {
|
|
_fb_properties.set_color_bits(16);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Called from the window thread in response to a request from within the code
|
|
* (via request_properties()) to change the size and/or position of the
|
|
* window. Returns true if the window is successfully changed, or false if
|
|
* there was a problem.
|
|
*/
|
|
bool CallbackGraphicsWindow::
|
|
do_reshape_request(int x_origin, int y_origin, bool has_origin,
|
|
int x_size, int y_size) {
|
|
// In this case, we assume the callback has handled the window resizing.
|
|
WindowProperties properties;
|
|
if (has_origin) {
|
|
properties.set_origin(x_origin, y_origin);
|
|
}
|
|
properties.set_size(x_size, y_size);
|
|
system_changed_properties(properties);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
void CallbackGraphicsWindow::EventsCallbackData::
|
|
upcall() {
|
|
_window->GraphicsWindow::process_events();
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
void CallbackGraphicsWindow::PropertiesCallbackData::
|
|
upcall() {
|
|
_window->GraphicsWindow::set_properties_now(_properties);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
void CallbackGraphicsWindow::RenderCallbackData::
|
|
upcall() {
|
|
switch (_callback_type) {
|
|
case RCT_begin_frame:
|
|
{
|
|
bool render_flag = _window->GraphicsWindow::begin_frame(_frame_mode, Thread::get_current_thread());
|
|
set_render_flag(render_flag);
|
|
}
|
|
break;
|
|
|
|
case RCT_end_frame:
|
|
_window->GraphicsWindow::end_frame(_frame_mode, Thread::get_current_thread());
|
|
break;
|
|
|
|
case RCT_begin_flip:
|
|
_window->GraphicsWindow::begin_flip();
|
|
break;
|
|
|
|
case RCT_end_flip:
|
|
_window->GraphicsWindow::end_flip();
|
|
break;
|
|
}
|
|
}
|