From 56f22e0692043e750dc3d57790fdd86283f88254 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sun, 8 Jan 2012 16:10:18 +0000 Subject: [PATCH] WxPandaWindow --- direct/src/showbase/ShowBase.py | 29 +- direct/src/showbase/WxGlobal.py | 8 +- direct/src/showbase/WxPandaWindow.py | 206 ++++++++++++ panda/src/display/Sources.pp | 3 + panda/src/display/callbackGraphicsWindow.I | 260 +++++++++++++++ panda/src/display/callbackGraphicsWindow.cxx | 299 ++++++++++++++++++ panda/src/display/callbackGraphicsWindow.h | 231 ++++++++++++++ panda/src/display/config_display.cxx | 2 + panda/src/display/graphicsEngine.cxx | 24 +- panda/src/display/graphicsPipe.cxx | 14 + panda/src/display/graphicsPipe.h | 2 + panda/src/display/graphicsStateGuardian.cxx | 5 +- panda/src/display/graphicsWindow.I | 11 - panda/src/display/graphicsWindow.cxx | 15 + panda/src/display/graphicsWindow.h | 2 +- panda/src/display/graphicsWindowInputDevice.h | 2 +- panda/src/display/p3display_composite1.cxx | 1 + panda/src/osxdisplay/osxGraphicsPipe.cxx | 15 +- panda/src/osxdisplay/osxGraphicsPipe.h | 1 + .../osxdisplay/osxGraphicsStateGuardian.cxx | 10 +- 20 files changed, 1116 insertions(+), 24 deletions(-) create mode 100644 direct/src/showbase/WxPandaWindow.py create mode 100644 panda/src/display/callbackGraphicsWindow.I create mode 100644 panda/src/display/callbackGraphicsWindow.cxx create mode 100644 panda/src/display/callbackGraphicsWindow.h diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 9703d6d254..197cb73fb7 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -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) diff --git a/direct/src/showbase/WxGlobal.py b/direct/src/showbase/WxGlobal.py index 17a4a4efa1..b89aed37d7 100755 --- a/direct/src/showbase/WxGlobal.py +++ b/direct/src/showbase/WxGlobal.py @@ -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") diff --git a/direct/src/showbase/WxPandaWindow.py b/direct/src/showbase/WxPandaWindow.py new file mode 100644 index 0000000000..ed7c337639 --- /dev/null +++ b/direct/src/showbase/WxPandaWindow.py @@ -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 diff --git a/panda/src/display/Sources.pp b/panda/src/display/Sources.pp index 74ba3923bb..99a8cca70b 100644 --- a/panda/src/display/Sources.pp +++ b/panda/src/display/Sources.pp @@ -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 \ diff --git a/panda/src/display/callbackGraphicsWindow.I b/panda/src/display/callbackGraphicsWindow.I new file mode 100644 index 0000000000..12592b5ebb --- /dev/null +++ b/panda/src/display/callbackGraphicsWindow.I @@ -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; +} diff --git a/panda/src/display/callbackGraphicsWindow.cxx b/panda/src/display/callbackGraphicsWindow.cxx new file mode 100644 index 0000000000..fb729daf59 --- /dev/null +++ b/panda/src/display/callbackGraphicsWindow.cxx @@ -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; + } +} diff --git a/panda/src/display/callbackGraphicsWindow.h b/panda/src/display/callbackGraphicsWindow.h new file mode 100644 index 0000000000..484e87754f --- /dev/null +++ b/panda/src/display/callbackGraphicsWindow.h @@ -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 diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index 7897ac5ad6..941006311a 100644 --- a/panda/src/display/config_display.cxx +++ b/panda/src/display/config_display.cxx @@ -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(); diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index f64287be48..5422b0a654 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -336,12 +336,35 @@ make_output(GraphicsPipe *pipe, nassertr(threading_model.get_draw_name() == 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()) { diff --git a/panda/src/display/graphicsPipe.cxx b/panda/src/display/graphicsPipe.cxx index 84fce1fb82..76ed9f2135 100644 --- a/panda/src/display/graphicsPipe.cxx +++ b/panda/src/display/graphicsPipe.cxx @@ -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 diff --git a/panda/src/display/graphicsPipe.h b/panda/src/display/graphicsPipe.h index 8508d50f7a..5c771e0a3e 100644 --- a/panda/src/display/graphicsPipe.h +++ b/panda/src/display/graphicsPipe.h @@ -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; diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 9a0dc918a4..8cb6135649 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -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); } diff --git a/panda/src/display/graphicsWindow.I b/panda/src/display/graphicsWindow.I index fa93d2f611..3a7bb12b17 100644 --- a/panda/src/display/graphicsWindow.I +++ b/panda/src/display/graphicsWindow.I @@ -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); -} - diff --git a/panda/src/display/graphicsWindow.cxx b/panda/src/display/graphicsWindow.cxx index 7b45d09f3d..cf0838b104 100644 --- a/panda/src/display/graphicsWindow.cxx +++ b/panda/src/display/graphicsWindow.cxx @@ -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 diff --git a/panda/src/display/graphicsWindow.h b/panda/src/display/graphicsWindow.h index 6a1f747591..e43aa9cf01 100644 --- a/panda/src/display/graphicsWindow.h +++ b/panda/src/display/graphicsWindow.h @@ -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; diff --git a/panda/src/display/graphicsWindowInputDevice.h b/panda/src/display/graphicsWindowInputDevice.h index f67b6276c3..a72770d07e 100644 --- a/panda/src/display/graphicsWindowInputDevice.h +++ b/panda/src/display/graphicsWindowInputDevice.h @@ -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()); diff --git a/panda/src/display/p3display_composite1.cxx b/panda/src/display/p3display_composite1.cxx index d20eb105d0..c273b235d8 100644 --- a/panda/src/display/p3display_composite1.cxx +++ b/panda/src/display/p3display_composite1.cxx @@ -1,4 +1,5 @@ #include "config_display.cxx" +#include "callbackGraphicsWindow.cxx" #include "displayInformation.cxx" #include "displayRegion.cxx" #include "displayRegionCullCallbackData.cxx" diff --git a/panda/src/osxdisplay/osxGraphicsPipe.cxx b/panda/src/osxdisplay/osxGraphicsPipe.cxx index 91a9181175..b9efb87ba6 100644 --- a/panda/src/osxdisplay/osxGraphicsPipe.cxx +++ b/panda/src/osxdisplay/osxGraphicsPipe.cxx @@ -383,7 +383,7 @@ make_output(const string &name, if (gsg != 0) { DCAST_INTO_R(osxgsg, gsg, NULL); } - + // First thing to try: an osxGraphicsWindow if (retry == 0) { @@ -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); +} diff --git a/panda/src/osxdisplay/osxGraphicsPipe.h b/panda/src/osxdisplay/osxGraphicsPipe.h index 5a02993bb6..7cf7b9b718 100644 --- a/panda/src/osxdisplay/osxGraphicsPipe.h +++ b/panda/src/osxdisplay/osxGraphicsPipe.h @@ -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() { diff --git a/panda/src/osxdisplay/osxGraphicsStateGuardian.cxx b/panda/src/osxdisplay/osxGraphicsStateGuardian.cxx index 693bb1af02..1b693800f4 100644 --- a/panda/src/osxdisplay/osxGraphicsStateGuardian.cxx +++ b/panda/src/osxdisplay/osxGraphicsStateGuardian.cxx @@ -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