WxPandaWindow

This commit is contained in:
David Rose 2012-01-08 16:10:18 +00:00
parent ce696a157e
commit 56f22e0692
20 changed files with 1116 additions and 24 deletions

View File

@ -559,11 +559,18 @@ class ShowBase(DirectObject.DirectObject):
def openWindow(self, props = None, pipe = None, gsg = None,
type = None, name = None, size = None, aspectRatio = None,
makeCamera = 1, keepCamera = 0,
scene = None, stereo = None, rawmice = 0):
scene = None, stereo = None, rawmice = 0,
callbackWindowDict = None):
"""
Creates a window and adds it to the list of windows that are
to be updated every frame.
If callbackWindowDict is not None, a CallbackGraphicWindow is
created instead, which allows the caller to create the actual
window with its own OpenGL context, and direct Panda's
rendering into that window.
"""
if pipe == None:
pipe = self.pipe
@ -614,6 +621,9 @@ class ShowBase(DirectObject.DirectObject):
elif type == 'offscreen':
flags = flags | GraphicsPipe.BFRefuseWindow
if callbackWindowDict:
flags = flags | GraphicsPipe.BFRequireCallbackWindow
if gsg:
win = self.graphicsEngine.makeOutput(pipe, name, 0, fbprops,
props, flags, gsg)
@ -625,6 +635,23 @@ class ShowBase(DirectObject.DirectObject):
# Couldn't create a window!
return None
if callbackWindowDict:
# If we asked for (and received) a CallbackGraphicsWindow,
# we now have to assign the callbacks, before we start
# trying to do anything with the window.
for callbackName in ['Events', 'Properties', 'Render']:
func = callbackWindowDict.get(callbackName, None)
if not func:
continue
setCallbackName = 'set%sCallback' % (callbackName)
setCallback = getattr(win, setCallbackName)
setCallback(PythonCallbackObject(func))
# We also need to set up the mouse/keyboard objects.
for inputName in callbackWindowDict.get('inputDevices', ['mouse']):
win.createInputDevice(inputName)
if hasattr(win, "requestProperties"):
win.requestProperties(props)

View File

@ -2,16 +2,20 @@ import wx
from direct.task.Task import Task
def wxLoop(self):
# Do all the wxPython events waiting on this frame
# First we need to ensure that the OS message queue is processed.
base.wxApp.Yield()
# Now do all the wxPython events waiting on this frame.
while base.wxApp.Pending():
base.wxApp.Dispatch()
return Task.cont
def spawnWxLoop():
if not getattr(base, 'wxApp', None):
# Create a new base.wxApp, but only if it's not already
# created.
base.wxApp = wx.App(False)
base.wxApp = wx.PySimpleApp(redirect = False)
# Spawn this task
taskMgr.add(wxLoop, "wxLoop")

View File

@ -0,0 +1,206 @@
""" This module implements a Panda3D window that can be embedded
within a wx.Frame. The window itself is either an embedded window,
which is a wx.Window with the Panda window attached to it, or it is a
wxgl.GLCanvas, with Panda directed to draw into it, depending on the
platform. In either case, you may simply embed this window into a
wx.Frame of your choosing, using sizers or whatever you like. """
import wx
import platform
try:
import wx.glcanvas as wxgl
except ImportError:
wxgl = None
from panda3d.core import *
__all__ = ['WxPandaWindow']
if platform.system() != 'Darwin':
class EmbeddedPandaWindow(wx.Window):
""" This class implements a Panda3D window that is directly
embedded within the frame. It is fully supported on Windows,
partially supported on Linux, and not at all on OSX. """
def __init__(self, *args, **kw):
wx.Window.__init__(self, *args, **kw)
wp = WindowProperties.getDefault()
wp.setParentWindow(self.GetHandle())
if base.win:
self.win = base.openWindow(props = wp)
else:
base.openDefaultWindow(props = wp)
self.win = base.win
self.Bind(wx.EVT_SIZE, self.__resized)
def __resized(self, event):
wp = WindowProperties()
wp.setOrigin(0, 0)
wp.setSize(*self.GetClientSizeTuple())
self.win.requestProperties(wp)
if hasattr(wxgl, 'GLCanvas'):
class OpenGLPandaWindow(wxgl.GLCanvas):
""" This class implements a Panda3D "window" that actually draws
within the wx GLCanvas object. It is supported whenever OpenGL is
Panda's rendering engine, and GLCanvas is available in wx. """
Keymap = {
wx.WXK_BACK : KeyboardButton.backspace(),
wx.WXK_TAB : KeyboardButton.tab(),
wx.WXK_RETURN : KeyboardButton.enter(),
wx.WXK_ESCAPE : KeyboardButton.escape(),
wx.WXK_DELETE : KeyboardButton._del(), # del is a Python keyword
wx.WXK_SHIFT : KeyboardButton.shift(),
wx.WXK_ALT : KeyboardButton.alt(),
wx.WXK_CONTROL : KeyboardButton.control(),
wx.WXK_MENU : KeyboardButton.meta(),
wx.WXK_PAUSE : KeyboardButton.pause(),
wx.WXK_END : KeyboardButton.end(),
wx.WXK_HOME : KeyboardButton.home(),
wx.WXK_LEFT : KeyboardButton.left(),
wx.WXK_UP : KeyboardButton.up(),
wx.WXK_RIGHT : KeyboardButton.right(),
wx.WXK_DOWN : KeyboardButton.down(),
wx.WXK_PRINT : KeyboardButton.printScreen(),
wx.WXK_INSERT : KeyboardButton.insert(),
wx.WXK_F1 : KeyboardButton.f1(),
wx.WXK_F2 : KeyboardButton.f2(),
wx.WXK_F3 : KeyboardButton.f3(),
wx.WXK_F4 : KeyboardButton.f4(),
wx.WXK_F5 : KeyboardButton.f5(),
wx.WXK_F6 : KeyboardButton.f6(),
wx.WXK_F7 : KeyboardButton.f7(),
wx.WXK_F8 : KeyboardButton.f8(),
wx.WXK_F9 : KeyboardButton.f9(),
wx.WXK_F10 : KeyboardButton.f10(),
wx.WXK_F11 : KeyboardButton.f11(),
wx.WXK_F12 : KeyboardButton.f12(),
wx.WXK_NUMLOCK : KeyboardButton.numLock(),
wx.WXK_SCROLL : KeyboardButton.scrollLock(),
wx.WXK_PAGEUP : KeyboardButton.pageUp(),
wx.WXK_PAGEDOWN : KeyboardButton.pageDown(),
wx.WXK_COMMAND : KeyboardButton.meta(),
}
def __init__(self, *args, **kw):
wxgl.GLCanvas.__init__(self, *args, **kw)
callbackWindowDict = {
'Events' : self.__eventsCallback,
'Properties' : self.__propertiesCallback,
'Render' : self.__renderCallback,
}
# Make sure we have an OpenGL GraphicsPipe.
if not base.pipe:
base.makeDefaultPipe()
pipe = base.pipe
if pipe.getInterfaceName() != 'OpenGL':
base.makeAllPipes()
for pipe in base.pipeList:
if pipe.getInterfaceName() == 'OpenGL':
break
if pipe.getInterfaceName() != 'OpenGL':
raise StandardError, "Couldn't get an OpenGL pipe."
self.SetCurrent()
if base.win:
self.win = base.openWindow(callbackWindowDict = callbackWindowDict, pipe = pipe)
else:
base.openDefaultWindow(callbackWindowDict = callbackWindowDict, pipe = pipe)
self.win = base.win
self.inputDevice = self.win.getInputDevice(0)
self.Bind(wx.EVT_SIZE, self.__resized)
self.Bind(wx.EVT_LEFT_DOWN, lambda event: self.__buttonDown(MouseButton.one()))
self.Bind(wx.EVT_LEFT_UP, lambda event: self.__buttonUp(MouseButton.one()))
self.Bind(wx.EVT_MIDDLE_DOWN, lambda event: self.__buttonDown(MouseButton.two()))
self.Bind(wx.EVT_MIDDLE_UP, lambda event: self.__buttonUp(MouseButton.two()))
self.Bind(wx.EVT_RIGHT_DOWN, lambda event: self.__buttonDown(MouseButton.three()))
self.Bind(wx.EVT_RIGHT_UP, lambda event: self.__buttonUp(MouseButton.three()))
self.Bind(wx.EVT_MOTION, self.__mouseMotion)
self.Bind(wx.EVT_LEAVE_WINDOW, self.__mouseLeaveWindow)
self.Bind(wx.EVT_KEY_DOWN, self.__keyDown)
self.Bind(wx.EVT_KEY_UP, self.__keyUp)
self.Bind(wx.EVT_CHAR, self.__keystroke)
def __buttonDown(self, button):
self.inputDevice.buttonDown(button)
def __buttonUp(self, button):
self.inputDevice.buttonUp(button)
def __mouseMotion(self, event):
self.inputDevice.setPointerInWindow(*event.GetPosition())
def __mouseLeaveWindow(self, event):
self.inputDevice.setPointerOutOfWindow()
def __keyDown(self, event):
key = self.__getkey(event)
if key:
self.inputDevice.buttonDown(key)
def __keyUp(self, event):
key = self.__getkey(event)
if key:
self.inputDevice.buttonUp(key)
def __getkey(self, event):
code = event.GetKeyCode()
key = self.Keymap.get(code, None)
if key is not None:
return key
if code >= 0x41 and code <= 0x5a:
# wxWidgets returns uppercase letters, but Panda expects
# lowercase letters.
return KeyboardButton.asciiKey(code + 0x20)
if code >= 0x20 and code <= 0x80:
# Other ASCII keys are treated the same way in wx and Panda.
return KeyboardButton.asciiKey(code)
return None
def __keystroke(self, event):
if hasattr(event, 'GetUnicodeKey'):
code = event.GetUnicodeKey()
else:
code = event.GetKeyCode()
if code < 0x20 or code >= 0x80:
return
self.inputDevice.keystroke(code)
def __eventsCallback(self, data):
data.upcall()
def __propertiesCallback(self, data):
data.upcall()
def __renderCallback(self, data):
cbType = data.getCallbackType()
if cbType == CallbackGraphicsWindow.RCTBeginFrame:
self.SetCurrent()
elif cbType == CallbackGraphicsWindow.RCTEndFlip:
self.SwapBuffers()
data.upcall()
def __resized(self, event):
wp = WindowProperties()
wp.setSize(*self.GetClientSizeTuple())
self.win.requestProperties(wp)
# Choose the best implementation of WxPandaWindow for the platform.
if platform.system() == 'Darwin':
WxPandaWindow = OpenGLPandaWindow
else:
WxPandaWindow = EmbeddedPandaWindow

View File

@ -14,6 +14,7 @@
standardMunger.I standardMunger.h \
config_display.h \
$[if $[HAVE_PYTHON], pythonGraphicsWindowProc.h] \
callbackGraphicsWindow.I callbackGraphicsWindow.h \
drawableRegion.I drawableRegion.h \
displayRegion.I displayRegion.h \
displayRegionCullCallbackData.I displayRegionCullCallbackData.h \
@ -53,6 +54,7 @@
standardMunger.cxx \
config_display.cxx \
$[if $[HAVE_PYTHON], pythonGraphicsWindowProc.cxx] \
callbackGraphicsWindow.cxx \
drawableRegion.cxx \
displayRegion.cxx \
displayRegionCullCallbackData.cxx \
@ -85,6 +87,7 @@
standardMunger.I standardMunger.h \
config_display.h \
$[if $[HAVE_PYTHON], pythonGraphicsWindowProc.h] \
callbackGraphicsWindow.I callbackGraphicsWindow.h \
drawableRegion.I drawableRegion.h \
displayInformation.h \
displayRegion.I displayRegion.h \

View File

@ -0,0 +1,260 @@
// Filename: callbackGraphicsWindow.I
// Created by: drose (06Jan11)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::set_events_callback
// Access: Published
// Description: Sets the CallbackObject that will be notified when
// this window is polled for window events, including
// mouse and keyboard events, as well as window resize
// events and other system-generated events.
//
// This callback will receive a
// CallbackGraphicsWindow::EventsCallbackData.
//
// This callback should process any system-generated
// events, and call data->upcall() to process requested
// property change requests made via
// request_properties().
////////////////////////////////////////////////////////////////////
INLINE void CallbackGraphicsWindow::
set_events_callback(CallbackObject *object) {
_events_callback = object;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::clear_events_callback
// Access: Published
// Description: Removes the callback set by an earlier call to
// set_events_callback().
////////////////////////////////////////////////////////////////////
INLINE void CallbackGraphicsWindow::
clear_events_callback() {
set_events_callback(NULL);
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::get_events_callback
// Access: Published
// Description: Returns the CallbackObject set by set_events_callback().
////////////////////////////////////////////////////////////////////
INLINE CallbackObject *CallbackGraphicsWindow::
get_events_callback() const {
return _events_callback;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::set_properties_callback
// Access: Published
// Description: Sets the CallbackObject that will be notified when
// this window receives a property change request from
// user code (e.g. via request_properties).
//
// This callback will receive a
// CallbackGraphicsWindow::PropertiesCallbackData, which
// provides a get_properties() method that returns a
// modifiable reference to a WindowsProperties object.
// This object will contain only those properties
// requested by user code. The callback should handle
// any of the requests it finds, including and
// especially set_open(), and remove them from the
// object when it has handled them. Any unhandled
// properties should be left unchanged in the properties
// object.
////////////////////////////////////////////////////////////////////
INLINE void CallbackGraphicsWindow::
set_properties_callback(CallbackObject *object) {
_properties_callback = object;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::clear_properties_callback
// Access: Published
// Description: Removes the callback set by an earlier call to
// set_properties_callback().
////////////////////////////////////////////////////////////////////
INLINE void CallbackGraphicsWindow::
clear_properties_callback() {
set_properties_callback(NULL);
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::get_properties_callback
// Access: Published
// Description: Returns the CallbackObject set by set_properties_callback().
////////////////////////////////////////////////////////////////////
INLINE CallbackObject *CallbackGraphicsWindow::
get_properties_callback() const {
return _properties_callback;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::set_render_callback
// Access: Published
// Description: Sets the CallbackObject that will be notified when
// this window is invoked (in the draw thread) to render
// its contents, and/or flip the graphics buffers.
//
// This callback will actually serve several different
// functions. It receivces a RenderCallbackData, and
// you can query data->get_callback_type() to return the
// actual function of each particular callback.
////////////////////////////////////////////////////////////////////
INLINE void CallbackGraphicsWindow::
set_render_callback(CallbackObject *object) {
_render_callback = object;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::clear_render_callback
// Access: Published
// Description: Removes the callback set by an earlier call to
// set_render_callback().
////////////////////////////////////////////////////////////////////
INLINE void CallbackGraphicsWindow::
clear_render_callback() {
set_render_callback(NULL);
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::get_render_callback
// Access: Published
// Description: Returns the CallbackObject set by set_render_callback().
////////////////////////////////////////////////////////////////////
INLINE CallbackObject *CallbackGraphicsWindow::
get_render_callback() const {
return _render_callback;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::WindowCallbackData::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE CallbackGraphicsWindow::WindowCallbackData::
WindowCallbackData(CallbackGraphicsWindow *window) : _window(window) {
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::WindowCallbackData::get_window
// Access: Published
// Description: Returns the window this callback was triggered from.
////////////////////////////////////////////////////////////////////
INLINE CallbackGraphicsWindow *CallbackGraphicsWindow::WindowCallbackData::
get_window() const {
return _window;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::EventsCallbackData::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE CallbackGraphicsWindow::EventsCallbackData::
EventsCallbackData(CallbackGraphicsWindow *window) :
WindowCallbackData(window)
{
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::PropertiesCallbackData::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE CallbackGraphicsWindow::PropertiesCallbackData::
PropertiesCallbackData(CallbackGraphicsWindow *window, WindowProperties &properties) :
WindowCallbackData(window),
_properties(properties)
{
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::PropertiesCallbackData::get_properties
// Access: Published
// Description: Returns the WindowProperties object that this
// callback should process. Any properties that are
// handled should be removed from this object;
// properties that are unhandled should be left alone.
////////////////////////////////////////////////////////////////////
INLINE WindowProperties &CallbackGraphicsWindow::PropertiesCallbackData::
get_properties() const {
return _properties;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::RenderCallbackData::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE CallbackGraphicsWindow::RenderCallbackData::
RenderCallbackData(CallbackGraphicsWindow *window, RenderCallbackType callback_type, FrameMode frame_mode) :
WindowCallbackData(window),
_callback_type(callback_type),
_frame_mode(frame_mode),
_render_flag(true)
{
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::RenderCallbackData::get_callback_type
// Access: Published
// Description: Since the render callback is shared for several
// functions, this method is needed to indicate which
// particular function is being invoked with this
// callback.
////////////////////////////////////////////////////////////////////
INLINE CallbackGraphicsWindow::RenderCallbackType CallbackGraphicsWindow::RenderCallbackData::
get_callback_type() const {
return _callback_type;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::RenderCallbackData::get_frame_mode
// Access: Published
// Description: If the callback type (returned by get_callback_type)
// is RCT_begin_frame or RCT_end_frame, then this method
// will return the particular frame mode indicating
// what, precisely, we want to do this frame.
////////////////////////////////////////////////////////////////////
INLINE GraphicsOutput::FrameMode CallbackGraphicsWindow::RenderCallbackData::
get_frame_mode() const {
return _frame_mode;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::RenderCallbackData::set_render_flag
// Access: Published
// Description: If the callback type is RCT_begin_frame, this call is
// available to specify the return value from the
// begin_frame() call. If this is true (the default),
// the frame is rendered normally; if it is false, the
// frame is omitted.
////////////////////////////////////////////////////////////////////
INLINE void CallbackGraphicsWindow::RenderCallbackData::
set_render_flag(bool render_flag) {
_render_flag = render_flag;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::RenderCallbackData::get_render_flag
// Access: Published
// Description: Returns the current setting of the render flag. See
// set_render_flag().
////////////////////////////////////////////////////////////////////
INLINE bool CallbackGraphicsWindow::RenderCallbackData::
get_render_flag() const {
return _render_flag;
}

View File

@ -0,0 +1,299 @@
// Filename: callbackGraphicsWindow.cxx
// Created by: drose (06Jan11)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#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;
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::Constructor
// Access: Protected
// Description: Use GraphicsEngine::make_output() to construct a
// CallbackGraphicsWindow.
////////////////////////////////////////////////////////////////////
CallbackGraphicsWindow::
CallbackGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
const string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsStateGuardian *gsg) :
GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, NULL)
{
#ifdef DO_MEMORY_USAGE
MemoryUsage::update_type(this, this);
#endif
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::Destructor
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CallbackGraphicsWindow::
~CallbackGraphicsWindow() {
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::get_input_device
// Access: Published
// Description: 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];
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::create_input_device
// Access: Published
// Description: 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 string &name) {
GraphicsWindowInputDevice device =
GraphicsWindowInputDevice::pointer_and_keyboard(this, name);
return add_input_device(device);
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::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 CallbackGraphicsWindow::
begin_frame(FrameMode mode, Thread *current_thread) {
bool result = false;
if (_render_callback != NULL) {
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);
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::end_frame
// Access: Public, Virtual
// Description: 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 != NULL) {
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();
}
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::begin_flip
// Access: Public, Virtual
// Description: 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 != NULL) {
RenderCallbackData data(this, RCT_begin_flip, FM_render);
_render_callback->do_callback(&data);
} else {
GraphicsWindow::begin_flip();
}
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::end_flip
// Access: Public, Virtual
// Description: 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 != NULL) {
RenderCallbackData data(this, RCT_end_flip, FM_render);
_render_callback->do_callback(&data);
} else {
GraphicsWindow::end_flip();
}
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::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 CallbackGraphicsWindow::
process_events() {
if (_events_callback != NULL) {
EventsCallbackData data(this);
_events_callback->do_callback(&data);
} else {
GraphicsWindow::process_events();
}
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::set_properties_now
// Access: Public, Virtual
// Description: 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 != NULL) {
PropertiesCallbackData data(this, properties);
_properties_callback->do_callback(&data);
} else {
GraphicsWindow::set_properties_now(properties);
}
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::open_window
// 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 CallbackGraphicsWindow::
open_window() {
// In this case, we assume the callback has handled the window
// opening.
return true;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::do_reshape_request
// Access: Protected, Virtual
// Description: 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;
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::EventsCallbackData::upcall
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void CallbackGraphicsWindow::EventsCallbackData::
upcall() {
_window->GraphicsWindow::process_events();
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::PropertiesCallbackData::upcall
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void CallbackGraphicsWindow::PropertiesCallbackData::
upcall() {
_window->GraphicsWindow::set_properties_now(_properties);
}
////////////////////////////////////////////////////////////////////
// Function: CallbackGraphicsWindow::RenderCallbackData::upcall
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void CallbackGraphicsWindow::RenderCallbackData::
upcall() {
switch (_callback_type) {
case RCT_begin_frame:
_window->GraphicsWindow::begin_frame(_frame_mode, Thread::get_current_thread());
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;
}
}

View File

@ -0,0 +1,231 @@
// Filename: callbackGraphicsWindow.h
// Created by: drose (06Jan11)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#ifndef CALLBACKGRAPHICSWINDOW_H
#define CALLBACKGRAPHICSWINDOW_H
#include "pandabase.h"
#include "graphicsWindow.h"
////////////////////////////////////////////////////////////////////
// Class : CallbackGraphicsWindow
// Description : This special window object doesn't represent a window
// in its own right, but instead hooks into some
// third-party API for creating and rendering to windows
// via callbacks. This can be used to allow Panda to
// render into an already-created OpenGL context, for
// instance.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_DISPLAY CallbackGraphicsWindow : public GraphicsWindow {
protected:
CallbackGraphicsWindow(GraphicsEngine *engine,
GraphicsPipe *pipe,
const string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsStateGuardian *gsg);
PUBLISHED:
virtual ~CallbackGraphicsWindow();
class WindowCallbackData : public CallbackData {
public:
INLINE WindowCallbackData(CallbackGraphicsWindow *window);
PUBLISHED:
INLINE CallbackGraphicsWindow *get_window() const;
protected:
PT(CallbackGraphicsWindow) _window;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
CallbackData::init_type();
register_type(_type_handle, "CallbackGraphicsWindow::WindowCallbackData",
CallbackData::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
class EventsCallbackData : public WindowCallbackData {
public:
INLINE EventsCallbackData(CallbackGraphicsWindow *window);
PUBLISHED:
virtual void upcall();
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
WindowCallbackData::init_type();
register_type(_type_handle, "CallbackGraphicsWindow::EventsCallbackData",
WindowCallbackData::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
class PropertiesCallbackData : public WindowCallbackData {
public:
INLINE PropertiesCallbackData(CallbackGraphicsWindow *window, WindowProperties &properties);
PUBLISHED:
INLINE WindowProperties &get_properties() const;
virtual void upcall();
private:
WindowProperties &_properties;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
WindowCallbackData::init_type();
register_type(_type_handle, "CallbackGraphicsWindow::PropertiesCallbackData",
WindowCallbackData::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
enum RenderCallbackType {
RCT_begin_frame,
RCT_end_frame,
RCT_begin_flip,
RCT_end_flip,
};
class RenderCallbackData : public WindowCallbackData {
public:
INLINE RenderCallbackData(CallbackGraphicsWindow *window, RenderCallbackType callback_type, FrameMode frame_mode);
PUBLISHED:
INLINE CallbackGraphicsWindow::RenderCallbackType get_callback_type() const;
INLINE GraphicsOutput::FrameMode get_frame_mode() const;
INLINE void set_render_flag(bool render_flag);
INLINE bool get_render_flag() const;
virtual void upcall();
private:
RenderCallbackType _callback_type;
FrameMode _frame_mode;
bool _render_flag;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
WindowCallbackData::init_type();
register_type(_type_handle, "CallbackGraphicsWindow::RenderCallbackData",
WindowCallbackData::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
INLINE void set_events_callback(CallbackObject *object);
INLINE void clear_events_callback();
INLINE CallbackObject *get_events_callback() const;
INLINE void set_properties_callback(CallbackObject *object);
INLINE void clear_properties_callback();
INLINE CallbackObject *get_properties_callback() const;
INLINE void set_render_callback(CallbackObject *object);
INLINE void clear_render_callback();
INLINE CallbackObject *get_render_callback() const;
GraphicsWindowInputDevice &get_input_device(int device);
int create_input_device(const string &name);
public:
virtual bool begin_frame(FrameMode mode, Thread *current_thread);
virtual void end_frame(FrameMode mode, Thread *current_thread);
virtual void begin_flip();
virtual void end_flip();
virtual void process_events();
virtual void set_properties_now(WindowProperties &properties);
protected:
virtual bool open_window();
virtual bool do_reshape_request(int x_origin, int y_origin, bool has_origin,
int x_size, int y_size);
private:
PT(CallbackObject) _events_callback;
PT(CallbackObject) _properties_callback;
PT(CallbackObject) _render_callback;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
GraphicsWindow::init_type();
register_type(_type_handle, "CallbackGraphicsWindow",
GraphicsWindow::get_class_type());
WindowCallbackData::init_type();
EventsCallbackData::init_type();
PropertiesCallbackData::init_type();
RenderCallbackData::init_type();
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
friend class GraphicsEngine;
};
#include "callbackGraphicsWindow.I"
#endif

View File

@ -13,6 +13,7 @@
////////////////////////////////////////////////////////////////////
#include "config_display.h"
#include "callbackGraphicsWindow.h"
#include "displayRegion.h"
#include "displayRegionCullCallbackData.h"
#include "displayRegionDrawCallbackData.h"
@ -449,6 +450,7 @@ init_libdisplay() {
}
initialized = true;
CallbackGraphicsWindow::init_type();
DisplayRegion::init_type();
DisplayRegionCullCallbackData::init_type();
DisplayRegionDrawCallbackData::init_type();

View File

@ -337,11 +337,34 @@ make_output(GraphicsPipe *pipe,
gsg->get_threading_model().get_draw_name(), NULL);
}
// Are we really asking for a callback window?
if ((flags & GraphicsPipe::BF_require_callback_window)!=0) {
PT(GraphicsStateGuardian) this_gsg = gsg;
if (this_gsg == (GraphicsStateGuardian *)NULL) {
// If we don't already have a GSG, we have to ask the pipe to
// make a new one, unencumbered by window dressing.
this_gsg = pipe->make_callback_gsg(this);
}
if (this_gsg != (GraphicsStateGuardian *)NULL) {
CallbackGraphicsWindow *window = new CallbackGraphicsWindow(this, pipe, name, fb_prop, win_prop, flags, this_gsg);
window->_sort = sort;
do_add_window(window, threading_model);
do_add_gsg(window->get_gsg(), pipe, threading_model);
display_cat.info() << "Created output of type CallbackGraphicsWindow\n";
return window;
}
// Couldn't make a callback window, because the pipe wouldn't make
// an unencumbered GSG.
return NULL;
}
// Determine if a parasite buffer meets the user's specs.
bool can_use_parasite = false;
if ((host != 0)&&
((flags&GraphicsPipe::BF_require_window)==0)&&
((flags&GraphicsPipe::BF_require_callback_window)==0)&&
((flags&GraphicsPipe::BF_refuse_parasite)==0)&&
((flags&GraphicsPipe::BF_can_bind_color)==0)&&
((flags&GraphicsPipe::BF_can_bind_every)==0)&&
@ -1998,7 +2021,6 @@ void GraphicsEngine::
do_add_gsg(GraphicsStateGuardian *gsg, GraphicsPipe *pipe,
const GraphicsThreadingModel &threading_model) {
ReMutexHolder holder(_lock);
nassertv(gsg->get_pipe() == pipe && gsg->get_engine() == this);
gsg->_threading_model = threading_model;
if (!_default_loader.is_null()) {

View File

@ -138,6 +138,20 @@ make_output(const string &name,
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsPipe::make_callback_gsg
// Access: Protected, Virtual
// Description: This is called when make_output() is used to create a
// CallbackGraphicsWindow. If the GraphicsPipe can
// construct a GSG that's not associated with any
// particular window object, do so now, assuming the
// correct graphics context has been set up externally.
////////////////////////////////////////////////////////////////////
PT(GraphicsStateGuardian) GraphicsPipe::
make_callback_gsg(GraphicsEngine *engine) {
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsPipe::get_display_information
// Access: Published

View File

@ -78,6 +78,7 @@ PUBLISHED:
BF_require_parasite = 0x0002,
BF_refuse_window = 0x0004,
BF_require_window = 0x0008,
BF_require_callback_window = 0x0010,
// Miscellaneous control flags.
BF_can_bind_color = 0x0040, // Need capability: bind the color bitplane to a tex.
@ -124,6 +125,7 @@ protected:
GraphicsOutput *host,
int retry,
bool &precertify);
virtual PT(GraphicsStateGuardian) make_callback_gsg(GraphicsEngine *engine);
LightMutex _lock;

View File

@ -2398,8 +2398,7 @@ determine_target_texture() {
nassertv(target_texture != (TextureAttrib *)NULL &&
target_tex_gen != (TexGenAttrib *)NULL);
int max_texture_stages = get_max_texture_stages();
_target_texture = target_texture->filter_to_max(max_texture_stages);
_target_texture = target_texture;
_target_tex_gen = target_tex_gen;
if (_has_texture_alpha_scale) {
@ -2411,6 +2410,8 @@ determine_target_texture() {
(stage, TexGenAttrib::M_constant, LTexCoord3(_current_color_scale[3], 0.0f, 0.0f)));
}
int max_texture_stages = get_max_texture_stages();
_target_texture = _target_texture->filter_to_max(max_texture_stages);
nassertv(_target_texture->get_num_on_stages() <= max_texture_stages);
}

View File

@ -56,14 +56,3 @@ get_window_handle() const {
return _window_handle;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsWindow::add_input_device
// Access: Protected
// Description: Adds a GraphicsWindowInputDevice to the vector.
////////////////////////////////////////////////////////////////////
INLINE void GraphicsWindow::
add_input_device(const GraphicsWindowInputDevice &device) {
_input_devices.push_back(device);
_input_devices.back().set_device_index(_input_devices.size()-1);
}

View File

@ -853,6 +853,21 @@ system_changed_size(int x_size, int y_size) {
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsWindow::add_input_device
// Access: Protected
// Description: Adds a GraphicsWindowInputDevice to the vector.
// Returns the index of the new device.
////////////////////////////////////////////////////////////////////
int GraphicsWindow::
add_input_device(const GraphicsWindowInputDevice &device) {
LightMutexHolder holder(_input_lock);
int index = (int)_input_devices.size();
_input_devices.push_back(device);
_input_devices.back().set_device_index(index);
return index;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsWindow::mouse_mode_relative
// Access: Protected, Virtual

View File

@ -141,7 +141,7 @@ protected:
void system_changed_size(int x_size, int y_size);
protected:
INLINE void add_input_device(const GraphicsWindowInputDevice &device);
int add_input_device(const GraphicsWindowInputDevice &device);
typedef vector_GraphicsWindowInputDevice InputDevices;
InputDevices _input_devices;
LightMutex _input_lock;

View File

@ -71,7 +71,7 @@ public:
bool has_pointer_event() const;
PT(PointerEventList) get_pointer_events();
public:
PUBLISHED:
// The following interface is for the various kinds of
// GraphicsWindows to record the data incoming on the device.
void button_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());

View File

@ -1,4 +1,5 @@
#include "config_display.cxx"
#include "callbackGraphicsWindow.cxx"
#include "displayInformation.cxx"
#include "displayRegion.cxx"
#include "displayRegionCullCallbackData.cxx"

View File

@ -464,3 +464,16 @@ make_output(const string &name,
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: osxGraphicsPipe::make_callback_gsg
// Access: Protected, Virtual
// Description: This is called when make_output() is used to create a
// CallbackGraphicsWindow. If the GraphicsPipe can
// construct a GSG that's not associated with any
// particular window object, do so now, assuming the
// correct graphics context has been set up externally.
////////////////////////////////////////////////////////////////////
PT(GraphicsStateGuardian) osxGraphicsPipe::
make_callback_gsg(GraphicsEngine *engine) {
return new osxGraphicsStateGuardian(engine, this, NULL);
}

View File

@ -50,6 +50,7 @@ protected:
GraphicsOutput *host,
int retry,
bool &precertify);
virtual PT(GraphicsStateGuardian) make_callback_gsg(GraphicsEngine *engine);
public:
static TypeHandle get_class_type() {

View File

@ -100,10 +100,12 @@ void osxGraphicsStateGuardian::reset()
GLGraphicsStateGuardian::reset();
// Apply the video-sync setting.
GLint value = sync_video ? 1 : 0;
aglSetInteger(_aglcontext, AGL_SWAP_INTERVAL, &value);
}
if (_aglcontext != (AGLContext)NULL) {
// Apply the video-sync setting.
GLint value = sync_video ? 1 : 0;
aglSetInteger(_aglcontext, AGL_SWAP_INTERVAL, &value);
}
}
////////////////////////////////////////////////////////////////////
// Function: osxGraphicsStateGuardian::draw_resize_box