From 58f6f61c4eedd3c0828f0200f481153906d8270a Mon Sep 17 00:00:00 2001 From: Jordan Maxwell Date: Sun, 6 Jan 2019 13:56:18 -0600 Subject: [PATCH 001/144] README: Updated resolution of panda logo [skip ci] Closes #514 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a9de69e51b..a5422499d8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Build Status](https://travis-ci.org/panda3d/panda3d.svg?branch=master)](https://travis-ci.org/panda3d/panda3d) - + Panda3D ======= From 294dc5fc40742adf8ef29df1d48f137f65551845 Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Sun, 6 Jan 2019 16:10:34 +1000 Subject: [PATCH 002/144] leveleditor: Fixed relative import for start - Relative imports only work within modules, not in scripts (as LevelEditorStart is expected to be called directly, not imported). --- direct/src/leveleditor/LevelEditorStart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/direct/src/leveleditor/LevelEditorStart.py b/direct/src/leveleditor/LevelEditorStart.py index 4ec577106c..bcb8800c94 100644 --- a/direct/src/leveleditor/LevelEditorStart.py +++ b/direct/src/leveleditor/LevelEditorStart.py @@ -1,4 +1,4 @@ -from . import LevelEditor +from direct.leveleditor import LevelEditor if __name__ == '__main__': base.le = LevelEditor.LevelEditor() From 4f548889a863677bac5271ff07b6c95393353a67 Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Sun, 6 Jan 2019 16:15:51 +1000 Subject: [PATCH 003/144] leveleditor: Use panda3d.core --- direct/src/leveleditor/ActionMgr.py | 2 +- direct/src/leveleditor/CurveEditor.py | 2 +- direct/src/leveleditor/FileMgr.py | 2 +- direct/src/leveleditor/LayerEditorUI.py | 2 +- direct/src/leveleditor/LevelEditorUIBase.py | 2 +- direct/src/leveleditor/ObjectMgrBase.py | 2 +- direct/src/leveleditor/ObjectPropertyUI.py | 2 +- direct/src/leveleditor/ProtoObjsUI.py | 2 +- direct/src/leveleditor/ProtoPaletteUI.py | 2 +- direct/src/leveleditor/SceneGraphUIBase.py | 2 +- direct/src/leveleditor/testData.py | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/direct/src/leveleditor/ActionMgr.py b/direct/src/leveleditor/ActionMgr.py index 29d9ba3742..dcc5b7ff91 100755 --- a/direct/src/leveleditor/ActionMgr.py +++ b/direct/src/leveleditor/ActionMgr.py @@ -1,4 +1,4 @@ -from pandac.PandaModules import * +from panda3d.core import * from . import ObjectGlobals as OG class ActionMgr: diff --git a/direct/src/leveleditor/CurveEditor.py b/direct/src/leveleditor/CurveEditor.py index b1acc04525..57cc119378 100755 --- a/direct/src/leveleditor/CurveEditor.py +++ b/direct/src/leveleditor/CurveEditor.py @@ -2,7 +2,7 @@ This is the module for curve edit """ -from pandac.PandaModules import * +from panda3d.core import * from direct.wxwidgets.WxPandaShell import * from direct.showbase.DirectObject import * from direct.directtools.DirectSelection import SelectionRay diff --git a/direct/src/leveleditor/FileMgr.py b/direct/src/leveleditor/FileMgr.py index a0b00d1a04..1f11dc7133 100755 --- a/direct/src/leveleditor/FileMgr.py +++ b/direct/src/leveleditor/FileMgr.py @@ -11,7 +11,7 @@ class FileMgr: def saveToFile(self, fileName): try: f = open(fileName, 'w') - f.write("from pandac.PandaModules import *\n") + f.write("from panda3d.core import *\n") f.write("\nif hasattr(base, 'le'):\n") f.write(" objectMgr = base.le.objectMgr\n") f.write(" animMgr = base.le.animMgr\n") diff --git a/direct/src/leveleditor/LayerEditorUI.py b/direct/src/leveleditor/LayerEditorUI.py index d77f8779bb..e30dc343b4 100644 --- a/direct/src/leveleditor/LayerEditorUI.py +++ b/direct/src/leveleditor/LayerEditorUI.py @@ -2,7 +2,7 @@ Defines Layer UI """ import wx -from pandac.PandaModules import * +from panda3d.core import * from . import ObjectGlobals as OG diff --git a/direct/src/leveleditor/LevelEditorUIBase.py b/direct/src/leveleditor/LevelEditorUIBase.py index f457f838d6..159ec58f36 100755 --- a/direct/src/leveleditor/LevelEditorUIBase.py +++ b/direct/src/leveleditor/LevelEditorUIBase.py @@ -2,7 +2,7 @@ ## import os ## from wx.lib.agw import fourwaysplitter as FWS -from pandac.PandaModules import * +from panda3d.core import * from direct.wxwidgets.WxPandaShell import * from direct.directtools.DirectSelection import SelectionRay diff --git a/direct/src/leveleditor/ObjectMgrBase.py b/direct/src/leveleditor/ObjectMgrBase.py index 3a65d6a998..2e9cc2a17c 100755 --- a/direct/src/leveleditor/ObjectMgrBase.py +++ b/direct/src/leveleditor/ObjectMgrBase.py @@ -6,7 +6,7 @@ import os, time, copy from direct.task import Task from direct.actor.Actor import Actor -from pandac.PandaModules import * +from panda3d.core import * from .ActionMgr import * from . import ObjectGlobals as OG diff --git a/direct/src/leveleditor/ObjectPropertyUI.py b/direct/src/leveleditor/ObjectPropertyUI.py index 08adb8b784..4b76cb8879 100755 --- a/direct/src/leveleditor/ObjectPropertyUI.py +++ b/direct/src/leveleditor/ObjectPropertyUI.py @@ -9,7 +9,7 @@ from wx.lib.embeddedimage import PyEmbeddedImage from wx.lib.scrolledpanel import ScrolledPanel from wx.lib.agw.cubecolourdialog import * from direct.wxwidgets.WxSlider import * -from pandac.PandaModules import * +from panda3d.core import * from . import ObjectGlobals as OG from . import AnimGlobals as AG diff --git a/direct/src/leveleditor/ProtoObjsUI.py b/direct/src/leveleditor/ProtoObjsUI.py index 63222e3a2d..a4e09af9f3 100755 --- a/direct/src/leveleditor/ProtoObjsUI.py +++ b/direct/src/leveleditor/ProtoObjsUI.py @@ -4,7 +4,7 @@ Defines ProtoObjs List UI import wx import os -from pandac.PandaModules import * +from panda3d.core import * from .ProtoObjs import * class ProtoDropTarget(wx.PyDropTarget): diff --git a/direct/src/leveleditor/ProtoPaletteUI.py b/direct/src/leveleditor/ProtoPaletteUI.py index d9f047b55f..51d26e8474 100755 --- a/direct/src/leveleditor/ProtoPaletteUI.py +++ b/direct/src/leveleditor/ProtoPaletteUI.py @@ -3,7 +3,7 @@ Defines ProtoPalette tree UI """ import wx import os -from pandac.PandaModules import * +from panda3d.core import * from .PaletteTreeCtrl import * class UniversalDropTarget(wx.PyDropTarget): diff --git a/direct/src/leveleditor/SceneGraphUIBase.py b/direct/src/leveleditor/SceneGraphUIBase.py index c98cf8505c..74afd6a585 100755 --- a/direct/src/leveleditor/SceneGraphUIBase.py +++ b/direct/src/leveleditor/SceneGraphUIBase.py @@ -2,7 +2,7 @@ Defines Scene Graph tree UI Base """ import wx -from pandac.PandaModules import * +from panda3d.core import * from .ActionMgr import * from . import ObjectGlobals as OG diff --git a/direct/src/leveleditor/testData.py b/direct/src/leveleditor/testData.py index 28d4a04d1c..d35c01b103 100755 --- a/direct/src/leveleditor/testData.py +++ b/direct/src/leveleditor/testData.py @@ -1,4 +1,4 @@ -from pandac.PandaModules import * +from panda3d.core import * if hasattr(base, 'le'): objectMgr = base.le.objectMgr From 8cf28e8d2c222a6fb952ffba7cb28aa4d41078fa Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Sun, 6 Jan 2019 17:30:31 +1000 Subject: [PATCH 004/144] wx: Fixed deprecation warnings/errors - Warnings/Errors associated with LevelEditor. --- direct/src/leveleditor/LevelEditor.py | 4 ++-- direct/src/leveleditor/LevelEditorBase.py | 4 ++-- direct/src/leveleditor/LevelEditorUIBase.py | 6 ++--- direct/src/leveleditor/ObjectPaletteUI.py | 2 +- direct/src/leveleditor/PaletteTreeCtrl.py | 4 ++-- direct/src/leveleditor/ProtoPaletteUI.py | 4 ++-- direct/src/leveleditor/SceneGraphUIBase.py | 26 ++++++++++----------- direct/src/showbase/ShowBase.py | 2 +- direct/src/wxwidgets/WxPandaShell.py | 8 +++---- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/direct/src/leveleditor/LevelEditor.py b/direct/src/leveleditor/LevelEditor.py index c1322c455d..36b1dd86e0 100644 --- a/direct/src/leveleditor/LevelEditor.py +++ b/direct/src/leveleditor/LevelEditor.py @@ -31,7 +31,7 @@ class LevelEditor(LevelEditorBase): # Populating uderlined data-structures self.ui = LevelEditorUI(self) - self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) + self.ui.SetCursor(wx.Cursor(wx.CURSOR_WAIT)) self.objectPalette.populate() self.protoPalette.populate() @@ -42,4 +42,4 @@ class LevelEditor(LevelEditorBase): # When you define your own LevelEditor class inheriting LevelEditorBase # you should call self.initialize() at the end of __init__() function self.initialize() - self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) + self.ui.SetCursor(wx.Cursor(wx.CURSOR_ARROW)) diff --git a/direct/src/leveleditor/LevelEditorBase.py b/direct/src/leveleditor/LevelEditorBase.py index ad351a7e39..16ff696744 100755 --- a/direct/src/leveleditor/LevelEditorBase.py +++ b/direct/src/leveleditor/LevelEditorBase.py @@ -305,7 +305,7 @@ class LevelEditorBase(DirectObject): if self.settingsFile is None: return - self.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) + self.ui.SetCursor(wx.Cursor(wx.CURSOR_WAIT)) try: f = open(self.settingsFile, 'r') configLines = f.readlines() @@ -342,7 +342,7 @@ class LevelEditorBase(DirectObject): self.ui.updateMenu() except: pass - self.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) + self.ui.SetCursor(wx.Cursor(wx.CURSOR_ARROW)) def convertMaya(self, modelname, callBack, obj=None, isAnim=False): if obj and isAnim: diff --git a/direct/src/leveleditor/LevelEditorUIBase.py b/direct/src/leveleditor/LevelEditorUIBase.py index 159ec58f36..33101dff22 100755 --- a/direct/src/leveleditor/LevelEditorUIBase.py +++ b/direct/src/leveleditor/LevelEditorUIBase.py @@ -478,7 +478,7 @@ class LevelEditorUIBase(WxPandaShell): self.editor.reset() def onOpen(self, evt=None): - dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", "*.py", wx.OPEN) + dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", "*.py", style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) if dialog.ShowModal() == wx.ID_OK: self.editor.load(dialog.GetPath()) self.editor.setTitleWithFilename(dialog.GetPath()) @@ -492,7 +492,7 @@ class LevelEditorUIBase(WxPandaShell): self.editor.save() def onSaveAs(self, evt): - dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", "*.py", wx.SAVE) + dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", "*.py", style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) result = True if dialog.ShowModal() == wx.ID_OK: self.editor.saveAs(dialog.GetPath()) @@ -503,7 +503,7 @@ class LevelEditorUIBase(WxPandaShell): return result def onExportToMaya(self, evt): - dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", "*.mb", wx.SAVE) + dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", "*.mb", style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) if dialog.ShowModal() == wx.ID_OK: self.editor.exportToMaya(dialog.GetPath()) dialog.Destroy() diff --git a/direct/src/leveleditor/ObjectPaletteUI.py b/direct/src/leveleditor/ObjectPaletteUI.py index bf84e3d492..ffd168a258 100755 --- a/direct/src/leveleditor/ObjectPaletteUI.py +++ b/direct/src/leveleditor/ObjectPaletteUI.py @@ -69,4 +69,4 @@ class ObjectPaletteUI(wx.Panel): return cmp(index1, index2) def getSelected(self): - return self.tree.GetItemPyData(self.tree.GetSelection()) + return self.tree.GetItemData(self.tree.GetSelection()) diff --git a/direct/src/leveleditor/PaletteTreeCtrl.py b/direct/src/leveleditor/PaletteTreeCtrl.py index c4a5d46fce..75c752f0fc 100644 --- a/direct/src/leveleditor/PaletteTreeCtrl.py +++ b/direct/src/leveleditor/PaletteTreeCtrl.py @@ -41,7 +41,7 @@ class PaletteTreeCtrl(wx.TreeCtrl): roots.append(key) for root in roots: newItem = self.AppendItem(parentItem, root) - self.SetItemPyData(newItem, root) + self.SetItemData(newItem, root) rootItems.append(newItem) itemKeys.remove(root) for rootItem in rootItems: @@ -108,7 +108,7 @@ class PaletteTreeCtrl(wx.TreeCtrl): item, cookie = self.GetFirstChild(parent) while item: itemName = self.GetItemText(item) - itemData = self.GetItemPyData(item) + itemData = self.GetItemData(item) newItem = self.AppendItem(newParent, itemName) self.SetItemPyData(newItem, itemData) diff --git a/direct/src/leveleditor/ProtoPaletteUI.py b/direct/src/leveleditor/ProtoPaletteUI.py index 51d26e8474..6736311821 100755 --- a/direct/src/leveleditor/ProtoPaletteUI.py +++ b/direct/src/leveleditor/ProtoPaletteUI.py @@ -6,10 +6,10 @@ import os from panda3d.core import * from .PaletteTreeCtrl import * -class UniversalDropTarget(wx.PyDropTarget): +class UniversalDropTarget(wx.DropTarget): """Implements drop target functionality to receive files, bitmaps and text""" def __init__(self, editor): - wx.PyDropTarget.__init__(self) + wx.DropTarget.__init__(self) self.editor = editor self.do = wx.DataObjectComposite() # the dataobject that gets filled with the appropriate data self.filedo = wx.FileDataObject() diff --git a/direct/src/leveleditor/SceneGraphUIBase.py b/direct/src/leveleditor/SceneGraphUIBase.py index 74afd6a585..66537fbbdf 100755 --- a/direct/src/leveleditor/SceneGraphUIBase.py +++ b/direct/src/leveleditor/SceneGraphUIBase.py @@ -26,7 +26,7 @@ class SceneGraphUIBase(wx.Panel): size=wx.DefaultSize, style=wx.TR_MULTIPLE|wx.TR_DEFAULT_STYLE, validator=wx.DefaultValidator, name="treeCtrl") self.root = self.tree.AddRoot('render') - self.tree.SetItemPyData(self.root, "render") + self.tree.SetItemData(self.root, "render") self.shouldShowPandaObjChildren = False @@ -61,7 +61,7 @@ class SceneGraphUIBase(wx.Panel): self.tree.Delete(item) def traversePandaObjects(self, parent, objNodePath): - itemId = self.tree.GetItemPyData(parent) + itemId = self.tree.GetItemData(parent) i = 0 for child in objNodePath.getChildren(): if child.hasTag('OBJRoot'): @@ -78,7 +78,7 @@ class SceneGraphUIBase(wx.Panel): def addPandaObjectChildren(self, parent): # first, find Panda Object's NodePath of the item - itemId = self.tree.GetItemPyData(parent) + itemId = self.tree.GetItemData(parent) if itemId == "render": return obj = self.editor.objectMgr.findObjectById(itemId) @@ -96,7 +96,7 @@ class SceneGraphUIBase(wx.Panel): def removePandaObjectChildren(self, parent): # first, find Panda Object's NodePath of the item - itemId = self.tree.GetItemPyData(parent) + itemId = self.tree.GetItemData(parent) if itemId == "render": return obj = self.editor.objectMgr.findObjectById(itemId) @@ -142,14 +142,14 @@ class SceneGraphUIBase(wx.Panel): def traverse(self, parent, itemId): # prevent from traversing into self - if itemId == self.tree.GetItemPyData(parent): + if itemId == self.tree.GetItemData(parent): return None # main loop - serching for an item with an itemId item, cookie = self.tree.GetFirstChild(parent) while item: # if the item was found - return it - if itemId == self.tree.GetItemPyData(item): + if itemId == self.tree.GetItemData(item): return item # the tem was not found - checking if it has children @@ -168,7 +168,7 @@ class SceneGraphUIBase(wx.Panel): item, cookie = self.tree.GetFirstChild(parent) while item: data = self.tree.GetItemText(item) - itemId = self.tree.GetItemPyData(item) + itemId = self.tree.GetItemData(item) newItem = self.tree.AppendItem(newParent, data) self.tree.SetItemPyData(newItem, itemId) @@ -186,13 +186,13 @@ class SceneGraphUIBase(wx.Panel): def reParent(self, oldParent, newParent, child): if newParent is None: newParent = self.root - itemId = self.tree.GetItemPyData(oldParent) + itemId = self.tree.GetItemData(oldParent) newItem = self.tree.AppendItem(newParent, child) self.tree.SetItemPyData(newItem, itemId) self.reParentTree(oldParent, newItem) obj = self.editor.objectMgr.findObjectById(itemId) - itemId = self.tree.GetItemPyData(newParent) + itemId = self.tree.GetItemData(newParent) if itemId != "render": newParentObj = self.editor.objectMgr.findObjectById(itemId) self.reParentData(newParentObj[OG.OBJ_NP], obj[OG.OBJ_NP]) @@ -207,7 +207,7 @@ class SceneGraphUIBase(wx.Panel): self.addPandaObjectChildren(newpParent) def isChildOrGrandChild(self, parent, child): - childId = self.tree.GetItemPyData(child) + childId = self.tree.GetItemData(child) return self.traverse(parent, childId) def changeHierarchy(self, data, x, y): @@ -226,7 +226,7 @@ class SceneGraphUIBase(wx.Panel): return # undo function setup... - action = ActionChangeHierarchy(self.editor, self.tree.GetItemPyData(self.tree.GetItemParent(item)), self.tree.GetItemPyData(item), self.tree.GetItemPyData(dragToItem), data) + action = ActionChangeHierarchy(self.editor, self.tree.GetItemData(self.tree.GetItemParent(item)), self.tree.GetItemData(item), self.tree.GetItemData(dragToItem), data) self.editor.actionMgr.push(action) action() @@ -283,7 +283,7 @@ class SceneGraphUIBase(wx.Panel): def onSelected(self, event): item = event.GetItem(); if item: - itemId = self.tree.GetItemPyData(item) + itemId = self.tree.GetItemData(item) if itemId: obj = self.editor.objectMgr.findObjectById(itemId); if obj: @@ -313,7 +313,7 @@ class SceneGraphUIBase(wx.Panel): if not item.IsOk(): return self.currItem = item - itemId = self.tree.GetItemPyData(item) + itemId = self.tree.GetItemData(item) if not itemId: return self.currObj = self.editor.objectMgr.findObjectById(itemId); diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index bff3b4652c..2d32d2b338 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -2926,7 +2926,7 @@ class ShowBase(DirectObject.DirectObject): if not self.wxApp: # Create a new base.wxApp. - self.wxApp = wx.PySimpleApp(redirect = False) + self.wxApp = wx.App(redirect = False) if ConfigVariableBool('wx-main-loop', True): # Put wxPython in charge of the main loop. It really diff --git a/direct/src/wxwidgets/WxPandaShell.py b/direct/src/wxwidgets/WxPandaShell.py index cae5fb9332..d6a1793684 100755 --- a/direct/src/wxwidgets/WxPandaShell.py +++ b/direct/src/wxwidgets/WxPandaShell.py @@ -202,15 +202,15 @@ class WxPandaShell(WxAppShell): """A step in the WX event loop. You can either call this yourself or use as task.""" while self.evtLoop.Pending(): self.evtLoop.Dispatch() - self.wxApp.ProcessIdle() + self.evtLoop.ProcessIdle() if task != None: return task.cont def appInit(self): """Overridden from WxAppShell.py.""" # Create a new event loop (to overide default wxEventLoop) - self.evtLoop = wx.EventLoop() - self.oldLoop = wx.EventLoop.GetActive() - wx.EventLoop.SetActive(self.evtLoop) + self.evtLoop = wx.GUIEventLoop() + self.oldLoop = wx.GUIEventLoop.GetActive() + wx.GUIEventLoop.SetActive(self.evtLoop) taskMgr.add(self.wxStep, "evtLoopTask") def onViewChange(self, evt, viewIdx): From 441e1e3d6684dda006c5466c81405fb7e367d57e Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 7 Jan 2019 12:35:13 +0100 Subject: [PATCH 005/144] Bump version number on master to 1.11.0 --- dtool/PandaVersion.pp | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dtool/PandaVersion.pp b/dtool/PandaVersion.pp index f504aab0cd..6e931a149c 100644 --- a/dtool/PandaVersion.pp +++ b/dtool/PandaVersion.pp @@ -7,7 +7,7 @@ // place to put this. // Use spaces to separate the major, minor, and sequence numbers here. -#define PANDA_VERSION 1 10 1 +#define PANDA_VERSION 1 11 0 // This variable will be defined to false in the CVS repository, but // scripts that generate source tarballs and/or binary releases for diff --git a/setup.cfg b/setup.cfg index 8a1a50afe0..340e432e56 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = Panda3D -version = 1.10.1 +version = 1.11.0 url = https://www.panda3d.org/ description = Panda3D is a framework for 3D rendering and game development for Python and C++ programs. license = Modified BSD License From 193ae8a3a680408ade5fb3060b1e1782c0f761d5 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 7 Jan 2019 15:56:56 +0100 Subject: [PATCH 006/144] pgraph: take advantage of constant initialization for states maps SimpleHashMap has a constexpr default constructor, so there is no static init ordering issue that requires us to allocate the states maps on the heap and then to leak them. --- panda/src/display/graphicsStateGuardian.cxx | 4 +- panda/src/pgraph/renderAttrib.cxx | 58 ++++++------- panda/src/pgraph/renderAttrib.h | 2 +- panda/src/pgraph/renderAttribRegistry.cxx | 4 +- panda/src/pgraph/renderState.cxx | 90 ++++++++------------- panda/src/pgraph/renderState.h | 2 +- panda/src/pgraph/renderState_ext.cxx | 11 +-- panda/src/pgraph/transformState.cxx | 84 +++++++------------ panda/src/pgraph/transformState.h | 2 +- panda/src/pgraph/transformState_ext.cxx | 16 ++-- panda/src/pgraphnodes/shaderGenerator.cxx | 8 +- 11 files changed, 110 insertions(+), 171 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 93a3f36651..cce8083b19 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -301,9 +301,9 @@ GraphicsStateGuardian:: // Note that if uniquify-states is false, we can't iterate over all the // states, and some GSGs will linger. Let's hope this isn't a problem. LightReMutexHolder holder(*RenderState::_states_lock); - size_t size = RenderState::_states->get_num_entries(); + size_t size = RenderState::_states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const RenderState *state = RenderState::_states->get_key(si); + const RenderState *state = RenderState::_states.get_key(si); state->_mungers.remove(_id); state->_munged_states.remove(_id); } diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 9bac4e666a..362419ff65 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -21,7 +21,7 @@ using std::ostream; LightReMutex *RenderAttrib::_attribs_lock = nullptr; -RenderAttrib::Attribs *RenderAttrib::_attribs = nullptr; +RenderAttrib::Attribs RenderAttrib::_attribs; TypeHandle RenderAttrib::_type_handle; size_t RenderAttrib::_garbage_index = 0; @@ -33,7 +33,7 @@ PStatCollector RenderAttrib::_garbage_collect_pcollector("*:State Cache:Garbage */ RenderAttrib:: RenderAttrib() { - if (_attribs == nullptr) { + if (_attribs_lock == nullptr) { init_attribs(); } _saved_entry = -1; @@ -156,11 +156,7 @@ write(ostream &out, int indent_level) const { int RenderAttrib:: get_num_attribs() { LightReMutexHolder holder(*_attribs_lock); - - if (_attribs == nullptr) { - return 0; - } - return _attribs->get_num_entries(); + return _attribs.get_num_entries(); } /** @@ -172,10 +168,10 @@ void RenderAttrib:: list_attribs(ostream &out) { LightReMutexHolder holder(*_attribs_lock); - size_t size = _attribs->get_num_entries(); + size_t size = _attribs.get_num_entries(); out << size << " attribs:\n"; for (size_t si = 0; si < size; ++si) { - const RenderAttrib *attrib = _attribs->get_key(si); + const RenderAttrib *attrib = _attribs.get_key(si); attrib->write(out, 2); } } @@ -186,16 +182,16 @@ list_attribs(ostream &out) { */ int RenderAttrib:: garbage_collect() { - if (_attribs == nullptr || !garbage_collect_states) { + if (!garbage_collect_states) { return 0; } LightReMutexHolder holder(*_attribs_lock); PStatTimer timer(_garbage_collect_pcollector); - size_t orig_size = _attribs->get_num_entries(); + size_t orig_size = _attribs.get_num_entries(); #ifdef _DEBUG - nassertr(_attribs->validate(), 0); + nassertr(_attribs.validate(), 0); #endif // How many elements to process this pass? @@ -214,7 +210,7 @@ garbage_collect() { size_t stop_at_element = (si + num_this_pass) % size; do { - RenderAttrib *attrib = (RenderAttrib *)_attribs->get_key(si); + RenderAttrib *attrib = (RenderAttrib *)_attribs.get_key(si); if (attrib->get_ref_count() == 1) { // This attrib has recently been unreffed to 1 (the one we added when // we stored it in the cache). Now it's time to delete it. This is @@ -238,15 +234,15 @@ garbage_collect() { } while (si != stop_at_element); _garbage_index = si; - nassertr(_attribs->get_num_entries() == size, 0); + nassertr(_attribs.get_num_entries() == size, 0); #ifdef _DEBUG - nassertr(_attribs->validate(), 0); + nassertr(_attribs.validate(), 0); #endif // If we just cleaned up a lot of attribs, see if we can reduce the table in // size. This will help reduce iteration overhead in the future. - _attribs->consider_shrink_table(); + _attribs.consider_shrink_table(); return (int)orig_size - (int)size; } @@ -259,17 +255,17 @@ garbage_collect() { bool RenderAttrib:: validate_attribs() { LightReMutexHolder holder(*_attribs_lock); - if (_attribs->is_empty()) { + if (_attribs.is_empty()) { return true; } - if (!_attribs->validate()) { + if (!_attribs.validate()) { pgraph_cat.error() << "RenderAttrib::_attribs cache is invalid!\n"; - size_t size = _attribs->get_num_entries(); + size_t size = _attribs.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const RenderAttrib *attrib = _attribs->get_key(si); + const RenderAttrib *attrib = _attribs.get_key(si); //cerr << si << ": " << attrib << "\n"; attrib->write(std::cerr, 2); } @@ -277,16 +273,16 @@ validate_attribs() { return false; } - size_t size = _attribs->get_num_entries(); + size_t size = _attribs.get_num_entries(); size_t si = 0; nassertr(si < size, false); - nassertr(_attribs->get_key(si)->get_ref_count() >= 0, false); + nassertr(_attribs.get_key(si)->get_ref_count() >= 0, false); size_t snext = si; ++snext; while (snext < size) { - nassertr(_attribs->get_key(snext)->get_ref_count() >= 0, false); - const RenderAttrib *ssi = _attribs->get_key(si); - const RenderAttrib *ssnext = _attribs->get_key(snext); + nassertr(_attribs.get_key(snext)->get_ref_count() >= 0, false); + const RenderAttrib *ssi = _attribs.get_key(si); + const RenderAttrib *ssnext = _attribs.get_key(snext); int c = ssi->compare_to(*ssnext); int ci = ssnext->compare_to(*ssi); if ((ci < 0) != (c > 0) || @@ -356,19 +352,19 @@ return_unique(RenderAttrib *attrib) { LightReMutexHolder holder(*_attribs_lock); if (attrib->_saved_entry != -1) { - // This attrib is already in the cache. nassertr(_attribs->find(attrib) + // This attrib is already in the cache. nassertr(_attribs.find(attrib) // == attrib->_saved_entry, attrib); return attrib; } - int si = _attribs->find(attrib); + int si = _attribs.find(attrib); if (si != -1) { // There's an equivalent attrib already in the set. Return it. If this // is a newly created RenderAttrib, though, be sure to delete it. if (attrib->get_ref_count() == 0) { delete attrib; } - return _attribs->get_key(si); + return _attribs.get_key(si); } // Not already in the set; add it. @@ -378,7 +374,7 @@ return_unique(RenderAttrib *attrib) { // deleted while it's in it. attrib->ref(); } - si = _attribs->store(attrib, nullptr); + si = _attribs.store(attrib, nullptr); // Save the index and return the input attrib. attrib->_saved_entry = si; @@ -495,7 +491,7 @@ release_new() { if (_saved_entry != -1) { _saved_entry = -1; - nassertv_always(_attribs->remove(this)); + nassertv_always(_attribs.remove(this)); } } @@ -508,8 +504,6 @@ release_new() { */ void RenderAttrib:: init_attribs() { - _attribs = new Attribs; - // TODO: we should have a global Panda mutex to allow us to safely create // _attribs_lock without a startup race condition. For the meantime, this // is OK because we guarantee that this method is called at static init diff --git a/panda/src/pgraph/renderAttrib.h b/panda/src/pgraph/renderAttrib.h index 98b9de315c..15f090f43d 100644 --- a/panda/src/pgraph/renderAttrib.h +++ b/panda/src/pgraph/renderAttrib.h @@ -186,7 +186,7 @@ private: // This mutex protects _attribs. static LightReMutex *_attribs_lock; typedef SimpleHashMap > Attribs; - static Attribs *_attribs; + static Attribs _attribs; int _saved_entry; size_t _hash; diff --git a/panda/src/pgraph/renderAttribRegistry.cxx b/panda/src/pgraph/renderAttribRegistry.cxx index 7919d75799..d79c6484a5 100644 --- a/panda/src/pgraph/renderAttribRegistry.cxx +++ b/panda/src/pgraph/renderAttribRegistry.cxx @@ -91,9 +91,9 @@ register_slot(TypeHandle type_handle, int sort, RenderAttrib *default_attrib) { if (default_attrib->_saved_entry == -1) { // If this attribute was already registered, something odd is going on. - nassertr(RenderAttrib::_attribs->find(default_attrib) == -1, 0); + nassertr(RenderAttrib::_attribs.find(default_attrib) == -1, 0); default_attrib->_saved_entry = - RenderAttrib::_attribs->store(default_attrib, nullptr); + RenderAttrib::_attribs.store(default_attrib, nullptr); } // It effectively lives forever. Might as well make it official. diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index 5ce1527247..636e960a8c 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -39,7 +39,7 @@ using std::ostream; LightReMutex *RenderState::_states_lock = nullptr; -RenderState::States *RenderState::_states = nullptr; +RenderState::States RenderState::_states; const RenderState *RenderState::_empty_state = nullptr; UpdateSeq RenderState::_last_cycle_detect; size_t RenderState::_garbage_index = 0; @@ -68,7 +68,7 @@ RenderState() : _flags(0), _lock("RenderState") { - if (_states == nullptr) { + if (_states_lock == nullptr) { init_states(); } _saved_entry = -1; @@ -716,11 +716,8 @@ get_max_priority() { */ int RenderState:: get_num_states() { - if (_states == nullptr) { - return 0; - } LightReMutexHolder holder(*_states_lock); - return _states->get_num_entries(); + return _states.get_num_entries(); } /** @@ -738,9 +735,6 @@ get_num_states() { */ int RenderState:: get_num_unused_states() { - if (_states == nullptr) { - return 0; - } LightReMutexHolder holder(*_states_lock); // First, we need to count the number of times each RenderState object is @@ -748,9 +742,9 @@ get_num_unused_states() { typedef pmap StateCount; StateCount state_count; - size_t size = _states->get_num_entries(); + size_t size = _states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const RenderState *state = _states->get_key(si); + const RenderState *state = _states.get_key(si); size_t i; size_t cache_size = state->_composition_cache.get_num_entries(); @@ -821,13 +815,10 @@ get_num_unused_states() { */ int RenderState:: clear_cache() { - if (_states == nullptr) { - return 0; - } LightReMutexHolder holder(*_states_lock); PStatTimer timer(_cache_update_pcollector); - int orig_size = _states->get_num_entries(); + int orig_size = _states.get_num_entries(); // First, we need to copy the entire set of states to a temporary vector, // reference-counting each object. That way we can walk through the copy, @@ -838,9 +829,9 @@ clear_cache() { TempStates temp_states; temp_states.reserve(orig_size); - size_t size = _states->get_num_entries(); + size_t size = _states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const RenderState *state = _states->get_key(si); + const RenderState *state = _states.get_key(si); temp_states.push_back(state); } @@ -879,7 +870,7 @@ clear_cache() { // the various objects' caches will go away. } - int new_size = _states->get_num_entries(); + int new_size = _states.get_num_entries(); return orig_size - new_size; } @@ -895,14 +886,14 @@ int RenderState:: garbage_collect() { int num_attribs = RenderAttrib::garbage_collect(); - if (_states == nullptr || !garbage_collect_states) { + if (!garbage_collect_states) { return num_attribs; } LightReMutexHolder holder(*_states_lock); PStatTimer timer(_garbage_collect_pcollector); - size_t orig_size = _states->get_num_entries(); + size_t orig_size = _states.get_num_entries(); // How many elements to process this pass? size_t size = orig_size; @@ -922,7 +913,7 @@ garbage_collect() { size_t stop_at_element = (si + num_this_pass) % size; do { - RenderState *state = (RenderState *)_states->get_key(si); + RenderState *state = (RenderState *)_states.get_key(si); if (break_and_uniquify) { if (state->get_cache_ref_count() > 0 && state->get_ref_count() == state->get_cache_ref_count()) { @@ -959,15 +950,15 @@ garbage_collect() { } while (si != stop_at_element); _garbage_index = si; - nassertr(_states->get_num_entries() == size, 0); + nassertr(_states.get_num_entries() == size, 0); #ifdef _DEBUG - nassertr(_states->validate(), 0); + nassertr(_states.validate(), 0); #endif // If we just cleaned up a lot of states, see if we can reduce the table in // size. This will help reduce iteration overhead in the future. - _states->consider_shrink_table(); + _states.consider_shrink_table(); return (int)orig_size - (int)size + num_attribs; } @@ -980,9 +971,9 @@ void RenderState:: clear_munger_cache() { LightReMutexHolder holder(*_states_lock); - size_t size = _states->get_num_entries(); + size_t size = _states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - RenderState *state = (RenderState *)(_states->get_key(si)); + RenderState *state = (RenderState *)(_states.get_key(si)); state->_mungers.clear(); state->_munged_states.clear(); state->_last_mi = -1; @@ -1004,18 +995,15 @@ clear_munger_cache() { */ void RenderState:: list_cycles(ostream &out) { - if (_states == nullptr) { - return; - } LightReMutexHolder holder(*_states_lock); typedef pset VisitedStates; VisitedStates visited; CompositionCycleDesc cycle_desc; - size_t size = _states->get_num_entries(); + size_t size = _states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const RenderState *state = _states->get_key(si); + const RenderState *state = _states.get_key(si); bool inserted = visited.insert(state).second; if (inserted) { @@ -1081,16 +1069,12 @@ list_cycles(ostream &out) { */ void RenderState:: list_states(ostream &out) { - if (_states == nullptr) { - out << "0 states:\n"; - return; - } LightReMutexHolder holder(*_states_lock); - size_t size = _states->get_num_entries(); + size_t size = _states.get_num_entries(); out << size << " states:\n"; for (size_t si = 0; si < size; ++si) { - const RenderState *state = _states->get_key(si); + const RenderState *state = _states.get_key(si); state->write(out, 2); } } @@ -1103,33 +1087,29 @@ list_states(ostream &out) { */ bool RenderState:: validate_states() { - if (_states == nullptr) { - return true; - } - PStatTimer timer(_state_validate_pcollector); LightReMutexHolder holder(*_states_lock); - if (_states->is_empty()) { + if (_states.is_empty()) { return true; } - if (!_states->validate()) { + if (!_states.validate()) { pgraph_cat.error() << "RenderState::_states cache is invalid!\n"; return false; } - size_t size = _states->get_num_entries(); + size_t size = _states.get_num_entries(); size_t si = 0; nassertr(si < size, false); - nassertr(_states->get_key(si)->get_ref_count() >= 0, false); + nassertr(_states.get_key(si)->get_ref_count() >= 0, false); size_t snext = si; ++snext; while (snext < size) { - nassertr(_states->get_key(snext)->get_ref_count() >= 0, false); - const RenderState *ssi = _states->get_key(si); - const RenderState *ssnext = _states->get_key(snext); + nassertr(_states.get_key(snext)->get_ref_count() >= 0, false); + const RenderState *ssi = _states.get_key(si); + const RenderState *ssnext = _states.get_key(snext); int c = ssi->compare_to(*ssnext); int ci = ssnext->compare_to(*ssi); if ((ci < 0) != (c > 0) || @@ -1299,7 +1279,7 @@ return_unique(RenderState *state) { LightReMutexHolder holder(*_states_lock); if (state->_saved_entry != -1) { - // This state is already in the cache. nassertr(_states->find(state) == + // This state is already in the cache. nassertr(_states.find(state) == // state->_saved_entry, pt_state); return state; } @@ -1318,7 +1298,7 @@ return_unique(RenderState *state) { } } - int si = _states->find(state); + int si = _states.find(state); if (si != -1) { // There's an equivalent state already in the set. Return it. The state // that was passed may be newly created and therefore may not be @@ -1326,7 +1306,7 @@ return_unique(RenderState *state) { if (state->get_ref_count() == 0) { delete state; } - return _states->get_key(si); + return _states.get_key(si); } // Not already in the set; add it. @@ -1336,7 +1316,7 @@ return_unique(RenderState *state) { // deleted while it's in it. state->cache_ref(); } - si = _states->store(state, nullptr); + si = _states.store(state, nullptr); // Save the index and return the input state. state->_saved_entry = si; @@ -1612,7 +1592,7 @@ release_new() { if (_saved_entry != -1) { _saved_entry = -1; - nassertv_always(_states->remove(this)); + nassertv_always(_states.remove(this)); } } @@ -1849,8 +1829,6 @@ update_pstats(int old_referenced_bits, int new_referenced_bits) { */ void RenderState:: init_states() { - _states = new States; - // TODO: we should have a global Panda mutex to allow us to safely create // _states_lock without a startup race condition. For the meantime, this is // OK because we guarantee that this method is called at static init time, @@ -1863,7 +1841,7 @@ init_states() { // is declared globally, and lives forever. RenderState *state = new RenderState; state->local_object(); - state->_saved_entry = _states->store(state, nullptr); + state->_saved_entry = _states.store(state, nullptr); _empty_state = state; } diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index c9e3719082..db4ebbd634 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -232,7 +232,7 @@ private: // _invert_composition_cache. static LightReMutex *_states_lock; typedef SimpleHashMap > States; - static States *_states; + static States _states; static const RenderState *_empty_state; // This iterator records the entry corresponding to this RenderState object diff --git a/panda/src/pgraph/renderState_ext.cxx b/panda/src/pgraph/renderState_ext.cxx index 2b7e3a4791..d0afb0718a 100644 --- a/panda/src/pgraph/renderState_ext.cxx +++ b/panda/src/pgraph/renderState_ext.cxx @@ -118,18 +118,15 @@ get_invert_composition_cache() const { PyObject *Extension:: get_states() { extern struct Dtool_PyTypedObject Dtool_RenderState; - if (RenderState::_states == nullptr) { - return PyList_New(0); - } LightReMutexHolder holder(*RenderState::_states_lock); - size_t num_states = RenderState::_states->get_num_entries(); + size_t num_states = RenderState::_states.get_num_entries(); PyObject *list = PyList_New(num_states); size_t i = 0; - size_t size = RenderState::_states->get_num_entries(); + size_t size = RenderState::_states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const RenderState *state = RenderState::_states->get_key(si); + const RenderState *state = RenderState::_states.get_key(si); state->ref(); PyObject *a = DTool_CreatePyInstanceTyped((void *)state, Dtool_RenderState, @@ -142,6 +139,4 @@ get_states() { return list; } - - #endif // HAVE_PYTHON diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index fc8b3de606..63adeb375d 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -27,7 +27,7 @@ using std::ostream; LightReMutex *TransformState::_states_lock = nullptr; -TransformState::States *TransformState::_states = nullptr; +TransformState::States TransformState::_states; CPT(TransformState) TransformState::_identity_state; CPT(TransformState) TransformState::_invalid_state; UpdateSeq TransformState::_last_cycle_detect; @@ -57,7 +57,7 @@ TypeHandle TransformState::_type_handle; */ TransformState:: TransformState() : _lock("TransformState") { - if (_states == nullptr) { + if (_states_lock == nullptr) { init_states(); } _saved_entry = -1; @@ -988,11 +988,8 @@ write_composition_cache(ostream &out, int indent_level) const { */ int TransformState:: get_num_states() { - if (_states == nullptr) { - return 0; - } LightReMutexHolder holder(*_states_lock); - return _states->get_num_entries(); + return _states.get_num_entries(); } /** @@ -1010,9 +1007,6 @@ get_num_states() { */ int TransformState:: get_num_unused_states() { - if (_states == nullptr) { - return 0; - } LightReMutexHolder holder(*_states_lock); // First, we need to count the number of times each TransformState object is @@ -1021,9 +1015,9 @@ get_num_unused_states() { typedef pmap StateCount; StateCount state_count; - size_t size = _states->get_num_entries(); + size_t size = _states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const TransformState *state = _states->get_key(si); + const TransformState *state = _states.get_key(si); size_t i; size_t cache_size = state->_composition_cache.get_num_entries(); @@ -1095,13 +1089,10 @@ get_num_unused_states() { */ int TransformState:: clear_cache() { - if (_states == nullptr) { - return 0; - } LightReMutexHolder holder(*_states_lock); PStatTimer timer(_cache_update_pcollector); - int orig_size = _states->get_num_entries(); + int orig_size = _states.get_num_entries(); // First, we need to copy the entire set of states to a temporary vector, // reference-counting each object. That way we can walk through the copy, @@ -1112,9 +1103,9 @@ clear_cache() { TempStates temp_states; temp_states.reserve(orig_size); - size_t size = _states->get_num_entries(); + size_t size = _states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const TransformState *state = _states->get_key(si); + const TransformState *state = _states.get_key(si); temp_states.push_back(state); } @@ -1153,7 +1144,7 @@ clear_cache() { // the various objects' caches will go away. } - int new_size = _states->get_num_entries(); + int new_size = _states.get_num_entries(); return orig_size - new_size; } @@ -1165,14 +1156,14 @@ clear_cache() { */ int TransformState:: garbage_collect() { - if (_states == nullptr || !garbage_collect_states) { + if (!garbage_collect_states) { return 0; } LightReMutexHolder holder(*_states_lock); PStatTimer timer(_garbage_collect_pcollector); - size_t orig_size = _states->get_num_entries(); + size_t orig_size = _states.get_num_entries(); // How many elements to process this pass? size_t size = orig_size; @@ -1192,7 +1183,7 @@ garbage_collect() { size_t stop_at_element = (si + num_this_pass) % size; do { - TransformState *state = (TransformState *)_states->get_key(si); + TransformState *state = (TransformState *)_states.get_key(si); if (break_and_uniquify) { if (state->get_cache_ref_count() > 0 && state->get_ref_count() == state->get_cache_ref_count()) { @@ -1229,15 +1220,15 @@ garbage_collect() { } while (si != stop_at_element); _garbage_index = si; - nassertr(_states->get_num_entries() == size, 0); + nassertr(_states.get_num_entries() == size, 0); #ifdef _DEBUG - nassertr(_states->validate(), 0); + nassertr(_states.validate(), 0); #endif // If we just cleaned up a lot of states, see if we can reduce the table in // size. This will help reduce iteration overhead in the future. - _states->consider_shrink_table(); + _states.consider_shrink_table(); return (int)orig_size - (int)size; } @@ -1257,18 +1248,15 @@ garbage_collect() { */ void TransformState:: list_cycles(ostream &out) { - if (_states == nullptr) { - return; - } LightReMutexHolder holder(*_states_lock); typedef pset VisitedStates; VisitedStates visited; CompositionCycleDesc cycle_desc; - size_t size = _states->get_num_entries(); + size_t size = _states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const TransformState *state = _states->get_key(si); + const TransformState *state = _states.get_key(si); bool inserted = visited.insert(state).second; if (inserted) { @@ -1334,16 +1322,12 @@ list_cycles(ostream &out) { */ void TransformState:: list_states(ostream &out) { - if (_states == nullptr) { - out << "0 states:\n"; - return; - } LightReMutexHolder holder(*_states_lock); - size_t size = _states->get_num_entries(); + size_t size = _states.get_num_entries(); out << size << " states:\n"; for (size_t si = 0; si < size; ++si) { - const TransformState *state = _states->get_key(si); + const TransformState *state = _states.get_key(si); state->write(out, 2); } } @@ -1356,36 +1340,32 @@ list_states(ostream &out) { */ bool TransformState:: validate_states() { - if (_states == nullptr) { - return true; - } - PStatTimer timer(_transform_validate_pcollector); LightReMutexHolder holder(*_states_lock); - if (_states->is_empty()) { + if (_states.is_empty()) { return true; } - if (!_states->validate()) { + if (!_states.validate()) { pgraph_cat.error() << "TransformState::_states cache is invalid!\n"; return false; } - size_t size = _states->get_num_entries(); + size_t size = _states.get_num_entries(); size_t si = 0; nassertr(si < size, false); - nassertr(_states->get_key(si)->get_ref_count() >= 0, false); + nassertr(_states.get_key(si)->get_ref_count() >= 0, false); size_t snext = si; ++snext; while (snext < size) { - nassertr(_states->get_key(snext)->get_ref_count() >= 0, false); - const TransformState *ssi = _states->get_key(si); + nassertr(_states.get_key(snext)->get_ref_count() >= 0, false); + const TransformState *ssi = _states.get_key(si); if (!ssi->validate_composition_cache()) { return false; } - const TransformState *ssnext = _states->get_key(snext); + const TransformState *ssnext = _states.get_key(snext); bool c = (*ssi) == (*ssnext); bool ci = (*ssnext) == (*ssi); if (c != ci) { @@ -1415,8 +1395,6 @@ validate_states() { */ void TransformState:: init_states() { - _states = new States; - ConfigVariableBool uniquify_matrix ("uniquify-matrix", true, PRC_DESC("Set this true to look up arbitrary 4x4 transform matrices in " @@ -1483,7 +1461,7 @@ return_unique(TransformState *state) { LightReMutexHolder holder(*_states_lock); if (state->_saved_entry != -1) { - // This state is already in the cache. nassertr(_states->find(state) == + // This state is already in the cache. nassertr(_states.find(state) == // state->_saved_entry, state); return state; } @@ -1492,10 +1470,10 @@ return_unique(TransformState *state) { // of this function if no one else uses it. CPT(TransformState) pt_state = state; - int si = _states->find(state); + int si = _states.find(state); if (si != -1) { // There's an equivalent state already in the set. Return it. - return _states->get_key(si); + return _states.get_key(si); } // Not already in the set; add it. @@ -1505,7 +1483,7 @@ return_unique(TransformState *state) { // deleted while it's in it. state->cache_ref(); } - si = _states->store(state, nullptr); + si = _states.store(state, nullptr); // Save the index and return the input state. state->_saved_entry = si; @@ -1893,7 +1871,7 @@ release_new() { if (_saved_entry != -1) { _saved_entry = -1; - nassertv_always(_states->remove(this)); + nassertv_always(_states.remove(this)); } } diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index 75b4fedb0e..370517de9c 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -253,7 +253,7 @@ private: // _invert_composition_cache. static LightReMutex *_states_lock; typedef SimpleHashMap > States; - static States *_states; + static States _states; static CPT(TransformState) _identity_state; static CPT(TransformState) _invalid_state; diff --git a/panda/src/pgraph/transformState_ext.cxx b/panda/src/pgraph/transformState_ext.cxx index 08a47b92cd..10b629ddff 100644 --- a/panda/src/pgraph/transformState_ext.cxx +++ b/panda/src/pgraph/transformState_ext.cxx @@ -132,18 +132,15 @@ get_invert_composition_cache() const { PyObject *Extension:: get_states() { extern struct Dtool_PyTypedObject Dtool_TransformState; - if (TransformState::_states == nullptr) { - return PyList_New(0); - } LightReMutexHolder holder(*TransformState::_states_lock); - size_t num_states = TransformState::_states->get_num_entries(); + size_t num_states = TransformState::_states.get_num_entries(); PyObject *list = PyList_New(num_states); size_t i = 0; - size_t size = TransformState::_states->get_num_entries(); + size_t size = TransformState::_states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const TransformState *state = TransformState::_states->get_key(si); + const TransformState *state = TransformState::_states.get_key(si); state->ref(); PyObject *a = DTool_CreatePyInstanceTyped((void *)state, Dtool_TransformState, @@ -163,15 +160,12 @@ get_states() { PyObject *Extension:: get_unused_states() { extern struct Dtool_PyTypedObject Dtool_TransformState; - if (TransformState::_states == nullptr) { - return PyList_New(0); - } LightReMutexHolder holder(*TransformState::_states_lock); PyObject *list = PyList_New(0); - size_t size = TransformState::_states->get_num_entries(); + size_t size = TransformState::_states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const TransformState *state = TransformState::_states->get_key(si); + const TransformState *state = TransformState::_states.get_key(si); if (state->get_cache_ref_count() == state->get_ref_count()) { state->ref(); PyObject *a = diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index 16a7483478..1a10a79e3b 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -580,9 +580,9 @@ rehash_generated_shaders() { // With uniquify-states turned on, we can actually go through all the states // and check whether their generated shader is still OK. - size_t size = RenderState::_states->get_num_entries(); + size_t size = RenderState::_states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const RenderState *state = RenderState::_states->get_key(si); + const RenderState *state = RenderState::_states.get_key(si); if (state->_generated_shader != nullptr) { ShaderKey key; @@ -619,9 +619,9 @@ void ShaderGenerator:: clear_generated_shaders() { LightReMutexHolder holder(*RenderState::_states_lock); - size_t size = RenderState::_states->get_num_entries(); + size_t size = RenderState::_states.get_num_entries(); for (size_t si = 0; si < size; ++si) { - const RenderState *state = RenderState::_states->get_key(si); + const RenderState *state = RenderState::_states.get_key(si); state->_generated_shader.clear(); } From 84df25cfe3d83669ccf1548b35de7205e27d6362 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 00:49:14 +0100 Subject: [PATCH 007/144] glgsg: fix sRGB support in multisample FBOs --- panda/src/glstuff/glGraphicsBuffer_src.cxx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index ebb038de7a..f6eb2c3919 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -1162,12 +1162,6 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLuint gl_format = GL_RGBA; #ifndef OPENGLES switch (slot) { - case RTP_aux_rgba_0: - case RTP_aux_rgba_1: - case RTP_aux_rgba_2: - case RTP_aux_rgba_3: - gl_format = GL_RGBA; - break; case RTP_aux_hrgba_0: case RTP_aux_hrgba_1: case RTP_aux_hrgba_2: @@ -1180,8 +1174,16 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, case RTP_aux_float_3: gl_format = GL_RGBA32F_ARB; break; + case RTP_aux_rgba_0: + case RTP_aux_rgba_1: + case RTP_aux_rgba_2: + case RTP_aux_rgba_3: default: - gl_format = GL_RGBA; + if (_fb_properties.get_srgb_color()) { + gl_format = GL_SRGB8_ALPHA8; + } else { + gl_format = GL_RGBA; + } break; } #endif From e215ff29286c071a46347df9f27ae97b2e9dbef1 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 19:20:45 +0100 Subject: [PATCH 008/144] makepackage: fix error building macOS package for Python 3.x only --- makepanda/makepackage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py index daf0877544..ed20117d10 100755 --- a/makepanda/makepackage.py +++ b/makepanda/makepackage.py @@ -473,7 +473,7 @@ def MakeInstallerOSX(version, runtime=False, python_versions=[], **kwargs): dmg_name = "Panda3D-" + version if len(python_versions) == 1 and not python_versions[0]["version"].startswith("2."): - dmg_name += "-py" + pyver + dmg_name += "-py" + python_versions[0]["version"] dmg_name += ".dmg" if (os.path.isfile(dmg_name)): oscmd("rm -f %s" % dmg_name) From 7262f16ed8ab49806c7fbb123a1d0de569f88cb7 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 19:23:43 +0100 Subject: [PATCH 009/144] tkwidgets: fix missing import from Valuator module Fixes #519 --- direct/src/tkwidgets/Valuator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/direct/src/tkwidgets/Valuator.py b/direct/src/tkwidgets/Valuator.py index 8b88d98680..39e0c8d73f 100644 --- a/direct/src/tkwidgets/Valuator.py +++ b/direct/src/tkwidgets/Valuator.py @@ -7,6 +7,7 @@ from direct.showbase.TkGlobal import * from . import WidgetPropertiesDialog import Pmw from direct.directtools.DirectUtil import getTkColorString +from panda3d.core import Vec4 if sys.version_info >= (3, 0): from tkinter.colorchooser import askcolor From e64a342a9fd2ee16e17f3534662afd9dd21c2819 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 20:09:18 +0100 Subject: [PATCH 010/144] task: fix error awaiting already scheduled task To reproduce this issue, try `await taskMgr.add(Task.pause(1.0))` --- panda/src/event/pythonTask.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/panda/src/event/pythonTask.cxx b/panda/src/event/pythonTask.cxx index 554e1368e7..86200802a9 100644 --- a/panda/src/event/pythonTask.cxx +++ b/panda/src/event/pythonTask.cxx @@ -598,7 +598,9 @@ do_python_task() { // directly instead of having to do: // await taskMgr.add(Task.pause(1.0)) AsyncTask *task = (AsyncTask *)fut; - _manager->add(task); + if (!task->is_alive()) { + _manager->add(task); + } } if (fut->add_waiting_task(this)) { if (task_cat.is_debug()) { From d1845530aa2844d415b0b9f3ad9fc81398ab6d55 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 22:12:02 +0100 Subject: [PATCH 011/144] task: fix mutex recursion when task awaiting other task ends --- panda/src/event/asyncTaskChain.cxx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/panda/src/event/asyncTaskChain.cxx b/panda/src/event/asyncTaskChain.cxx index 34e458691e..1d511bce45 100644 --- a/panda/src/event/asyncTaskChain.cxx +++ b/panda/src/event/asyncTaskChain.cxx @@ -788,18 +788,17 @@ cleanup_task(AsyncTask *task, bool upon_death, bool clean_exit) { _manager->remove_task_by_name(task); - if (upon_death && task->set_future_state(clean_exit ? AsyncFuture::FS_finished - : AsyncFuture::FS_cancelled)) { - task->notify_done(clean_exit); - } - - task->_manager = nullptr; - if (upon_death) { _manager->_lock.unlock(); + if (task->set_future_state(clean_exit ? AsyncFuture::FS_finished + : AsyncFuture::FS_cancelled)) { + task->notify_done(clean_exit); + } task->upon_death(_manager, clean_exit); _manager->_lock.lock(); } + + task->_manager = nullptr; } /** From 649372d333ff78c1f6b1a5321e6ce4d3e854bdd4 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 22:13:16 +0100 Subject: [PATCH 012/144] Loader: work around Python 3.7 await headache caused by PEP 479 Generators can no longer raise StopIteration, and we are supposed to use "return" instead. But, return with value inside generator is a syntax error in Python 2. Fixes #513 --- direct/src/showbase/Loader.py | 62 ++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/direct/src/showbase/Loader.py b/direct/src/showbase/Loader.py index 924b396616..270b537078 100644 --- a/direct/src/showbase/Loader.py +++ b/direct/src/showbase/Loader.py @@ -27,6 +27,42 @@ class Loader(DirectObject): # This indicates that this class behaves like a Future. _asyncio_future_blocking = False + class ResultAwaiter(object): + """Reinvents generators because of PEP 479, sigh. See #513.""" + + __slots__ = 'requestList', 'index' + + def __init__(self, requestList): + self.requestList = requestList + self.index = 0 + + def __await__(self): + return self + + def __anext__(self): + if self.index >= len(self.requestList): + raise StopAsyncIteration + return self + + def __iter__(self): + return self + + def __next__(self): + i = self.index + request = self.requestList[i] + if not request.done(): + return request + + self.index = i + 1 + + result = request.result() + if isinstance(result, PandaNode): + result = NodePath(result) + + exc = StopIteration(result) + exc.value = result + raise exc + def __init__(self, loader, numObjects, gotList, callback, extraArgs): self._loader = loader self.objects = [None] * numObjects @@ -81,16 +117,14 @@ class Loader(DirectObject): def __await__(self): """ Returns a generator that raises StopIteration when the loading is complete. This allows this class to be used with 'await'.""" + if self.requests: self._asyncio_future_blocking = True - yield self - # This should be a simple return, but older versions of Python - # don't allow return statements with arguments. - result = self.result() - exc = StopIteration(result) - exc.value = result - raise exc + if self.gotList: + return self.ResultAwaiter([self]) + else: + return self.ResultAwaiter(self.requestList) def __aiter__(self): """ This allows using `async for` to iterate asynchronously over @@ -100,19 +134,7 @@ class Loader(DirectObject): requestList = self.requestList assert requestList is not None, "Request was cancelled." - class AsyncIter: - index = 0 - def __anext__(self): - if self.index < len(requestList): - i = self.index - self.index = i + 1 - return requestList[i] - else: - raise StopAsyncIteration - - iter = AsyncIter() - iter.objects = self.objects - return iter + return self.ResultAwaiter(requestList) # special methods def __init__(self, base): From 886d44d15d191c2b0bf1dea4ed15bce517fbc47d Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 22:39:05 +0100 Subject: [PATCH 013/144] glgsg: fix multisampling for floating-point framebuffers --- panda/src/glstuff/glGraphicsBuffer_src.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index f6eb2c3919..bdeb26345f 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -1181,6 +1181,8 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, default: if (_fb_properties.get_srgb_color()) { gl_format = GL_SRGB8_ALPHA8; + } else if (_fb_properties.get_float_color()) { + gl_format = GL_RGBA32F_ARB; } else { gl_format = GL_RGBA; } From 60a944e783c3a78bffaf41b2364beeb8c8a36516 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 22:39:36 +0100 Subject: [PATCH 014/144] glgsg: fix shader inputs not being updated in esoteric case Specifically, this happens if you have a custom ShaderGenerator that assigns shader inputs via the ShaderAttrib. If two objects then both have the auto-shader turned on, and the shader generator generates ShaderAttribs with the same shaders but different inputs, the inputs will not be updated properly for one of the objects. --- panda/src/glstuff/glShaderContext_src.cxx | 9 +++++---- panda/src/glstuff/glShaderContext_src.h | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index ae7a845efc..a2ac21cbc4 100644 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -2042,10 +2042,6 @@ set_state_and_transform(const RenderState *target_rs, target_rs->get_attrib(MaterialAttrib::get_class_slot())) { altered |= Shader::SSD_material; } - if (state_rs->get_attrib(ShaderAttrib::get_class_slot()) != - target_rs->get_attrib(ShaderAttrib::get_class_slot())) { - altered |= Shader::SSD_shaderinputs; - } if (state_rs->get_attrib(FogAttrib::get_class_slot()) != target_rs->get_attrib(FogAttrib::get_class_slot())) { altered |= Shader::SSD_fog; @@ -2069,6 +2065,11 @@ set_state_and_transform(const RenderState *target_rs, _state_rs = target_rs; } + if (_shader_attrib.get_orig() != _glgsg->_target_shader || _shader_attrib.was_deleted()) { + altered |= Shader::SSD_shaderinputs; + _shader_attrib = _glgsg->_target_shader; + } + // Is this the first time this shader is used this frame? int frame_number = ClockObject::get_global_clock()->get_frame_count(); if (frame_number != _frame_number) { diff --git a/panda/src/glstuff/glShaderContext_src.h b/panda/src/glstuff/glShaderContext_src.h index 91130e9224..0ccb99fe90 100644 --- a/panda/src/glstuff/glShaderContext_src.h +++ b/panda/src/glstuff/glShaderContext_src.h @@ -76,6 +76,7 @@ private: CPT(TransformState) _camera_transform; CPT(TransformState) _projection_transform; CPT(ColorAttrib) _color_attrib; + WCPT(ShaderAttrib) _shader_attrib; /* * struct ParamContext { CPT(InternalName) _name; GLint _location; GLsizei From 7d398c9aba6e5f83115292db36e3c2e3439feb3c Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 22:46:34 +0100 Subject: [PATCH 015/144] flt: prevent zero-byte allocation --- pandatool/src/flt/fltRecordReader.cxx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pandatool/src/flt/fltRecordReader.cxx b/pandatool/src/flt/fltRecordReader.cxx index c999001d64..4f1ccfe1bb 100644 --- a/pandatool/src/flt/fltRecordReader.cxx +++ b/pandatool/src/flt/fltRecordReader.cxx @@ -131,12 +131,13 @@ advance(bool ok_eof) { // And now read the full record based on the length. int length = _next_record_length - header_size; - char *buffer = new char[length]; if (length > 0) { - _in.read(buffer, length); + vector_uchar data((size_t)length); + _in.read((char *)&data[0], length); + _datagram = Datagram(std::move(data)); + } else { + _datagram = Datagram(); } - _datagram = Datagram(buffer, length); - delete[] buffer; if (_in.eof()) { _state = S_eof; @@ -162,12 +163,12 @@ advance(bool ok_eof) { _record_length += _next_record_length; length = _next_record_length - header_size; - buffer = new char[length]; if (length > 0) { + char *buffer = new char[length]; _in.read(buffer, length); + _datagram.append_data(buffer, length); + delete[] buffer; } - _datagram.append_data(buffer, length); - delete[] buffer; if (_in.eof()) { _state = S_eof; From 3e5f2cf67215adf36d4b7fc26098f84483f9e967 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 22:52:18 +0100 Subject: [PATCH 016/144] flt: fix crash due to macOS libc++ bug in istream::eof() Apparently eof() in older versions of libc++ returns true if the last character has just been read, whereas the proper behavior is only to return true when attempting to read past the end of the stream. Since failbit is reliably set in all cases when reading past the length of the stream, we should only trust the result of eof() if fail() also returns true. --- pandatool/src/flt/fltRecordReader.cxx | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pandatool/src/flt/fltRecordReader.cxx b/pandatool/src/flt/fltRecordReader.cxx index 4f1ccfe1bb..eb3ba94840 100644 --- a/pandatool/src/flt/fltRecordReader.cxx +++ b/pandatool/src/flt/fltRecordReader.cxx @@ -139,13 +139,13 @@ advance(bool ok_eof) { _datagram = Datagram(); } - if (_in.eof()) { - _state = S_eof; - assert(!flt_error_abort); - return FE_end_of_file; - } - if (_in.fail()) { + if (_in.eof()) { + _state = S_eof; + assert(!flt_error_abort); + return FE_end_of_file; + } + _state = S_error; assert(!flt_error_abort); return FE_read_error; @@ -170,13 +170,13 @@ advance(bool ok_eof) { delete[] buffer; } - if (_in.eof()) { - _state = S_eof; - assert(!flt_error_abort); - return FE_end_of_file; - } - if (_in.fail()) { + if (_in.eof()) { + _state = S_eof; + assert(!flt_error_abort); + return FE_end_of_file; + } + _state = S_error; assert(!flt_error_abort); return FE_read_error; @@ -222,11 +222,11 @@ read_next_header() { char bytes[header_size]; _in.read(bytes, header_size); - if (_in.eof()) { - _next_error = FE_end_of_file; - return; - - } else if (_in.fail()) { + if (_in.fail()) { + if (_in.eof()) { + _next_error = FE_end_of_file; + return; + } _next_error = FE_read_error; return; } From 3ccfbfaba722d068bce535225979c13ad0e19fd1 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 22:56:40 +0100 Subject: [PATCH 017/144] putil: fix hang reading bam due to macOS libc++ bug in istream::eof() Apparently eof() in older versions of libc++ returns true if the last character has just been read, whereas the proper behavior is only to return true when attempting to read past the end of the stream. Since failbit is reliably set in all cases when reading past the length of the stream, we should only trust the result of eof() if fail() also returns true. --- panda/src/putil/datagramInputFile.cxx | 28 ++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/panda/src/putil/datagramInputFile.cxx b/panda/src/putil/datagramInputFile.cxx index c4802ceed2..600f699635 100644 --- a/panda/src/putil/datagramInputFile.cxx +++ b/panda/src/putil/datagramInputFile.cxx @@ -109,7 +109,7 @@ read_header(std::string &header, size_t num_bytes) { nassertr(buffer != nullptr, false); _in->read(buffer, num_bytes); - if (_in->fail() || _in->eof()) { + if (_in->fail()) { return false; } @@ -130,7 +130,7 @@ get_datagram(Datagram &data) { // First, get the size of the upcoming datagram. StreamReader reader(_in, false); uint32_t num_bytes_32 = reader.get_uint32(); - if (_in->fail() || _in->eof()) { + if (_in->fail()) { return false; } @@ -141,16 +141,29 @@ get_datagram(Datagram &data) { return true; } + if (_in->eof()) { + return false; + } + size_t num_bytes = (size_t)num_bytes_32; if (num_bytes_32 == (uint32_t)-1) { // Another special case for a value larger than 32 bits. uint64_t num_bytes_64 = reader.get_uint64(); - if (_in->fail() || _in->eof()) { + if (_in->fail()) { _error = true; return false; } + if (num_bytes_64 == 0) { + data.clear(); + return false; + } + + if (_in->eof()) { + return false; + } + num_bytes = (size_t)num_bytes_64; // Make sure we have a reasonable datagram size for putting into memory. @@ -169,6 +182,11 @@ get_datagram(Datagram &data) { while (bytes_read < num_bytes) { size_t bytes_left = num_bytes - bytes_read; + if (_in->eof()) { + _error = true; + return false; + } + // Hold up a second - datagrams >4MB are pretty large by bam/network // standards. Let's take it 4MB at a time just in case the length is // corrupt, so we don't allocate potentially a few GBs of RAM only to @@ -180,7 +198,7 @@ get_datagram(Datagram &data) { unsigned char *ptr = &buffer.p()[bytes_read]; _in->read((char *)ptr, (streamsize)bytes_left); - if (_in->fail() || _in->eof()) { + if (_in->fail()) { _error = true; return false; } @@ -210,7 +228,7 @@ save_datagram(SubfileInfo &info) { // First, get the size of the upcoming datagram. StreamReader reader(_in, false); size_t num_bytes_32 = reader.get_uint32(); - if (_in->fail() || _in->eof()) { + if (_in->fail() || (_in->eof() && num_bytes_32 > 0)) { return false; } From de9b9590de60bc7526b8a29528c7d82fa2a23e71 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 23:34:44 +0100 Subject: [PATCH 018/144] tests: add test for HashVal reading from hex stream --- tests/express/test_hashval.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/express/test_hashval.py diff --git a/tests/express/test_hashval.py b/tests/express/test_hashval.py new file mode 100644 index 0000000000..b2334e24d9 --- /dev/null +++ b/tests/express/test_hashval.py @@ -0,0 +1,9 @@ +from panda3d import core +import random + + +def test_hashval_hex(): + hex = '%032x' % random.getrandbits(32 * 4) + val = core.HashVal() + val.input_hex(core.StringStream(hex.encode('ascii'))) + assert str(val) == hex.lower() From 58acc25ea2fb04f6a7018d12235349f7d13e5127 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 16:58:46 -0500 Subject: [PATCH 019/144] Remove old Carbon-based OS X graphics back-end This back-end has been deprecated by Apple for a while, and has not been used in Panda. As we will no longer be supporting 32-bit macs going forward, and the Carbon windowing API is not available for 64-bit mac, there's no point in keeping it. --- makepanda/makepanda.py | 38 +- makepanda/makepanda.vcproj | 19 - panda/metalibs/pandagl/pandagl.cxx | 11 +- panda/src/osxdisplay/config_osxdisplay.cxx | 87 - panda/src/osxdisplay/config_osxdisplay.h | 29 - panda/src/osxdisplay/osxGraphicsBuffer.cxx | 200 -- panda/src/osxdisplay/osxGraphicsBuffer.h | 69 - panda/src/osxdisplay/osxGraphicsPipe.cxx | 451 ---- panda/src/osxdisplay/osxGraphicsPipe.h | 73 - .../osxdisplay/osxGraphicsStateGuardian.cxx | 459 ---- .../src/osxdisplay/osxGraphicsStateGuardian.h | 94 - panda/src/osxdisplay/osxGraphicsWindow.I | 24 - panda/src/osxdisplay/osxGraphicsWindow.h | 145 -- panda/src/osxdisplay/osxGraphicsWindow.mm | 2019 ----------------- .../osxdisplay/p3osxdisplay_composite1.cxx | 4 - panda/src/osxdisplay/resize_box.rgb | Bin 1683 -> 0 bytes panda/src/osxdisplay/resize_box.rgb.c | 167 -- panda/src/pandabase/pandasymbols.h | 9 - panda/src/tinydisplay/config_tinydisplay.cxx | 34 - panda/src/tinydisplay/config_tinydisplay.h | 4 - .../tinydisplay/p3tinydisplay_composite2.cxx | 6 - panda/src/tinydisplay/tinyOsxGraphicsPipe.I | 12 - panda/src/tinydisplay/tinyOsxGraphicsPipe.cxx | 252 -- panda/src/tinydisplay/tinyOsxGraphicsPipe.h | 79 - panda/src/tinydisplay/tinyOsxGraphicsWindow.I | 20 - panda/src/tinydisplay/tinyOsxGraphicsWindow.h | 146 -- .../src/tinydisplay/tinyOsxGraphicsWindow.mm | 1734 -------------- 27 files changed, 6 insertions(+), 6179 deletions(-) delete mode 100644 panda/src/osxdisplay/config_osxdisplay.cxx delete mode 100644 panda/src/osxdisplay/config_osxdisplay.h delete mode 100644 panda/src/osxdisplay/osxGraphicsBuffer.cxx delete mode 100644 panda/src/osxdisplay/osxGraphicsBuffer.h delete mode 100644 panda/src/osxdisplay/osxGraphicsPipe.cxx delete mode 100644 panda/src/osxdisplay/osxGraphicsPipe.h delete mode 100644 panda/src/osxdisplay/osxGraphicsStateGuardian.cxx delete mode 100644 panda/src/osxdisplay/osxGraphicsStateGuardian.h delete mode 100644 panda/src/osxdisplay/osxGraphicsWindow.I delete mode 100644 panda/src/osxdisplay/osxGraphicsWindow.h delete mode 100644 panda/src/osxdisplay/osxGraphicsWindow.mm delete mode 100644 panda/src/osxdisplay/p3osxdisplay_composite1.cxx delete mode 100644 panda/src/osxdisplay/resize_box.rgb delete mode 100644 panda/src/osxdisplay/resize_box.rgb.c delete mode 100644 panda/src/tinydisplay/tinyOsxGraphicsPipe.I delete mode 100644 panda/src/tinydisplay/tinyOsxGraphicsPipe.cxx delete mode 100644 panda/src/tinydisplay/tinyOsxGraphicsPipe.h delete mode 100644 panda/src/tinydisplay/tinyOsxGraphicsWindow.I delete mode 100644 panda/src/tinydisplay/tinyOsxGraphicsWindow.h delete mode 100644 panda/src/tinydisplay/tinyOsxGraphicsWindow.mm diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index dc0bded1f8..b39c09dce4 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -94,7 +94,7 @@ PkgListSet(["PYTHON", "DIRECT", # Python support "GTK2", # GTK2 is used for PStats on Unix "MFC", "WX", "FLTK", # Used for web plug-in only "ROCKET", # GUI libraries - "CARBON", "COCOA", # Mac OS X toolkits + "COCOA", # Mac OS X toolkits "X11", # Unix platform support "PANDATOOL", "PVIEW", "DEPLOYTOOLS", # Toolchain "SKEL", # Example SKEL project @@ -178,6 +178,7 @@ def parseopts(args): # Options for which to display a deprecation warning. removedopts = [ "use-touchinput", "no-touchinput", "no-awesomium", "no-directscripts", + "no-carbon", ] # All recognized options. @@ -622,7 +623,6 @@ if (COMPILER == "MSVC"): PkgDisable("GLES") PkgDisable("GLES2") PkgDisable("EGL") - PkgDisable("CARBON") PkgDisable("COCOA") DefSymbol("FLEX", "YY_NO_UNISTD_H") if (PkgSkip("PYTHON")==0): @@ -875,14 +875,10 @@ if (COMPILER == "MSVC"): if (COMPILER=="GCC"): if GetTarget() != "darwin": - PkgDisable("CARBON") PkgDisable("COCOA") elif RUNTIME: # We don't support Cocoa in the runtime yet. PkgDisable("COCOA") - if 'x86_64' in OSX_ARCHS: - # 64-bits OS X doesn't have Carbon. - PkgDisable("CARBON") #if (PkgSkip("PYTHON")==0): # IncDirectory("PYTHON", SDK["PYTHON"]) @@ -2450,7 +2446,6 @@ DTOOL_CONFIG=[ ("HAVE_ARTOOLKIT", 'UNDEF', 'UNDEF'), ("HAVE_DIRECTCAM", 'UNDEF', 'UNDEF'), ("HAVE_SQUISH", 'UNDEF', 'UNDEF'), - ("HAVE_CARBON", 'UNDEF', 'UNDEF'), ("HAVE_COCOA", 'UNDEF', 'UNDEF'), ("HAVE_OPENAL_FRAMEWORK", 'UNDEF', 'UNDEF'), ("HAVE_ROCKET_PYTHON", '1', '1'), @@ -3354,7 +3349,6 @@ if not PkgSkip("EGG"): if GetTarget() == 'windows': CopyAllHeaders('panda/src/wgldisplay') elif GetTarget() == 'darwin': - CopyAllHeaders('panda/src/osxdisplay') CopyAllHeaders('panda/src/cocoadisplay') elif GetTarget() == 'android': CopyAllHeaders('panda/src/android') @@ -4875,26 +4869,6 @@ if (GetTarget() == 'darwin' and PkgSkip("COCOA")==0 and PkgSkip("GL")==0 and not TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS) TargetAdd('libpandagl.dll', opts=['MODULE', 'GL', 'NVIDIACG', 'CGGL', 'COCOA', 'CARBON']) -# -# DIRECTORY: panda/src/osxdisplay/ -# - -elif (GetTarget() == 'darwin' and PkgSkip("CARBON")==0 and PkgSkip("GL")==0 and not RUNTIME): - OPTS=['DIR:panda/src/osxdisplay', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG', 'CGGL'] - TargetAdd('p3osxdisplay_composite1.obj', opts=OPTS, input='p3osxdisplay_composite1.cxx') - TargetAdd('p3osxdisplay_osxGraphicsWindow.obj', opts=OPTS, input='osxGraphicsWindow.mm') - OPTS=['DIR:panda/metalibs/pandagl', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG', 'CGGL'] - TargetAdd('pandagl_pandagl.obj', opts=OPTS, input='pandagl.cxx') - TargetAdd('libpandagl.dll', input='pandagl_pandagl.obj') - TargetAdd('libpandagl.dll', input='p3glgsg_config_glgsg.obj') - TargetAdd('libpandagl.dll', input='p3glgsg_glgsg.obj') - TargetAdd('libpandagl.dll', input='p3osxdisplay_composite1.obj') - TargetAdd('libpandagl.dll', input='p3osxdisplay_osxGraphicsWindow.obj') - if (PkgSkip('PANDAFX')==0): - TargetAdd('libpandagl.dll', input='libpandafx.dll') - TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libpandagl.dll', opts=['MODULE', 'GL', 'NVIDIACG', 'CGGL', 'CARBON', 'AGL', 'COCOA']) - # # DIRECTORY: panda/src/wgldisplay/ # @@ -5247,14 +5221,10 @@ if (not RUNTIME and (GetTarget() in ('windows', 'darwin') or PkgSkip("X11")==0) TargetAdd('p3tinydisplay_ztriangle_3.obj', opts=OPTS, input='ztriangle_3.cxx') TargetAdd('p3tinydisplay_ztriangle_4.obj', opts=OPTS, input='ztriangle_4.cxx') TargetAdd('p3tinydisplay_ztriangle_table.obj', opts=OPTS, input='ztriangle_table.cxx') - if GetTarget() == 'darwin': - TargetAdd('p3tinydisplay_tinyOsxGraphicsWindow.obj', opts=OPTS, input='tinyOsxGraphicsWindow.mm') - TargetAdd('libp3tinydisplay.dll', input='p3tinydisplay_tinyOsxGraphicsWindow.obj') - TargetAdd('libp3tinydisplay.dll', opts=['CARBON', 'AGL', 'COCOA']) - elif GetTarget() == 'windows': + if GetTarget() == 'windows': TargetAdd('libp3tinydisplay.dll', input='libp3windisplay.dll') TargetAdd('libp3tinydisplay.dll', opts=['WINIMM', 'WINGDI', 'WINKERNEL', 'WINOLDNAMES', 'WINUSER', 'WINMM']) - else: + elif GetTarget() != 'darwin': TargetAdd('libp3tinydisplay.dll', input='p3x11display_composite1.obj') TargetAdd('libp3tinydisplay.dll', opts=['X11']) TargetAdd('libp3tinydisplay.dll', input='p3tinydisplay_composite1.obj') diff --git a/makepanda/makepanda.vcproj b/makepanda/makepanda.vcproj index 03324fb60e..9ac171d7a2 100644 --- a/makepanda/makepanda.vcproj +++ b/makepanda/makepanda.vcproj @@ -1619,7 +1619,6 @@ - @@ -1627,13 +1626,11 @@ - - @@ -1675,12 +1672,10 @@ - - @@ -3506,20 +3501,6 @@ - - - - - - - - - - - - - - diff --git a/panda/metalibs/pandagl/pandagl.cxx b/panda/metalibs/pandagl/pandagl.cxx index 0e33961c9f..7775d2e7b4 100644 --- a/panda/metalibs/pandagl/pandagl.cxx +++ b/panda/metalibs/pandagl/pandagl.cxx @@ -16,9 +16,6 @@ #if defined(HAVE_COCOA) #include "config_cocoadisplay.h" #include "cocoaGraphicsPipe.h" -#elif defined(HAVE_CARBON) -#include "config_osxdisplay.h" -#include "osxGraphicsPipe.h" #endif #ifdef HAVE_GLX @@ -26,8 +23,8 @@ #include "glxGraphicsPipe.h" #endif -#if !defined(HAVE_WGL) && !defined(HAVE_COCOA) && !defined(HAVE_CARBON) && !defined(HAVE_GLX) -#error One of HAVE_WGL, HAVE_COCOA, HAVE_CARBON or HAVE_GLX must be defined when compiling pandagl! +#if !defined(HAVE_WGL) && !defined(HAVE_COCOA) && !defined(HAVE_GLX) +#error One of HAVE_WGL, HAVE_COCOA or HAVE_GLX must be defined when compiling pandagl! #endif /** @@ -46,8 +43,6 @@ init_libpandagl() { #if defined(HAVE_COCOA) init_libcocoadisplay(); -#elif defined(HAVE_CARBON) - init_libosxdisplay(); #endif #ifdef IS_LINUX @@ -67,8 +62,6 @@ get_pipe_type_pandagl() { #if defined(HAVE_COCOA) return CocoaGraphicsPipe::get_class_type().get_index(); -#elif defined(HAVE_CARBON) - return osxGraphicsPipe::get_class_type().get_index(); #endif #ifdef HAVE_GLX diff --git a/panda/src/osxdisplay/config_osxdisplay.cxx b/panda/src/osxdisplay/config_osxdisplay.cxx deleted file mode 100644 index 0ebc9454bd..0000000000 --- a/panda/src/osxdisplay/config_osxdisplay.cxx +++ /dev/null @@ -1,87 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_osxdisplay.cxx - */ - -#include "config_osxdisplay.h" -#include "osxGraphicsBuffer.h" -#include "osxGraphicsPipe.h" -#include "osxGraphicsStateGuardian.h" -#include "osxGraphicsWindow.h" - -#include "graphicsPipeSelection.h" -#include "dconfig.h" -#include "pandaSystem.h" - - -#if !defined(CPPPARSER) && !defined(LINK_ALL_STATIC) && !defined(BUILDING_PANDA_OSXDISPLAY) - #error Buildsystem error: BUILDING_PANDA_OSXDISPLAY not defined -#endif - -Configure(config_osxdisplay); - -NotifyCategoryDef(osxdisplay, "display"); - -ConfigureFn(config_osxdisplay) { - init_libosxdisplay(); -} - -ConfigVariableBool show_resize_box -("show-resize-box", true, - PRC_DESC("When this variable is true, then resizable OSX Panda windows will " - "be rendered with a resize control in the lower-right corner. " - "This is specially handled by Panda, since otherwise the 3-d " - "window would completely hide any resize control drawn by the " - "OS. Set this variable false to allow this control to be hidden.")); - -ConfigVariableBool osx_support_gl_buffer -("osx-support-gl-buffer", true, - PRC_DESC("Set this true to support use of GLBuffers on OSX. When true, there is a risk of " - "a program crash due to buggy driver support for GLBuffers. " - "If this is false, offscreen buffers will be created as " - "AGLPbuffers, which are less powerful, and appear to have their " - "own set of problems.")); - -ConfigVariableBool osx_disable_event_loop -("osx-disable-event-loop", false, - PRC_DESC("Set this true to disable the window event loop for the Panda " - "windows. This makes sense only in a publish environment where " - "the window event loop is already handled by another part of the " - "app.")); - -ConfigVariableInt osx_mouse_wheel_scale -("osx-mouse-wheel-scale", 1, - PRC_DESC("Specify the number of units to spin the Mac mouse wheel to " - "represent a single wheel_up or wheel_down message.")); - -/** - * Initializes the library. This must be called at least once before any of - * the functions or classes in this library can be used. Normally it will be - * called by the static initializers and need not be called explicitly, but - * special cases exist. - */ -void -init_libosxdisplay() { - static bool initialized = false; - if (initialized) { - return; - } - initialized = true; - - osxGraphicsBuffer::init_type(); - osxGraphicsPipe::init_type(); - osxGraphicsWindow::init_type(); - osxGraphicsStateGuardian::init_type(); - - GraphicsPipeSelection *selection = GraphicsPipeSelection::get_global_ptr(); - selection->add_pipe_type(osxGraphicsPipe::get_class_type(), osxGraphicsPipe::pipe_constructor); - - PandaSystem *ps = PandaSystem::get_global_ptr(); - ps->set_system_tag("OpenGL", "window_system", "OSX"); -} diff --git a/panda/src/osxdisplay/config_osxdisplay.h b/panda/src/osxdisplay/config_osxdisplay.h deleted file mode 100644 index 5eadc80a7e..0000000000 --- a/panda/src/osxdisplay/config_osxdisplay.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_osxdisplay.h - */ - -#ifndef __CONFIG_OSXDISPLAY_H__ -#define __CONFIG_OSXDISPLAY_H__ - -#include "pandabase.h" -#include "notifyCategoryProxy.h" -#include "configVariableBool.h" -#include "configVariableInt.h" - -NotifyCategoryDecl( osxdisplay , EXPCL_PANDA_OSXDISPLAY, EXPTP_PANDA_OSXDISPLAY); - -extern EXPCL_PANDA_OSXDISPLAY void init_libosxdisplay(); - -extern ConfigVariableBool show_resize_box; -extern ConfigVariableBool osx_support_gl_buffer; -extern ConfigVariableBool osx_disable_event_loop; -extern ConfigVariableInt osx_mouse_wheel_scale; - -#endif /* __CONFIG_OSXDISPLAY_H__ */ diff --git a/panda/src/osxdisplay/osxGraphicsBuffer.cxx b/panda/src/osxdisplay/osxGraphicsBuffer.cxx deleted file mode 100644 index 03bfa46d79..0000000000 --- a/panda/src/osxdisplay/osxGraphicsBuffer.cxx +++ /dev/null @@ -1,200 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file osxGraphicsBuffer.cxx - */ - -#include "osxGraphicsBuffer.h" -#include "osxGraphicsStateGuardian.h" -#include "config_osxdisplay.h" -#include "osxGraphicsPipe.h" - -#include "graphicsPipe.h" -#include "glgsg.h" -#include "pStatTimer.h" - -TypeHandle osxGraphicsBuffer::_type_handle; - -/** - * - */ -osxGraphicsBuffer:: -osxGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe, - const std::string &name, - const FrameBufferProperties &fb_prop, - const WindowProperties &win_prop, - int flags, - GraphicsStateGuardian *gsg, - GraphicsOutput *host) : - GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host) -{ - osxGraphicsPipe *osx_pipe; - DCAST_INTO_V(osx_pipe, _pipe); - - _pbuffer = nullptr; - - // Since the pbuffer never gets flipped, we get screenshots from the same - // buffer we draw into. - _screenshot_buffer_type = _draw_buffer_type; -} - -/** - * - */ -osxGraphicsBuffer:: -~osxGraphicsBuffer() { - nassertv(_pbuffer == nullptr); -} - -/** - * 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 osxGraphicsBuffer:: -begin_frame(FrameMode mode, Thread *current_thread) { - PStatTimer timer(_make_current_pcollector); - - begin_frame_spam(mode); - if (_gsg == nullptr) { - return false; - } - nassertr(_pbuffer != nullptr, false); - - osxGraphicsStateGuardian *osxgsg; - DCAST_INTO_R(osxgsg, _gsg, false); - if (!aglSetPBuffer(osxgsg->get_context(), _pbuffer, 0, 0, 0)) { - report_agl_error("aglSetPBuffer"); - return false; - } - - if (!aglSetCurrentContext(osxgsg->get_context())) { - report_agl_error("aglSetCurrentContext"); - return false; - } - - osxgsg->reset_if_new(); - - if (mode == FM_render) { - CDLockedReader cdata(_cycler); - for (size_t i = 0; i != cdata->_textures.size(); ++i) { - const RenderTexture &rt = cdata->_textures[i]; - RenderTextureMode rtm_mode = rt._rtm_mode; - if (rtm_mode == RTM_bind_or_copy) { - CDWriter cdataw(_cycler, cdata, false); - nassertr(cdata->_textures.size() == cdataw->_textures.size(), false); - cdataw->_textures[i]._rtm_mode = RTM_copy_texture; - } - } - clear_cube_map_selection(); - } - _gsg->set_current_properties(&get_fb_properties()); - return _gsg->begin_frame(current_thread); -} - -/** - * This function will be called within the draw thread after rendering is - * completed for a given frame. It should do whatever finalization is - * required. - */ -void osxGraphicsBuffer:: -end_frame(FrameMode mode, Thread *current_thread) { - end_frame_spam(mode); - nassertv(_gsg != nullptr); - - if (mode == FM_render) { - copy_to_textures(); - } - - _gsg->end_frame(current_thread); - - if (mode == FM_render) { - trigger_flip(); - clear_cube_map_selection(); - } -} - -/** - * Closes the buffer right now. Called from the window thread. - */ -void osxGraphicsBuffer:: -close_buffer() { - if (_gsg != nullptr) { - // aglSetPBuffer(osxgsg->get_context(), _pbuffer, 0, 0, 0); - _gsg.clear(); - } - if (_pbuffer != nullptr) { - aglDestroyPBuffer(_pbuffer); - _pbuffer = nullptr; - } - _is_valid = false; -} - -/** - * Opens the buffer right now. Called from the window thread. Returns true - * if the buffer is successfully opened, or false if there was a problem. - */ -bool osxGraphicsBuffer:: -open_buffer() { - if (_gsg == 0) { - _gsg = new osxGraphicsStateGuardian(_engine, _pipe, nullptr); - } - - if (_pbuffer == nullptr) { - GLenum target = GL_TEXTURE_RECTANGLE_ARB; - if (_size[0] == Texture::up_to_power_2(_size[0]) && - _size[1] == Texture::up_to_power_2(_size[1])) { - // It's a power-of-two size, so we can use GL_TEXTURE_2D as the target. - // Dunno, but maybe this will be more likely to work on some hardware. - target = GL_TEXTURE_2D; - } - if (!aglCreatePBuffer(_size.get_x(), _size.get_y(), target, GL_RGBA, 0, &_pbuffer)) { - report_agl_error("aglCreatePBuffer"); - close_buffer(); - return false; - } - } - - osxGraphicsStateGuardian *osxgsg; - DCAST_INTO_R(osxgsg, _gsg, false); - - OSStatus stat = osxgsg->build_gl(false, true, _fb_properties); - if (stat != noErr) { - return false; - } - - if (!aglSetPBuffer(osxgsg->get_context(), _pbuffer, 0, 0, 0)) { - report_agl_error("aglSetPBuffer"); - close_buffer(); - return false; - } - - if (!aglSetCurrentContext(osxgsg->get_context())) { - report_agl_error("aglSetCurrentContext"); - return false; - } - - osxgsg->reset_if_new(); - if (!osxgsg->is_valid()) { - close_buffer(); - return false; - } - - /* - if (!osxgsg->get_fb_properties().verify_hardware_software - (_fb_properties, osxgsg->get_gl_renderer())) { - close_buffer(); - return false; - } - _fb_properties = osxgsg->get_fb_properties(); - */ - - _is_valid = true; - return true; -} diff --git a/panda/src/osxdisplay/osxGraphicsBuffer.h b/panda/src/osxdisplay/osxGraphicsBuffer.h deleted file mode 100644 index 7ea83d1c4c..0000000000 --- a/panda/src/osxdisplay/osxGraphicsBuffer.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file osxGraphicsBuffer.h - */ - -#ifndef OSXGRAPHICSBUFFER_H -#define OSXGRAPHICSBUFFER_H -#include - -#define __glext_h_ -#include -#include - -#include "pandabase.h" -#include "graphicsBuffer.h" -#include "glgsg.h" - -/** - * An offscreen buffer in the OSX environment. This creates an AGLPbuffer. - */ -class osxGraphicsBuffer : public GraphicsBuffer { -public: - osxGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe, - const std::string &name, - const FrameBufferProperties &fb_prop, - const WindowProperties &win_prop, - int flags, - GraphicsStateGuardian *gsg, - GraphicsOutput *host); - virtual ~osxGraphicsBuffer(); - - virtual bool begin_frame(FrameMode mode, Thread *current_thread); - virtual void end_frame(FrameMode mode, Thread *current_thread); - -protected: - virtual void close_buffer(); - virtual bool open_buffer(); - -private: - AGLPbuffer _pbuffer; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - GraphicsBuffer::init_type(); - register_type(_type_handle, "osxGraphicsBuffer", - GraphicsBuffer::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; - - friend class osxGraphicsStateGuardian; -}; - - -#endif diff --git a/panda/src/osxdisplay/osxGraphicsPipe.cxx b/panda/src/osxdisplay/osxGraphicsPipe.cxx deleted file mode 100644 index 5a56a6259d..0000000000 --- a/panda/src/osxdisplay/osxGraphicsPipe.cxx +++ /dev/null @@ -1,451 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file osxGraphicsPipe.cxx - */ - -#include "osxGraphicsPipe.h" -#include "config_osxdisplay.h" -#include "osxGraphicsWindow.h" -#include "osxGraphicsBuffer.h" -#include "osxGraphicsStateGuardian.h" -#include "pnmImage.h" -#include "subprocessWindow.h" -#include "nativeWindowHandle.h" -#include "displayInformation.h" -#import - -// some macros to make code more readable. -#define GetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth) -#define GetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight) -#define GetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate) -#define GetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel) -#define GetModeSafeForHardware(mode) GetDictionaryBoolean((mode), kCGDisplayModeIsSafeForHardware) -#define GetModeStretched(mode) GetDictionaryBoolean((mode), kCGDisplayModeIsStretched) -#define MAX_DISPLAYS 32 - -Boolean GetDictionaryBoolean(CFDictionaryRef theDict, const void* key) { - // get a boolean from the dictionary - Boolean value = false; - CFBooleanRef boolRef; - boolRef = (CFBooleanRef)CFDictionaryGetValue(theDict, key); - if (boolRef != nullptr) - value = CFBooleanGetValue(boolRef); - return value; -} - -long GetDictionaryLong(CFDictionaryRef theDict, const void* key) { - // get a long from the dictionary - long value = 0; - CFNumberRef numRef; - numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key); - if (numRef != nullptr) - CFNumberGetValue(numRef, kCFNumberLongType, &value); - return value; -} - -static CFComparisonResult CompareModes (const void *val1,const void *val2,void *context) { - // CFArray comparison callback for sorting display modes. -#pragma unused(context) - CFDictionaryRef thisMode = (CFDictionaryRef)val1; - CFDictionaryRef otherMode = (CFDictionaryRef)val2; - - long width = GetModeWidth(thisMode); - long otherWidth = GetModeWidth(otherMode); - long height = GetModeHeight(thisMode); - long otherHeight = GetModeHeight(otherMode); - - // sort modes in screen size order - if (width * height < otherWidth * otherHeight) { - return kCFCompareLessThan; - } else if (width * height > otherWidth * otherHeight) { - return kCFCompareGreaterThan; - } - - // sort modes by bits per pixel - long bitsPerPixel = GetModeBitsPerPixel(thisMode); - long otherBitsPerPixel = GetModeBitsPerPixel(otherMode); - if (bitsPerPixel < otherBitsPerPixel) { - return kCFCompareLessThan; - } else if (bitsPerPixel > otherBitsPerPixel) { - return kCFCompareGreaterThan; - } - - // sort modes by refresh rate. - long refreshRate = GetModeRefreshRate(thisMode); - long otherRefreshRate = GetModeRefreshRate(otherMode); - if (refreshRate < otherRefreshRate) { - return kCFCompareLessThan; - } else if (refreshRate > otherRefreshRate) { - return kCFCompareGreaterThan; - } - - return kCFCompareEqualTo; -} - -CFArrayRef GSCGDisplayAvailableModesUsefulForOpenGL(CGDirectDisplayID display) { - // get a list of all possible display modes for this system. - CFArrayRef availableModes = CGDisplayAvailableModes(display); - unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes); - - // creat mutable array to hold the display modes we are interested int. - CFMutableArrayRef usefulModes = CFArrayCreateMutable(kCFAllocatorDefault, numberOfAvailableModes, nullptr); - - // get the current bits per pixel. - long currentModeBitsPerPixel = GetModeBitsPerPixel(CGDisplayCurrentMode(display)); - - unsigned int i; - for (i= 0; i refreshRate) { - skipped = true; - break; - } - } - } - // this is a useful mode so add it to the array. - if (!replaced && !skipped) { - CFArrayAppendValue(usefulModes, mode); - } - } - // now sort the useful mode array, using the comparison callback. - CFArraySortValues( usefulModes, - CFRangeMake(0, CFArrayGetCount(usefulModes)), - (CFComparatorFunction) CompareModes, nullptr); - // return the CFArray of the useful display modes. - return usefulModes; -} - -TypeHandle osxGraphicsPipe::_type_handle; - -/** - * - */ -osxGraphicsPipe:: -osxGraphicsPipe() { - CGRect display_bounds = CGDisplayBounds(kCGDirectMainDisplay); - _display_width = CGRectGetWidth(display_bounds); - _display_height = CGRectGetHeight(display_bounds); - - CGDirectDisplayID display, displayArray[MAX_DISPLAYS] ; - CGDisplayCount numDisplays; - CFDictionaryRef displayMode; - CFArrayRef displayModeArray; - int number, i; - CGGetActiveDisplayList (MAX_DISPLAYS, displayArray, &numDisplays); - display = displayArray [numDisplays - 1]; - displayModeArray = GSCGDisplayAvailableModesUsefulForOpenGL( display ); - number = CFArrayGetCount( displayModeArray ); - DisplayMode *displays = new DisplayMode[ number ]; - for(i = 0; i < number; i++) { - displayMode = (CFDictionaryRef) CFArrayGetValueAtIndex (displayModeArray, i); - _display_information -> _total_display_modes++; - displays[i].width = (signed int)GetModeWidth (displayMode); - displays[i].height = (signed int)GetModeHeight (displayMode); - displays[i].bits_per_pixel = (signed int)GetModeBitsPerPixel (displayMode); - displays[i].refresh_rate = (signed int)GetModeRefreshRate (displayMode); - } - _display_information -> _display_mode_array = displays; -} - -/** - * - */ -osxGraphicsPipe:: -~osxGraphicsPipe() { -} - -/** - * Returns the name of the rendering interface associated with this - * GraphicsPipe. This is used to present to the user to allow him/her to - * choose between several possible GraphicsPipes available on a particular - * platform, so the name should be meaningful and unique for a given platform. - */ -std::string osxGraphicsPipe:: -get_interface_name() const { - return "OpenGL"; -} - -/** - * This function is passed to the GraphicsPipeSelection object to allow the - * user to make a default osxGraphicsPipe. - */ -PT(GraphicsPipe) osxGraphicsPipe:: -pipe_constructor() { - return new osxGraphicsPipe; -} - -/** - * Returns an indication of the thread in which this GraphicsPipe requires its - * window processing to be performed: typically either the app thread (e.g. - * X) or the draw thread (Windows). - */ -GraphicsPipe::PreferredWindowThread -osxGraphicsPipe::get_preferred_window_thread() const { - return PWT_app; -} - -/** - * Creates a new Quartz bitmap image with the data in the indicated PNMImage. - * The caller should eventually free this image via CGImageRelease. - */ -CGImageRef osxGraphicsPipe:: -create_cg_image(const PNMImage &pnm_image) { - size_t width = pnm_image.get_x_size(); - size_t height = pnm_image.get_y_size(); - -#ifdef PGM_BIGGRAYS - size_t bytes_per_component = 2; -#else - size_t bytes_per_component = 1; -#endif - size_t bits_per_component = bytes_per_component * 8; - size_t num_components = pnm_image.get_num_channels(); - - size_t bits_per_pixel = num_components * bits_per_component; - size_t bytes_per_row = num_components * bytes_per_component * width; - - size_t num_bytes = bytes_per_row * height; - bool has_alpha; - bool is_grayscale; - - CFStringRef color_space_name = nullptr; - switch (pnm_image.get_color_type()) { - case PNMImage::CT_grayscale: - color_space_name = kCGColorSpaceGenericGray; - has_alpha = false; - is_grayscale = true; - break; - - case PNMImage::CT_two_channel: - color_space_name = kCGColorSpaceGenericGray; - has_alpha = true; - is_grayscale = true; - break; - - case PNMImage::CT_color: - color_space_name = kCGColorSpaceGenericRGB; - has_alpha = false; - is_grayscale = false; - break; - - case PNMImage::CT_four_channel: - color_space_name = kCGColorSpaceGenericRGB; - has_alpha = true; - is_grayscale = false; - break; - - case PNMImage::CT_invalid: - // Shouldn't get here. - nassertr(false, nullptr); - break; - } - nassertr(color_space_name != nullptr, nullptr); - - CGColorSpaceRef color_space = CGColorSpaceCreateWithName(color_space_name); - nassertr(color_space != nullptr, nullptr); - - CGBitmapInfo bitmap_info = 0; -#ifdef PGM_BIGGRAYS - bitmap_info |= kCGBitmapByteOrder16Host; -#endif - if (has_alpha) { - bitmap_info |= kCGImageAlphaLast; - } - - // Now convert the pixel data to a format friendly to CGImageCreate(). - char *char_array = (char *)PANDA_MALLOC_ARRAY(num_bytes); - - xelval *dp = (xelval *)char_array; - for (size_t yi = 0; yi < height; ++yi) { - for (size_t xi = 0; xi < width; ++xi) { - if (is_grayscale) { - *dp++ = (xelval)(pnm_image.get_gray(xi, yi) * PGM_MAXMAXVAL); - } else { - *dp++ = (xelval)(pnm_image.get_red(xi, yi) * PGM_MAXMAXVAL); - *dp++ = (xelval)(pnm_image.get_green(xi, yi) * PGM_MAXMAXVAL); - *dp++ = (xelval)(pnm_image.get_blue(xi, yi) * PGM_MAXMAXVAL); - } - if (has_alpha) { - *dp++ = (xelval)(pnm_image.get_alpha(xi, yi) * PGM_MAXMAXVAL); - } - } - } - nassertr((void *)dp == (void *)(char_array + num_bytes), nullptr); - - CGDataProviderRef provider = - CGDataProviderCreateWithData(nullptr, char_array, num_bytes, release_data); - nassertr(provider != nullptr, nullptr); - - CGImageRef image = CGImageCreate - (width, height, bits_per_component, bits_per_pixel, bytes_per_row, - color_space, bitmap_info, provider, - nullptr, false, kCGRenderingIntentDefault); - nassertr(image != nullptr, nullptr); - - CGColorSpaceRelease(color_space); - CGDataProviderRelease(provider); - - return image; -} - -/** - * This callback is assigned to delete the data array allocated within - * create_cg_image(). - */ -void osxGraphicsPipe:: -release_data(void *info, const void *data, size_t size) { - char *char_array = (char *)data; - PANDA_FREE_ARRAY(char_array); -} - -/** - * Creates a new window on the pipe, if possible. - */ -PT(GraphicsOutput) osxGraphicsPipe:: -make_output(const std::string &name, - const FrameBufferProperties &fb_prop, - const WindowProperties &win_prop, - int flags, - GraphicsEngine *engine, - GraphicsStateGuardian *gsg, - GraphicsOutput *host, - int retry, - bool &precertify) { - if (!_is_valid) { - return nullptr; - } - - osxGraphicsStateGuardian *osxgsg = 0; - if (gsg != 0) { - DCAST_INTO_R(osxgsg, gsg, nullptr); - } - - // First thing to try: an osxGraphicsWindow - - if (retry == 0) { - if (((flags&BF_require_parasite)!=0)|| - ((flags&BF_refuse_window)!=0)|| - ((flags&BF_resizeable)!=0)|| - ((flags&BF_size_track_host)!=0)|| - ((flags&BF_can_bind_color)!=0)|| - ((flags&BF_can_bind_every)!=0)|| - ((flags&BF_can_bind_layered)!=0)) { - return nullptr; - } - WindowHandle *window_handle = win_prop.get_parent_window(); - if (window_handle != nullptr) { - osxdisplay_cat.info() - << "Got parent_window " << *window_handle << "\n"; -#ifdef SUPPORT_SUBPROCESS_WINDOW - WindowHandle::OSHandle *os_handle = window_handle->get_os_handle(); - if (os_handle != nullptr && - os_handle->is_of_type(NativeWindowHandle::SubprocessHandle::get_class_type())) { - return new SubprocessWindow(engine, this, name, fb_prop, win_prop, - flags, gsg, host); - } -#endif // SUPPORT_SUBPROCESS_WINDOW - } - return new osxGraphicsWindow(engine, this, name, fb_prop, win_prop, - flags, gsg, host); - } - - // Second thing to try: a GLGraphicsBuffer - - if (retry == 1) { - if (!osx_support_gl_buffer || !gl_support_fbo || host == nullptr || - (flags & (BF_require_parasite | BF_require_window)) != 0) { - return nullptr; - } - // Early failure - if we are sure that this buffer WONT meet specs, we can - // bail out early. - if ((flags & BF_fb_props_optional) == 0) { - if (fb_prop.get_indexed_color() || - fb_prop.get_back_buffers() > 0 || - fb_prop.get_accum_bits() > 0) { - return nullptr; - } - } - if (osxgsg != nullptr && osxgsg->is_valid() && !osxgsg->needs_reset()) { - if (!osxgsg->_supports_framebuffer_object || - osxgsg->_glDrawBuffers == nullptr) { - return nullptr; - } else if (fb_prop.is_basic()) { - // Early success - if we are sure that this buffer WILL meet specs, we - // can precertify it. - precertify = true; - } - } - return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop, flags, gsg, host); - } - - // Third thing to try: an osxGraphicsBuffer - if (retry == 2) { - if ((!support_render_texture)|| - ((flags&BF_require_parasite)!=0)|| - ((flags&BF_require_window)!=0)|| - ((flags&BF_resizeable)!=0)|| - ((flags&BF_size_track_host)!=0)|| - ((flags&BF_can_bind_every)!=0)|| - ((flags&BF_can_bind_layered)!=0)) { - return nullptr; - } - return new osxGraphicsBuffer(engine, this, name, fb_prop, win_prop, - flags, gsg, host); - } - - // Nothing else left to try. - return nullptr; -} - -/** - * 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, nullptr); -} diff --git a/panda/src/osxdisplay/osxGraphicsPipe.h b/panda/src/osxdisplay/osxGraphicsPipe.h deleted file mode 100644 index 75094778d6..0000000000 --- a/panda/src/osxdisplay/osxGraphicsPipe.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file osxGraphicsPipe.h - */ - -#ifndef OSXGRAPHICSPIPE_H -#define OSXGRAPHICSPIPE_H - -#include "pandabase.h" -#include "graphicsPipe.h" - -#include - -class osxGraphicsStateGuardian; -class PNMImage; - -/** - * This graphics pipe represents the interface for creating OpenGL graphics - * windows on the various OSX's. - */ -class EXPCL_PANDA_OSXDISPLAY osxGraphicsPipe : public GraphicsPipe { -public: - osxGraphicsPipe(); - virtual ~osxGraphicsPipe(); - - virtual std::string get_interface_name() const; - static PT(GraphicsPipe) pipe_constructor(); - virtual PreferredWindowThread get_preferred_window_thread() const; - - static CGImageRef create_cg_image(const PNMImage &pnm_image); - -private: - static void release_data(void *info, const void *data, size_t size); - -protected: - virtual PT(GraphicsOutput) make_output(const std::string &name, - const FrameBufferProperties &fb_prop, - const WindowProperties &win_prop, - int flags, - GraphicsEngine *engine, - GraphicsStateGuardian *gsg, - GraphicsOutput *host, - int retry, - bool &precertify); - virtual PT(GraphicsStateGuardian) make_callback_gsg(GraphicsEngine *engine); - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - GraphicsPipe::init_type(); - register_type(_type_handle, "osxGraphicsPipe", - GraphicsPipe::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; - - friend class osxGraphicsBuffer; -}; - -#endif diff --git a/panda/src/osxdisplay/osxGraphicsStateGuardian.cxx b/panda/src/osxdisplay/osxGraphicsStateGuardian.cxx deleted file mode 100644 index 2fb60d2d74..0000000000 --- a/panda/src/osxdisplay/osxGraphicsStateGuardian.cxx +++ /dev/null @@ -1,459 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file osxGraphicsStateGuardian.cxx - */ - -#include "osxGraphicsStateGuardian.h" -#include "osxGraphicsBuffer.h" -#include "string_utils.h" -#include "config_osxdisplay.h" -#include "depthWriteAttrib.h" -#include "depthTestAttrib.h" -#include "textureAttrib.h" -#include "pnmImage.h" - -#include -#import - -// This is generated data for the standard texture we use for drawing the -// resize box in the window corner. -#include "resize_box.rgb.c" - -TypeHandle osxGraphicsStateGuardian::_type_handle; - -/** - * Returns the pointer to the GL extension function with the indicated name. - * It is the responsibility of the caller to ensure that the required - * extension is defined in the OpenGL runtime prior to calling this; it is an - * error to call this for a function that is not defined. - */ -void *osxGraphicsStateGuardian:: -do_get_extension_func(const char *name) { - std::string fullname = "_" + std::string(name); - NSSymbol symbol = nullptr; - - if (NSIsSymbolNameDefined(fullname.c_str())) { - symbol = NSLookupAndBindSymbol(fullname.c_str()); - } - - return symbol ? NSAddressOfSymbol(symbol) : nullptr; -} - -/** - * - */ -osxGraphicsStateGuardian:: -osxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe, - osxGraphicsStateGuardian *share_with) : - GLGraphicsStateGuardian(engine, pipe), - _share_with(share_with), - _aglPixFmt(nullptr), - _aglcontext(nullptr) -{ - _shared_buffer = 1011; - get_gamma_table(); -} - -/** - * - */ -osxGraphicsStateGuardian:: -~osxGraphicsStateGuardian() { - if (_aglcontext != (AGLContext)nullptr) { - aglSetCurrentContext(nullptr); - aglDestroyContext(_aglcontext); - report_agl_error("aglDestroyContext"); - _aglcontext = (AGLContext)nullptr; - } -} - -/** - * Resets all internal state as if the gsg were newly created. - */ -void osxGraphicsStateGuardian::reset() -{ -/* - if(_aglcontext != (AGLContext)NULL) - { - aglDestroyContext(_aglcontext); - report_agl_error(); - _aglcontext = (AGLContext)NULL; - } - */ - - GLGraphicsStateGuardian::reset(); - - if (_aglcontext != (AGLContext)nullptr) { - // Apply the video-sync setting. - GLint value = sync_video ? 1 : 0; - aglSetInteger(_aglcontext, AGL_SWAP_INTERVAL, &value); - } -} - -/** - * Draws an OSX-style resize icon in the bottom right corner of the current - * display region. This is normally done automatically at the end of each - * frame when the window is indicated as resizable, since the 3-D graphics - * overlay the normal, OS-drawn resize icon and the user won't be able see it. - */ -void osxGraphicsStateGuardian:: -draw_resize_box() { - // This state is created, once, and never freed. - static CPT(RenderState) state; - if (state == nullptr) { - state = RenderState::make(TransparencyAttrib::make(TransparencyAttrib::M_alpha), - DepthWriteAttrib::make(DepthWriteAttrib::M_off), - DepthTestAttrib::make(DepthTestAttrib::M_none)); - - // Get the default texture to apply to the resize box; it's compiled into - // the code. - std::string resize_box_string((const char *)resize_box, resize_box_len); - std::istringstream resize_box_strm(resize_box_string); - PNMImage resize_box_pnm; - if (resize_box_pnm.read(resize_box_strm, "resize_box.rgb")) { - PT(Texture) tex = new Texture; - tex->set_name("resize_box.rgb"); - tex->load(resize_box_pnm); - tex->set_minfilter(SamplerState::FT_linear); - tex->set_magfilter(SamplerState::FT_linear); - state = state->add_attrib(TextureAttrib::make(tex)); - } - } - - // Clear out the lens. - _projection_mat_inv = _projection_mat = TransformState::make_identity(); - prepare_lens(); - - // Set the state to our specific, known state for drawing the icon. - set_state_and_transform(state, TransformState::make_identity()); - - // Now determine the inner corner of the quad, choosing a 15x15 pixel square - // in the lower-right corner, computed from the viewport size. - PN_stdfloat inner_x = 1.0f - (15.0f * 2.0f / _viewport_width); - PN_stdfloat inner_y = (15.0f * 2.0f / _viewport_height) - 1.0f; - - // Draw the quad. We just use the slow, simple immediate mode calls here. - // It's just one quad, after all. - glBegin(GL_QUADS); - - glColor4f(1.0, 1.0, 1.0, 1.0); - glTexCoord2f(0.0, 0.0); - glVertex2f(inner_x, -1.0); - - glTexCoord2f(0.9375, 0.0); - glVertex2f(1.0, -1.0); - - glTexCoord2f(0.9375, 0.9375); - glVertex2f(1.0, inner_y); - - glTexCoord2f(0.0, 0.9375); - glVertex2f(inner_x, inner_y); - - glEnd(); -} - -/** - * This function will build up a context for a gsg.. - */ -OSStatus osxGraphicsStateGuardian:: -build_gl(bool full_screen, bool pbuffer, FrameBufferProperties &fb_props) { - if (_aglcontext) { - describe_pixel_format(fb_props); - return noErr; // already built - } - - OSStatus err = noErr; - - GDHandle display = GetMainDevice(); - - pvector attrib; - if (!fb_props.get_indexed_color()) { - attrib.push_back(AGL_RGBA); - int color_bits = fb_props.get_color_bits(); - int alpha_bits = fb_props.get_alpha_bits(); - attrib.push_back(AGL_BUFFER_SIZE); - attrib.push_back(color_bits + alpha_bits); - attrib.push_back(AGL_PIXEL_SIZE); - attrib.push_back(color_bits); - attrib.push_back(AGL_RED_SIZE); - attrib.push_back(fb_props.get_red_bits()); - attrib.push_back(AGL_GREEN_SIZE); - attrib.push_back(fb_props.get_green_bits()); - attrib.push_back(AGL_BLUE_SIZE); - attrib.push_back(fb_props.get_blue_bits()); - attrib.push_back(AGL_ALPHA_SIZE); - attrib.push_back(alpha_bits); - } - attrib.push_back(AGL_DEPTH_SIZE); - attrib.push_back(fb_props.get_depth_bits()); - attrib.push_back(AGL_STENCIL_SIZE); - attrib.push_back(fb_props.get_stencil_bits()); - if (fb_props.get_multisamples() != 0) { - attrib.push_back(AGL_MULTISAMPLE); - attrib.push_back(AGL_SAMPLE_BUFFERS_ARB); - attrib.push_back(1); - attrib.push_back(AGL_SAMPLES_ARB); - attrib.push_back(fb_props.get_multisamples()); - } - - if (fb_props.is_stereo()) { - attrib.push_back(AGL_STEREO); - } - - if (!fb_props.is_single_buffered()) { - attrib.push_back(AGL_DOUBLEBUFFER); - } - if (full_screen) { - attrib.push_back(AGL_FULLSCREEN); - } - if (pbuffer) { - attrib.push_back(AGL_PBUFFER); - } - - if (fb_props.get_force_hardware()) { - attrib.push_back(AGL_ACCELERATED); - attrib.push_back(AGL_NO_RECOVERY); - } - - // Allow the system to choose the largest buffers requested that meets all - // our selections. - attrib.push_back(AGL_MAXIMUM_POLICY); - - // Terminate the list. - attrib.push_back(AGL_NONE); - - // build context - _aglcontext = nullptr; - _aglPixFmt = aglChoosePixelFormat(&display, 1, &attrib[0]); - err = report_agl_error("aglChoosePixelFormat"); - if (_aglPixFmt) { - if(_share_with == nullptr) { - _aglcontext = aglCreateContext(_aglPixFmt, nullptr); - } else { - _aglcontext = aglCreateContext(_aglPixFmt, ((osxGraphicsStateGuardian *)_share_with)->_aglcontext); - } - err = report_agl_error("aglCreateContext"); - - if (_aglcontext == nullptr) { - osxdisplay_cat.error() - << "osxGraphicsStateGuardian::build_gl Error Getting GL Context \n" ; - if(err == noErr) { - err = -1; - } - } else { - aglSetInteger(_aglcontext, AGL_BUFFER_NAME, &_shared_buffer); - err = report_agl_error("aglSetInteger AGL_BUFFER_NAME"); - } - - } else { - osxdisplay_cat.error() - << "osxGraphicsStateGuardian::build_gl Error Getting Pixel Format\n" ; - osxdisplay_cat.error() - << fb_props << "\n"; - if(err == noErr) { - err = -1; - } - } - - if (err == noErr) { - describe_pixel_format(fb_props); - } - - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "osxGraphicsStateGuardian::build_gl Returning :" << err << "\n"; - osxdisplay_cat.debug() - << fb_props << "\n"; - } - - return err; -} - - -/** - * Fills in the fb_props member with the appropriate values according to the - * chosen pixel format. - */ -void osxGraphicsStateGuardian:: -describe_pixel_format(FrameBufferProperties &fb_props) { - fb_props.clear(); - GLint value; - - if (aglDescribePixelFormat(_aglPixFmt, AGL_RGBA, &value)) { - fb_props.set_indexed_color(!value); - fb_props.set_rgb_color(value); - } - if (aglDescribePixelFormat(_aglPixFmt, AGL_DEPTH_SIZE, &value)) { - fb_props.set_depth_bits(value); - } - int color_bits = 0; - if (aglDescribePixelFormat(_aglPixFmt, AGL_RED_SIZE, &value)) { - fb_props.set_red_bits(value); - color_bits += value; - } - if (aglDescribePixelFormat(_aglPixFmt, AGL_GREEN_SIZE, &value)) { - fb_props.set_green_bits(value); - color_bits += value; - } - if (aglDescribePixelFormat(_aglPixFmt, AGL_BLUE_SIZE, &value)) { - fb_props.set_blue_bits(value); - color_bits += value; - } - fb_props.set_color_bits(color_bits); - if (aglDescribePixelFormat(_aglPixFmt, AGL_ALPHA_SIZE, &value)) { - fb_props.set_alpha_bits(value); - } - - if (aglDescribePixelFormat(_aglPixFmt, AGL_STENCIL_SIZE, &value)) { - fb_props.set_stencil_bits(value); - } - - int accum_bits = 0; - if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_RED_SIZE, &value)) { - accum_bits += value; - } - if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_GREEN_SIZE, &value)) { - accum_bits += value; - } - if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_BLUE_SIZE, &value)) { - accum_bits += value; - } - - if (aglDescribePixelFormat(_aglPixFmt, AGL_SAMPLES_ARB, &value)) { - fb_props.set_multisamples(value); - } - - if (aglDescribePixelFormat(_aglPixFmt, AGL_DOUBLEBUFFER, &value)) { - if (value) { - fb_props.set_back_buffers(1); - } else { - fb_props.set_back_buffers(0); - } - } - - if (aglDescribePixelFormat(_aglPixFmt, AGL_STEREO, &value)) { - fb_props.set_stereo(value); - } - - // Until we query the renderer, we don't know whether it's hardware or - // software based, so set both flags to indicate we don't know. - fb_props.set_force_hardware(true); - fb_props.set_force_software(true); - - GLint ndevs; - AGLDevice *gdevs = aglDevicesOfPixelFormat(_aglPixFmt, &ndevs); - if (gdevs != nullptr) { - AGLRendererInfo rinfo = aglQueryRendererInfo(gdevs, ndevs); - if (rinfo != nullptr) { - if (aglDescribeRenderer(rinfo, AGL_ACCELERATED, &value)) { - // Now we know whether it's hardware or software. - fb_props.set_force_hardware(value); - fb_props.set_force_software(!value); - } - if (aglDescribeRenderer(rinfo, AGL_VIDEO_MEMORY, &value)) { - osxdisplay_cat.debug() - << "Reported video memory is " << value << "\n"; - } - if (aglDescribeRenderer(rinfo, AGL_TEXTURE_MEMORY, &value)) { - osxdisplay_cat.debug() - << "Reported texture memory is " << value << "\n"; - } - } - } -} - -/** - * Static function for getting the orig gamma tables - */ -bool osxGraphicsStateGuardian:: -get_gamma_table() { - CGDisplayRestoreColorSyncSettings(); - _cgErr = CGGetDisplayTransferByTable( 0, 256, _gOriginalRedTable, _gOriginalGreenTable, _gOriginalBlueTable, &_sampleCount); -} - -/** - * Static function for setting gamma which is needed for atexit. - */ -bool osxGraphicsStateGuardian:: -static_set_gamma(bool restore, PN_stdfloat gamma) { - bool set; - - set = false; - - if (restore) { - CGDisplayRestoreColorSyncSettings(); - set = true; - return set; - } - // CGDisplayRestoreColorSyncSettings(); - - // CGGammaValue gOriginalRedTable[ 256 ]; CGGammaValue gOriginalGreenTable[ - // 256 ]; CGGammaValue gOriginalBlueTable[ 256 ]; - - // CGTableCount sampleCount; CGDisplayErr cgErr; - - // cgErr = CGGetDisplayTransferByTable( 0, 256, _gOriginalRedTable, - // _gOriginalGreenTable, _gOriginalBlueTable, &_sampleCount); - - CGGammaValue redTable[ 256 ]; - CGGammaValue greenTable[ 256 ]; - CGGammaValue blueTable[ 256 ]; - - short j, i; - short y[3]; - - for (j = 0; j < 3; j++) { - y[j] = 255; - } - - y[0] = 256 * gamma; - y[1] = 256 * gamma; - y[2] = 256 * gamma; - - for (i = 0; i < 256; i++) { - redTable[i] = _gOriginalRedTable[ i ] * (y[ 0 ] ) / 256; - greenTable[ i ] = _gOriginalGreenTable[ i ] * (y[ 1 ] ) / 256; - blueTable[ i ] = _gOriginalBlueTable[ i ] * (y[ 2 ] ) / 256; - } - _cgErr = CGSetDisplayTransferByTable( 0, 256, redTable, greenTable, blueTable); - - if (_cgErr == 0) { - set = true; - } - - return set; -} - -/** - * Non static version of setting gamma. Returns true on success. - */ -bool osxGraphicsStateGuardian:: -set_gamma(PN_stdfloat gamma) { - bool set; - - set = static_set_gamma(false, gamma); - - return set; -} - -/** - * Restore original gamma. - */ -void osxGraphicsStateGuardian:: -restore_gamma() { - static_set_gamma(true, 1.0f); -} - -/** - * This function is passed to the atexit function. - */ -void osxGraphicsStateGuardian:: -atexit_function() { - static_set_gamma(true, 1.0); -} diff --git a/panda/src/osxdisplay/osxGraphicsStateGuardian.h b/panda/src/osxdisplay/osxGraphicsStateGuardian.h deleted file mode 100644 index 96c86f28dd..0000000000 --- a/panda/src/osxdisplay/osxGraphicsStateGuardian.h +++ /dev/null @@ -1,94 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file osxGraphicsStateGuardian.h - */ - -#ifndef OSXGRAPHICSSTATEGUARDIAN_H -#define OSXGRAPHICSSTATEGUARDIAN_H -#include -#include - -#define __glext_h_ -#include -#include - -#include "pandabase.h" -#include "glgsg.h" - -#include "osxGraphicsWindow.h" - -class osxGraphicsWindow; - -/** - * A tiny specialization on GLGraphicsStateGuardian to add some wgl-specific - * information. - */ -class osxGraphicsStateGuardian : public GLGraphicsStateGuardian { -public: - osxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe, - osxGraphicsStateGuardian *share_with); - virtual ~osxGraphicsStateGuardian(); - virtual void reset(); - - void draw_resize_box(); - - bool get_gamma_table(); - bool static_set_gamma(bool restore, PN_stdfloat gamma); - bool set_gamma(PN_stdfloat gamma); - void atexit_function(); - void restore_gamma(); - -protected: - virtual void *do_get_extension_func(const char *name); - -public: - OSStatus build_gl(bool full_screen, bool pbuffer, FrameBufferProperties &fb_props); - AGLContext get_context() { return _aglcontext; }; - - const AGLPixelFormat get_agl_pixel_format() const { return _aglPixFmt; }; - -private: - void describe_pixel_format(FrameBufferProperties &fb_props); - - // We have to save a pointer to the GSG we intend to share texture context - // with, since we don't create our own context in the constructor. - PT(osxGraphicsStateGuardian) _share_with; - AGLPixelFormat _aglPixFmt; - AGLContext _aglcontext; - CGGammaValue _gOriginalRedTable[ 256 ]; - CGGammaValue _gOriginalGreenTable[ 256 ]; - CGGammaValue _gOriginalBlueTable[ 256 ]; - uint32_t _sampleCount; - CGDisplayErr _cgErr; - -public: - GLint _shared_buffer; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - GLGraphicsStateGuardian::init_type(); - register_type(_type_handle, "osxGraphicsStateGuardian", - GLGraphicsStateGuardian::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; - - friend class osxGraphicsBuffer; -}; - - -#endif diff --git a/panda/src/osxdisplay/osxGraphicsWindow.I b/panda/src/osxdisplay/osxGraphicsWindow.I deleted file mode 100644 index a5a7661366..0000000000 --- a/panda/src/osxdisplay/osxGraphicsWindow.I +++ /dev/null @@ -1,24 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file osxGraphicsWindow.I - * @author drose - * @date 2009-02-13 - */ - -/** - * - */ -inline void osxGraphicsWindow:: -send_key_event(ButtonHandle key, bool down) { - if (down) { - _input_devices[0].button_down(key); - } else { - _input_devices[0].button_up(key); - } -} diff --git a/panda/src/osxdisplay/osxGraphicsWindow.h b/panda/src/osxdisplay/osxGraphicsWindow.h deleted file mode 100644 index b797cc10f4..0000000000 --- a/panda/src/osxdisplay/osxGraphicsWindow.h +++ /dev/null @@ -1,145 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file osxGraphicsWindow.h - */ - -#ifndef OSXGRAPHICSWINDOW_H -#define OSXGRAPHICSWINDOW_H - -#include "pandabase.h" -#include "graphicsWindow.h" -#include "buttonHandle.h" - -#include - -#define __glext_h_ -#include -#include - -#define HACK_SCREEN_HASH_CONTEXT true -OSStatus report_agl_error(const std::string &comment); - -/** - * An interface to the osx/ system for managing GL windows under X. - */ -class osxGraphicsWindow : public GraphicsWindow { -public: - osxGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, - const std::string &name, - const FrameBufferProperties &fb_prop, - const WindowProperties &win_prop, - int flags, - GraphicsStateGuardian *gsg, - GraphicsOutput *host); - virtual ~osxGraphicsWindow(); - - virtual bool move_pointer(int device, int x, int y); - - 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 bool do_reshape_request(int x_origin, int y_origin, bool has_origin, - int x_size, int y_size); - - virtual void mouse_mode_absolute(); - virtual void mouse_mode_relative(); - - virtual void set_properties_now(WindowProperties &properties); - -private: - void release_system_resources(bool destructing); - inline void send_key_event(ButtonHandle key, bool down); - -protected: - virtual void close_window(); - virtual bool open_window(); - -private: - bool os_open_window(WindowProperties &properties); - - // a singleton .. for the events to find the right pipe to push the event - // into - -public: // do not call direct .. - OSStatus handle_key_input(EventHandlerCallRef myHandler, EventRef event, - Boolean keyDown); - OSStatus handle_text_input(EventHandlerCallRef myHandler, EventRef event); - OSStatus handle_window_mouse_events(EventHandlerCallRef myHandler, EventRef event); - ButtonHandle osx_translate_key(UInt32 key, EventRef event); - static osxGraphicsWindow *get_current_osx_window(WindowRef hint); - - void handle_modifier_delta(UInt32 new_modifiers); - void handle_button_delta(UInt32 new_buttons); - void do_resize(); - - OSStatus event_handler(EventHandlerCallRef myHandler, EventRef event); - - virtual void user_close_request(); - void system_close_window(); - void system_set_window_foreground(bool foreground); - void system_point_to_local_point(Point &global_point); - void local_point_to_system_point(Point &local_point); - AGLContext get_gsg_context(); - AGLContext get_context(); - OSStatus build_gl(bool full_screen); - bool set_icon_filename(const Filename &icon_filename); - - void set_pointer_in_window(int x, int y); - void set_pointer_out_of_window(); - -private: - UInt32 _last_key_modifiers; - UInt32 _last_buttons; - WindowRef _osx_window; - bool _is_fullscreen; - - CGImageRef _pending_icon; - CGImageRef _current_icon; - - int _ID; - static osxGraphicsWindow *full_screen_window; - -#ifdef HACK_SCREEN_HASH_CONTEXT - AGLContext _holder_aglcontext; -#endif - CFDictionaryRef _originalMode; - - // True if _properties.get_cursor_hidden() is true. - bool _cursor_hidden; - - // True if the cursor is actually hidden right now via system calls. - bool _display_hide_cursor; - - SInt32 _wheel_hdelta; - SInt32 _wheel_vdelta; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - GraphicsWindow::init_type(); - register_type(_type_handle, "osxGraphicsWindow", - GraphicsWindow::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; -}; - -#include "osxGraphicsWindow.I" - -#endif diff --git a/panda/src/osxdisplay/osxGraphicsWindow.mm b/panda/src/osxdisplay/osxGraphicsWindow.mm deleted file mode 100644 index 293f2fd2a3..0000000000 --- a/panda/src/osxdisplay/osxGraphicsWindow.mm +++ /dev/null @@ -1,2019 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file osxGraphicsWindow.mm - */ - -// We include these system header files first, because there is a namescope -// conflict between them and some other header file that gets included later -// (in particular, TCP_NODELAY must not be a #define symbol for these headers -// to be included properly). - -#include -#include -#include -#include -#include - -// We have to include this before we include the system OpenGLgl.h file, but -// after we include all of the above header files. Deal with this -// contradiction later. -#include "glgsg.h" - -#include "osxGraphicsWindow.h" -#include "config_osxdisplay.h" -#include "osxGraphicsPipe.h" -#include "pStatTimer.h" -#include "keyboardButton.h" -#include "mouseButton.h" -#include "osxGraphicsStateGuardian.h" -#include "osxGraphicsPipe.h" -#include "throw_event.h" -#include "pnmImage.h" -#include "virtualFileSystem.h" -#include "config_putil.h" -#include "pset.h" -#include "pmutex.h" - - -static Mutex & -osx_global_mutex() { - static Mutex m("osx_global_mutex"); - return m; -} - - -TypeHandle osxGraphicsWindow::_type_handle; -osxGraphicsWindow *osxGraphicsWindow::full_screen_window = NULL; - -#define USER_CONTAINER - -#ifdef USER_CONTAINER - -pset my_windows; -static void -add_a_window(WindowRef window) { - my_windows.insert(window); -} - -static bool -check_my_window(WindowRef window) { - return my_windows.find(window) != my_windows.end(); -} - -#else // USER_CONTAINER - -static void -add_a_window(WindowRef window) { -} - -static bool -check_my_window(WindowRef window) { - return true; -} - -#endif // USER_CONTAINER - - - -/** - * Returns the active window for the purpose of recording events. - */ -osxGraphicsWindow *osxGraphicsWindow:: -get_current_osx_window(WindowRef window) { - if (full_screen_window != NULL) { - return full_screen_window; - } - - if (window == NULL) { - // HID use this path - - // Assume first we are a child window. If we cant find a window of that - // class, then we are standalone and can jsut grab the front window. - window = GetFrontWindowOfClass(kSimpleWindowClass, TRUE); - if (window == NULL) { - window = FrontNonFloatingWindow(); - } - } - - if (window && check_my_window(window)) { - return (osxGraphicsWindow *)GetWRefCon (window); - } else { - return NULL; - } -} - -/** - * Convenience function to report the current AGL error code as a formatted - * error message. - */ -OSStatus -report_agl_error(const string &comment) { - GLenum err = aglGetError(); - if (err != AGL_NO_ERROR) { - osxdisplay_cat.error() - << "AGL Error " << aglErrorString(err) << " [" <> 1; - i += rowBytes, j -= rowBytes) { - memcpy(buffer, &imageData[i], rowBytes); - memcpy(&imageData[i], &imageData[j], rowBytes); - memcpy(&imageData[j], buffer, rowBytes); - } -} - -/** - * Drop a GL overlay onto a carbon window.. - */ -static void -composite_gl_buffer_into_window(AGLContext ctx, Rect *bufferRect, - GrafPtr out_port) { - GWorldPtr world; - QDErr err; - - // blit OpenGL content into window backing store allocate buffer to hold - // pane image - long width = (bufferRect->right - bufferRect->left); - long height = (bufferRect->bottom - bufferRect->top); - - Rect src_rect = {0, 0, height, width}; - Rect ddrc_rect = {0, 0, height, width}; - long row_bytes = width * 4; - long image_size = row_bytes * height; - char *image = (char *)NewPtr(image_size); - - if (!image) { - osxdisplay_cat.error() - << "Out of memory in composite_gl_buffer_into_window()!\n"; - return; // no harm in continuing - } - - // pull GL content down to our image buffer - aglSetCurrentContext(ctx); - glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - image); - - // GL buffers are upside-down relative to QD buffers, so we need to flip it - invert_gl_image(image, image_size, row_bytes); - - // create a GWorld containing our image - err = NewGWorldFromPtr(&world, k32ARGBPixelFormat, &src_rect, 0, 0, 0, - image, row_bytes); - if (err != noErr) { - osxdisplay_cat.error() - << " error in NewGWorldFromPtr, called from composite_gl_buffer_into_window()\n"; - DisposePtr(image); - return; - } - - GrafPtr port_save = NULL; - Boolean port_changed = QDSwapPort(out_port, &port_save); - - CopyBits(GetPortBitMapForCopyBits(world), - GetPortBitMapForCopyBits(out_port), - &src_rect, &ddrc_rect, srcCopy, 0); - - if (port_changed) { - QDSwapPort(port_save, NULL); - } - - DisposeGWorld(world); - DisposePtr(image); -} - -/** - * The standard window event handler for non-fullscreen windows. - */ -OSStatus osxGraphicsWindow:: -event_handler(EventHandlerCallRef myHandler, EventRef event) { - OSStatus result = eventNotHandledErr; - UInt32 the_class = GetEventClass(event); - UInt32 kind = GetEventKind(event); - - WindowRef window = NULL; - GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, - sizeof(window), NULL, &window); - - UInt32 attributes = 0; - GetEventParameter(event, kEventParamAttributes, typeUInt32, NULL, - sizeof(attributes), NULL, &attributes); - - if (osxdisplay_cat.is_spam()) { - osxdisplay_cat.spam() - << ClockObject::get_global_clock()->get_real_time() - << " event_handler: " << (void *)this << ", " << window - << ", " << the_class << ", " << kind << "\n"; - } - - switch (the_class) { - case kEventClassMouse: - result = handle_window_mouse_events (myHandler, event); - break; - - case kEventClassWindow: - switch (kind) { - case kEventWindowCollapsing: - /* - Rect r; - GetWindowPortBounds (window, &r); - composite_gl_buffer_into_window(get_context(), &r, GetWindowPort (window)); - UpdateCollapsedWindowDockTile (window); - */ - system_set_window_foreground(false); - break; - - case kEventWindowActivated: // called on click activation and initially - system_set_window_foreground(true); - do_resize(); - break; - - case kEventWindowDeactivated: - system_set_window_foreground(false); - break; - - case kEventWindowClose: // called when window is being closed (close box) - // This is a message from the window manager indicating that the user - // has requested to close the window. - user_close_request(); - result = noErr; - break; - - case kEventWindowShown: // called on initial show (not on un-minimize) - if (window == FrontNonFloatingWindow ()) - SetUserFocusWindow (window); - break; - - case kEventWindowBoundsChanging: - // Gives us a chance to intercept resize attempts - if (attributes & kWindowBoundsChangeSizeChanged) { - // If the window is supposed to be fixed-size, enforce this. - if (_properties.get_fixed_size()) { - Rect bounds; - GetEventParameter(event, kEventParamCurrentBounds, - typeQDRectangle, NULL, sizeof(bounds), NULL, &bounds); - bounds.right = bounds.left + _properties.get_x_size(); - bounds.bottom = bounds.top + _properties.get_y_size(); - SetEventParameter(event, kEventParamCurrentBounds, - typeQDRectangle, sizeof(bounds), &bounds); - result = noErr; - } - } - break; - - case kEventWindowBoundsChanged: // called for resize and moves (drag) - do_resize(); - break; - - case kEventWindowZoomed: - break; - - case kEventWindowCollapsed: - { - WindowProperties properties; - properties.set_minimized(true); - system_changed_properties(properties); - } - break; - - case kEventWindowExpanded: - { - WindowProperties properties; - properties.set_minimized(false); - system_changed_properties(properties); - } - break; - } - break; - } - - return result; -} - -/** - * The user has requested to close the window, for instance with Cmd-W, or by - * clicking on the close button. - */ -void osxGraphicsWindow:: -user_close_request() { - string close_request_event = get_close_request_event(); - if (!close_request_event.empty()) { - // In this case, the app has indicated a desire to intercept the request - // and process it directly. - throw_event(close_request_event); - } else { - // In this case, the default case, the app does not intend to service the - // request, so we do by closing the window. - close_window(); - } -} - -/** - * The window has been closed by an OS resource, not by an internal request - */ -void osxGraphicsWindow:: -system_close_window() { - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "System Closing Window \n"; - } - release_system_resources(false); -} - -/** - * The C callback for Window Events - * - * We only hook this up for non-fullscreen windows, so we only handle system - * window events. - */ -static pascal OSStatus -window_event_handler(EventHandlerCallRef my_handler, EventRef event, void *) { - // volatile().lock(); - - WindowRef window = NULL; - GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, - sizeof(WindowRef), NULL, &window); - - if (window != NULL) { - osxGraphicsWindow *osx_win = osxGraphicsWindow::get_current_osx_window(window); - if (osx_win != (osxGraphicsWindow *)NULL) { - // osx_global_mutex().release(); - return osx_win->event_handler(my_handler, event); - } - } - - // osx_global_mutex().release(); - return eventNotHandledErr; -} - -/** - * - */ -void osxGraphicsWindow:: -do_resize() { - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "In Resize....." << _properties << "\n"; - } - - // only in window mode .. not full screen - if (_osx_window != NULL && !_is_fullscreen && _properties.has_size()) { - Rect rectPort = { - 0, 0, 0, 0 - }; - CGRect viewRect = { - { 0.0f, 0.0f }, { 0.0f, 0.0f } - }; - - GetWindowPortBounds(_osx_window, &rectPort); - viewRect.size.width = (PN_stdfloat)(rectPort.right - rectPort.left); - viewRect.size.height = (PN_stdfloat)(rectPort.bottom - rectPort.top); - - // tell panda - WindowProperties properties; - properties.set_size((int)viewRect.size.width,(int)viewRect.size.height); - properties.set_origin((int) rectPort.left,(int)rectPort.top); - system_changed_properties(properties); - - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << " Resizing Window " << viewRect.size.width - << " " << viewRect.size.height << "\n"; - } - - AGLContext context = get_gsg_context(); - if (context != (AGLContext)NULL) { - // ping gl - if (!aglSetCurrentContext(context)) { - report_agl_error("aglSetCurrentContext"); - } - aglUpdateContext(context); - report_agl_error("aglUpdateContext .. This is a Resize.."); - } - - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "Resize Complete.....\n"; - } - } -} - -/** - * The C callback for Application events. - * - * Hooked once per application. - */ -static pascal OSStatus -app_event_handler(EventHandlerCallRef my_handler, EventRef event, - void *user_data) { - OSStatus result = eventNotHandledErr; - { - // osx_global_mutex().lock(); - - osxGraphicsWindow *osx_win = NULL; - WindowRef window = NULL; - UInt32 the_class = GetEventClass (event); - UInt32 kind = GetEventKind (event); - - GetEventParameter(event, kEventParamWindowRef, typeWindowRef, NULL, - sizeof(WindowRef), NULL, (void*) &window); - osx_win = osxGraphicsWindow::get_current_osx_window(window); - if (osx_win == NULL) { - // osx_global_mutex().release(); - return eventNotHandledErr; - } - - switch (the_class) { - case kEventClassTextInput: - if (kind == kEventTextInputUnicodeForKeyEvent) { - osx_win->handle_text_input(my_handler, event); - } - // result = noErr; can not report handled .. the os will not sent the - // raw key strokes then if(osx_win->handle_text_input(my_handler, event) - // == noErr) result = noErr; - break; - - case kEventClassKeyboard: - { - switch (kind) { - case kEventRawKeyRepeat: - case kEventRawKeyDown: - result = osx_win->handle_key_input (my_handler, event, true); - break; - case kEventRawKeyUp: - result = osx_win->handle_key_input (my_handler, event, false); - break; - case kEventRawKeyModifiersChanged: - { - UInt32 newModifiers; - OSStatus error = GetEventParameter(event, kEventParamKeyModifiers,typeUInt32, NULL,sizeof(UInt32), NULL, &newModifiers); - if (error == noErr) { - osx_win->handle_modifier_delta(newModifiers); - result = noErr; - } - } - break; - } - } - break; - - case kEventClassMouse: - // osxdisplay_cat.info() << "Mouse movement handled by Application - // handler\n"; if(osxGraphicsWindow::full_screen_window != NULL) - result = osx_win->handle_window_mouse_events(my_handler, event); - // result = noErr; - break; - } - - // osx_global_mutex().release(); - } - - return result; -} - -/** - * Trap Unicode Input. - */ -OSStatus osxGraphicsWindow:: -handle_text_input(EventHandlerCallRef my_handler, EventRef text_event) { - UniChar *text = NULL; - UInt32 actual_size = 0; - - OSStatus ret = GetEventParameter(text_event, kEventParamTextInputSendText, - typeUnicodeText, NULL, 0, &actual_size, NULL); - if (ret != noErr) { - return ret; - } - - text = (UniChar*)NewPtr(actual_size); - if (text!= NULL) { - ret = GetEventParameter (text_event, kEventParamTextInputSendText,typeUnicodeText, NULL, actual_size, NULL, text); - if (ret != noErr) { - return ret; - } - - for (unsigned int x = 0; x < actual_size/sizeof(UniChar); ++x) { - _input_devices[0].keystroke(text[x]); - } - DisposePtr((char *)text); - } - - return ret; -} - -/** - * Clean up the OS level messes. - */ -void osxGraphicsWindow:: -release_system_resources(bool destructing) { - if (_is_fullscreen) { - _is_fullscreen = false; - full_screen_window = NULL; - - if (_originalMode != NULL) { - CGDisplaySwitchToMode(kCGDirectMainDisplay, _originalMode); - } - - CGDisplayRelease(kCGDirectMainDisplay); - aglSetDrawable(get_gsg_context(), NULL); - - _originalMode = NULL; - } - - // if the gsg context is assigned to this window clear it.. - if (_osx_window != NULL && GetWindowPort (_osx_window) == (GrafPtr)aglGetDrawable(get_gsg_context())) { - aglSetDrawable(get_gsg_context(),NULL); - } - - // if we are the active gl context clear it.. - if (aglGetCurrentContext() == get_gsg_context()) { - aglSetCurrentContext(NULL); - } - - if (_osx_window != NULL) { - SetWRefCon(_osx_window, (long int) NULL); - HideWindow(_osx_window); - DisposeWindow(_osx_window); - _osx_window = NULL; - } - - if (_holder_aglcontext) { - aglDestroyContext(_holder_aglcontext); - _holder_aglcontext = NULL; - } - - if (_pending_icon != NULL) { - CGImageRelease(_pending_icon); - _pending_icon = NULL; - } - - if (_current_icon != NULL) { - CGImageRelease(_current_icon); - _current_icon = NULL; - } - - if (!destructing) { - WindowProperties properties; - properties.set_foreground(false); - properties.set_open(false); - properties.set_cursor_filename(Filename()); - system_changed_properties(properties); - } - - _is_fullscreen = false; - _osx_window = NULL; -} - - -static int id_seed = 100; - -/** - * - */ -osxGraphicsWindow:: -osxGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, - const string &name, - const FrameBufferProperties &fb_prop, - const WindowProperties &win_prop, - int flags, - GraphicsStateGuardian *gsg, - GraphicsOutput *host) : - GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host), - _osx_window(NULL), - _is_fullscreen(false), - _pending_icon(NULL), - _current_icon(NULL), -#ifdef HACK_SCREEN_HASH_CONTEXT - _holder_aglcontext(NULL), -#endif - _originalMode(NULL), - _ID(id_seed++) -{ - GraphicsWindowInputDevice device = - GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard/mouse"); - _input_devices.push_back(device); - _input_devices[0].set_pointer_in_window(0, 0); - _last_key_modifiers = 0; - _last_buttons = 0; - - _cursor_hidden = false; - _display_hide_cursor = false; - _wheel_hdelta = 0; - _wheel_vdelta = 0; - - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "osxGraphicsWindow::osxGraphicsWindow() -" <<_ID << "\n"; - } -} - -/** - * - */ -osxGraphicsWindow:: -~osxGraphicsWindow() { - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "osxGraphicsWindow::~osxGraphicsWindow() -" <<_ID << "\n"; - } - - // Make sure the window callback won't come back to this (destructed) object - // any more. - if (_osx_window) { - SetWRefCon(_osx_window, (long) NULL); - } - - release_system_resources(true); -} - -/** - * Helper to decide whitch context to use if any - */ -AGLContext osxGraphicsWindow:: -get_context() { - if (_holder_aglcontext != NULL) { - return _holder_aglcontext; - } - - return get_gsg_context(); -} - -/** - * - */ -AGLContext osxGraphicsWindow:: -get_gsg_context() { - if (_gsg != NULL) { - osxGraphicsStateGuardian *osxgsg = NULL; - osxgsg = DCAST(osxGraphicsStateGuardian, _gsg); - return osxgsg->get_context(); - } - return NULL; -} - -/** - * Code of the class.. used to control the GL context Allocation. - */ -OSStatus osxGraphicsWindow:: -build_gl(bool full_screen) { - // make sure the gsg is up and runnig.. - osxGraphicsStateGuardian *osxgsg = NULL; - osxgsg = DCAST(osxGraphicsStateGuardian, _gsg); - OSStatus stat = osxgsg->build_gl(full_screen, false, _fb_properties); - - if (stat != noErr) { - return stat; - } - - OSStatus err = noErr; - - if (osxgsg->get_agl_pixel_format()) { - _holder_aglcontext = aglCreateContext(osxgsg->get_agl_pixel_format(), NULL); - - err = report_agl_error("aglCreateContext"); - if (_holder_aglcontext == NULL) { - osxdisplay_cat.error() - << "osxGraphicsWindow::build_gl Error aglCreateContext \n"; - if (err ==noErr) { - err = -1; - } - } else { - aglSetInteger(_holder_aglcontext, AGL_BUFFER_NAME, &osxgsg->_shared_buffer); - err = report_agl_error ("aglSetInteger AGL_BUFFER_NAME"); - } - } else { - osxdisplay_cat.error() - << "osxGraphicsWindow::build_gl Error Getting PixelFormat \n"; - if (err ==noErr) { - err = -1; - } - } - return err; -} - -/** - * Called internally to load up an icon file that should be applied to the - * window. Returns true on success, false on failure. - */ -bool osxGraphicsWindow:: -set_icon_filename(const Filename &icon_filename) { - VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); - - Filename icon_pathname = icon_filename; - if (!vfs->resolve_filename(icon_pathname, get_model_path())) { - // The filename doesn't exist along the search path. - if (icon_pathname.is_fully_qualified() && vfs->exists(icon_pathname)) { - // But it does exist locally, so accept it. - - } else { - osxdisplay_cat.warning() - << "Could not find icon filename " << icon_filename << "\n"; - return false; - } - } - - - PNMImage pnmimage; - if (!pnmimage.read(icon_pathname)) { - osxdisplay_cat.warning() - << "Could not read icon filename " << icon_pathname << "\n"; - return false; - } - - CGImageRef icon_image = osxGraphicsPipe::create_cg_image(pnmimage); - if (icon_image == NULL) { - return false; - } - - if (_pending_icon != NULL) { - CGImageRelease(_pending_icon); - _pending_icon = NULL; - } - _pending_icon = icon_image; - return true; -} - -/** - * Indicates the mouse pointer is seen within the window. - */ -void osxGraphicsWindow:: -set_pointer_in_window(int x, int y) { - _input_devices[0].set_pointer_in_window(x, y); - - if (_cursor_hidden != _display_hide_cursor) { - if (_cursor_hidden) { - CGDisplayHideCursor(kCGDirectMainDisplay); - _display_hide_cursor = true; - } else { - CGDisplayShowCursor(kCGDirectMainDisplay); - _display_hide_cursor = false; - } - } -} - -/** - * Indicates the mouse pointer is no longer within the window. - */ -void osxGraphicsWindow:: -set_pointer_out_of_window() { - _input_devices[0].set_pointer_out_of_window(); - - if (_display_hide_cursor) { - CGDisplayShowCursor(kCGDirectMainDisplay); - _display_hide_cursor = false; - } -} - - -/** - * 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 osxGraphicsWindow:: -begin_frame(FrameMode mode, Thread *current_thread) { - PStatTimer timer(_make_current_pcollector); - - begin_frame_spam(mode); - if (_gsg == (GraphicsStateGuardian *)NULL || - (_osx_window == NULL && !_is_fullscreen)) { - // not powered up .. just abort.. - return false; - } - - // Now is a good time to apply the icon change that may have recently been - // requested. By this point, we should be able to get a handle to the dock - // context. - if (_pending_icon != NULL) { - CGContextRef context = BeginCGContextForApplicationDockTile(); - if (context != NULL) { - SetApplicationDockTileImage(_pending_icon); - EndCGContextForApplicationDockTile(context); - - if (_current_icon != NULL) { - CGImageRelease(_current_icon); - _current_icon = NULL; - } - _current_icon = _pending_icon; - _pending_icon = NULL; - } - } - - if (_is_fullscreen) { - aglSetFullScreen(get_gsg_context(),0,0,0,0); - report_agl_error ("aglSetFullScreen"); - - } else { - if (full_screen_window != NULL) { - return false; - } - - if (!aglSetDrawable(get_gsg_context(), GetWindowPort (_osx_window))) { - report_agl_error("aglSetDrawable"); - } - } - - if (!aglSetCurrentContext(get_gsg_context())) { - report_agl_error ("aglSetCurrentContext"); - } - - _gsg->reset_if_new(); - _gsg->set_current_properties(&get_fb_properties()); - - return _gsg->begin_frame(current_thread); -} - -/** - * This function will be called within the draw thread after rendering is - * completed for a given frame. It should do whatever finalization is - * required. - */ -void osxGraphicsWindow:: -end_frame(FrameMode mode, Thread *current_thread) { - end_frame_spam(mode); - - if (mode == FM_render) { - nassertv(_gsg != (GraphicsStateGuardian *)NULL); - - copy_to_textures(); - - if (!_properties.get_fixed_size() && - !_properties.get_undecorated() && - !_properties.get_fullscreen() && - show_resize_box) { - // Draw a kludgey little resize box in the corner of the window, so the - // user knows he's supposed to be able to drag the window if he wants. - DisplayRegionPipelineReader dr_reader(_overlay_display_region, current_thread); - _gsg->prepare_display_region(&dr_reader); - DCAST(osxGraphicsStateGuardian, _gsg)->draw_resize_box(); - } - - aglSwapBuffers (get_gsg_context()); - _gsg->end_frame(current_thread); - } -} - -/** - * 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 osxGraphicsWindow:: -end_flip() { - // cerr << " end_flip [" << _ID << "]\n"; -} - -void osxGraphicsWindow:: -begin_flip() { - // this forces a rip to proper context cerr << " begin_flip [" << _ID << - // "]\n"; - return; - - if (_is_fullscreen) { - if (!aglSetFullScreen(get_gsg_context(),0,0,0,0)) { - report_agl_error("aglSetFullScreen"); - } - - if (!aglSetCurrentContext(get_gsg_context())) { - report_agl_error("aglSetCurrentContext"); - } - - aglSwapBuffers (get_gsg_context()); - } else { - if (!aglSetDrawable (get_gsg_context(),GetWindowPort (_osx_window))) { - report_agl_error("aglSetDrawable"); - } - - if (!aglSetCurrentContext(get_gsg_context())) { - report_agl_error("aglSetCurrentContext"); - } - - aglSwapBuffers (get_gsg_context()); - } -} - -/** - * Closes the window right now. Called from the window thread. - */ -void osxGraphicsWindow:: -close_window() { - system_close_window(); - - WindowProperties properties; - properties.set_open(false); - system_changed_properties(properties); - - release_system_resources(false); - _gsg.clear(); - GraphicsWindow::close_window(); -} - -/* - * HACK ALLERT ************ Undocumented OSX calls... I can not find any other - * way to get the mouse focus to a window in OSX.. extern "C" { struct - * CPSProcessSerNum { UInt32 lo; UInt32 hi; }; - */ - -// extern OSErr CPSGetCurrentProcess(CPSProcessSerNum *psn); extern OSErr -// CPSEnableForegroundOperation(struct CPSProcessSerNum *psn); extern OSErr -// CPSSetProcessName (struct CPSProcessSerNum *psn, char *processname); extern -// OSErr CPSSetFrontProcess(struct CPSProcessSerNum *psn); }; - -/** - * 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 osxGraphicsWindow:: -open_window() { - WindowProperties req_properties = _properties; - - if (_gsg == 0) { - _gsg = new osxGraphicsStateGuardian(_engine, _pipe, NULL); - } - - // osx_global_mutex().lock(); - bool answer = os_open_window(req_properties); - // osx_global_mutex().release(); - return answer; -} - -/** - * Actually makes the OS calls to open a window. - */ -bool osxGraphicsWindow:: -os_open_window(WindowProperties &req_properties) { - OSErr err = noErr; - - if (_current_icon != NULL && _pending_icon == NULL) { - // If we already have an icon specified, we'll need to reapply it when the - // window is successfully created. - _pending_icon = _current_icon; - _current_icon = NULL; - } - - static bool GlobalInits = false; - if (!GlobalInits) { - // one time aplication inits.. to get a window open from a standalone - // aplication.. - - EventHandlerRef application_event_ref_ref1; - EventTypeSpec list1[] = { - // { kEventClassCommand, kEventProcessCommand }, { kEventClassCommand, - // kEventCommandUpdateStatus }, - { kEventClassMouse, kEventMouseDown },// handle trackball functionality globaly because there is only a single user - { kEventClassMouse, kEventMouseUp }, - { kEventClassMouse, kEventMouseMoved }, - { kEventClassMouse, kEventMouseDragged }, - { kEventClassMouse, kEventMouseWheelMoved } , - { kEventClassKeyboard, kEventRawKeyDown }, - { kEventClassKeyboard, kEventRawKeyUp } , - { kEventClassKeyboard, kEventRawKeyRepeat }, - { kEventClassKeyboard, kEventRawKeyModifiersChanged } , - { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent}, - }; - - EventHandlerUPP gEvtHandler = NewEventHandlerUPP(app_event_handler); - err = InstallApplicationEventHandler (gEvtHandler, GetEventTypeCount (list1) , list1, this, &application_event_ref_ref1); - GlobalInits = true; - - ProcessSerialNumber psn = { 0, kCurrentProcess }; - - // Determine if we're running from a bundle. - CFDictionaryRef dref = - ProcessInformationCopyDictionary(&psn, kProcessDictionaryIncludeAllInformationMask); - // If the dictionary doesn't have "BundlePath" (or the BundlePath is the - // same as the executable path), then we're not running from a bundle, and - // we need to call TransformProcessType to make the process a "foreground" - // application, with its own icon in the dock and such. - - bool has_bundle = false; - - CFStringRef bundle_path = (CFStringRef)CFDictionaryGetValue(dref, CFSTR("BundlePath")); - if (bundle_path != NULL) { - // OK, we have a bundle path. We're probably running in a bundle . . . - has_bundle = true; - - // . . . unless it turns out it's the same as the executable path. - CFStringRef exe_path = (CFStringRef)CFDictionaryGetValue(dref, kCFBundleExecutableKey); - if (exe_path != NULL) { - if (CFStringCompare(bundle_path, exe_path, kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - has_bundle = false; - } - CFRelease(exe_path); - } - - CFRelease(bundle_path); - } - - if (!has_bundle) { - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - } - SetFrontProcess(&psn); - } - - bool wants_fullscreen = req_properties.has_fullscreen() && req_properties.get_fullscreen(); - if (req_properties.get_minimized()) { - // A minimized window can't be fullscreen. - wants_fullscreen = false; - } - - if (wants_fullscreen) { - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "Creating full screen\n"; - } - - // capture the main display - CGDisplayCapture(kCGDirectMainDisplay); - // if sized try and switch it.. - if (req_properties.has_size()) { - _originalMode = CGDisplayCurrentMode(kCGDirectMainDisplay); - CFDictionaryRef newMode = CGDisplayBestModeForParameters(kCGDirectMainDisplay, 32, req_properties.get_x_size(), req_properties.get_y_size(), 0); - if (newMode == NULL) { - osxdisplay_cat.error() - << "Invalid fullscreen size: " << req_properties.get_x_size() - << ", " << req_properties.get_y_size() - << "\n"; - } else { - CGDisplaySwitchToMode(kCGDirectMainDisplay, newMode); - - // Set our new window size according to the size we actually got. - - SInt32 width, height; - CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(newMode, kCGDisplayWidth), kCFNumberSInt32Type, &width); - CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(newMode, kCGDisplayHeight), kCFNumberSInt32Type, &height); - - _properties.set_size(width, height); - } - } - - if (build_gl(true) != noErr) { - if (_originalMode != NULL) { - CGDisplaySwitchToMode(kCGDirectMainDisplay, _originalMode); - } - _originalMode = NULL; - - CGDisplayRelease(kCGDirectMainDisplay); - return false; - } - - _properties.set_fullscreen(true); - _properties.set_minimized(false); - _properties.set_foreground(true); - - _is_fullscreen = true; - full_screen_window = this; - req_properties.clear_fullscreen(); - - } else { - int x_origin = 10; - int y_origin = 50; - if (req_properties.has_origin()) { - y_origin = req_properties.get_y_origin(); - x_origin = req_properties.get_x_origin(); - } - - int x_size = 512; - int y_size = 512; - if (req_properties.has_size()) { - x_size = req_properties.get_x_size(); - y_size = req_properties.get_y_size(); - } - - // A coordinate of -2 means to center the window on screen. - if (y_origin == -2 || x_origin == -2) { - if (y_origin == -2) { - y_origin = (_pipe->get_display_height() - y_size) / 2; - } - if (x_origin == -2) { - x_origin = (_pipe->get_display_width() - x_size) / 2; - } - } - - // A coordinate of -1 means a default location. - if (y_origin == -1) { - y_origin = 50; - } - if (x_origin == -1) { - x_origin = 10; - } - - _properties.set_origin(x_origin, y_origin); - _properties.set_size(x_size, y_size); - - Rect r; - r.top = y_origin; - r.left = x_origin; - r.right = r.left + x_size; - r.bottom = r.top + y_size; - - /* - if (req_properties.has_parent_window()) { - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "Creating child window\n"; - } - - CreateNewWindow(kSimpleWindowClass, kWindowNoAttributes, &r, &_osx_window); - add_a_window(_osx_window); - - _properties.set_fixed_size(true); - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "Child window created\n"; - } - } else */ - { - int attributes = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute; - if (req_properties.has_fixed_size() && req_properties.get_fixed_size()) { - attributes &= ~kWindowResizableAttribute; - } - - if (req_properties.has_undecorated() && req_properties.get_undecorated()) { - // create a unmovable .. no edge window.. - - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "Creating undecorated window\n"; - } - - // We don't want a resize box either. - attributes &= ~kWindowResizableAttribute; - attributes |= kWindowNoTitleBarAttribute; - CreateNewWindow(kDocumentWindowClass, attributes, &r, &_osx_window); - } else { - // create a window with crome and sizing and sucj In this case, we - // want to constrain the window to the available size. - - Rect bounds; - GetAvailableWindowPositioningBounds(GetMainDevice(), &bounds); - - r.left = max(r.left, bounds.left); - r.right = min(r.right, bounds.right); - r.top = max(r.top, bounds.top); - r.bottom = min(r.bottom, bounds.bottom); - - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "Creating standard window\n"; - } - CreateNewWindow(kDocumentWindowClass, attributes, &r, &_osx_window); - add_a_window(_osx_window); - } - } - - if (_osx_window) { - EventHandlerUPP gWinEvtHandler; // window event handler - EventTypeSpec list[] = { - { kEventClassWindow, kEventWindowCollapsing }, - { kEventClassWindow, kEventWindowShown }, - { kEventClassWindow, kEventWindowActivated }, - { kEventClassWindow, kEventWindowDeactivated }, - { kEventClassWindow, kEventWindowClose }, - { kEventClassWindow, kEventWindowBoundsChanging }, - { kEventClassWindow, kEventWindowBoundsChanged }, - - { kEventClassWindow, kEventWindowCollapsed }, - { kEventClassWindow, kEventWindowExpanded }, - { kEventClassWindow, kEventWindowZoomed }, - { kEventClassWindow, kEventWindowClosed }, - }; - - // point to the window record in the ref con of the window - SetWRefCon(_osx_window, (long) this); - gWinEvtHandler = NewEventHandlerUPP(window_event_handler); - InstallWindowEventHandler(_osx_window, gWinEvtHandler, GetEventTypeCount(list), list, (void*)this, NULL); // add event handler - - ShowWindow (_osx_window); - - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "Event handler installed, now build_gl\n"; - } - if (build_gl(false) != noErr) { - osxdisplay_cat.error() - << "Error in build_gl\n"; - - HideWindow(_osx_window); - SetWRefCon(_osx_window, (long int) NULL); - DisposeWindow(_osx_window); - _osx_window = NULL; - return false; - } - - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "build_gl complete, set properties\n"; - } - - // attach the holder context to the window.. - - if (!aglSetDrawable(_holder_aglcontext, GetWindowPort(_osx_window))) { - err = report_agl_error("aglSetDrawable"); - } - - if (req_properties.has_fullscreen()) { - _properties.set_fullscreen(false); - req_properties.clear_fullscreen(); - } - - if (req_properties.has_undecorated()) { - _properties.set_undecorated(req_properties.get_undecorated()); - req_properties.clear_undecorated(); - } - - _properties.set_minimized(false); - _properties.set_foreground(true); - - if (req_properties.has_minimized()) { - CollapseWindow(_osx_window, req_properties.get_minimized()); - _properties.set_minimized(req_properties.get_minimized()); - _properties.set_foreground(!req_properties.get_minimized()); - req_properties.clear_minimized(); - } - } - - // Now measure the size and placement of the window we actually ended up - // with. - Rect rectPort = {0,0,0,0}; - GetWindowPortBounds (_osx_window, &rectPort); - _properties.set_size((int)(rectPort.right - rectPort.left),(int) (rectPort.bottom - rectPort.top)); - req_properties.clear_size(); - req_properties.clear_origin(); - } - - if (req_properties.has_icon_filename()) { - set_icon_filename(req_properties.get_icon_filename()); - } - - if (req_properties.has_cursor_hidden()) { - _properties.set_cursor_hidden(req_properties.get_cursor_hidden()); - _cursor_hidden = req_properties.get_cursor_hidden(); - if (_cursor_hidden) { - if (!_display_hide_cursor) { - CGDisplayHideCursor(kCGDirectMainDisplay); - _display_hide_cursor = true; - } - } else { - if (_display_hide_cursor) { - CGDisplayShowCursor(kCGDirectMainDisplay); - _display_hide_cursor = false; - } - } - req_properties.clear_cursor_hidden(); - } - - _properties.set_open(true); - - if (_properties.has_size()) { - set_size_and_recalc(_properties.get_x_size(), _properties.get_y_size()); - } - - return (err == noErr); -} - -/** - * Required event upcall, used to dispatch window and application events back - * into panda. - */ -void osxGraphicsWindow:: -process_events() { - GraphicsWindow::process_events(); - - if (!osx_disable_event_loop) { - EventRef theEvent; - EventTargetRef theTarget = GetEventDispatcherTarget(); - - /*if (!_properties.has_parent_window()) */ { - while (ReceiveNextEvent(0, NULL, kEventDurationNoWait, true, &theEvent)== noErr) { - SendEventToEventTarget (theEvent, theTarget); - ReleaseEvent(theEvent); - } - } - } -} - -/** - * Required event upcall, used to dispatch window and application events back - * into panda. - */ -OSStatus osxGraphicsWindow:: -handle_key_input(EventHandlerCallRef my_handler, EventRef event, - Boolean key_down) { - if (osxdisplay_cat.is_debug()) { - UInt32 key_code; - GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, - sizeof(UInt32), NULL, &key_code); - - osxdisplay_cat.debug() - << ClockObject::get_global_clock()->get_real_time() - << " handle_key_input: " << (void *)this << ", " << key_code - << ", " << (int)key_down << "\n"; - } - - // CallNextEventHandler(my_handler, event); - - // We don't check the result of the above function. In principle, this - // should return eventNotHandledErr if the key event is not handled by the - // OS, but in practice, testing this just seems to eat the Escape keypress - // meaninglessly. Keypresses like F11 that are already mapped in the - // desktop seem to not even come into this function in the first place. - UInt32 new_modifiers = 0; - OSStatus error = GetEventParameter(event, kEventParamKeyModifiers, - typeUInt32, NULL, sizeof(UInt32), - NULL, &new_modifiers); - if (error == noErr) { - handle_modifier_delta(new_modifiers); - } - - UInt32 key_code; - GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, - sizeof(UInt32), NULL, &key_code); - ButtonHandle button = osx_translate_key(key_code, event); - - if (key_down) { - if ((new_modifiers & cmdKey) != 0) { - if (button == KeyboardButton::ascii_key("q") || - button == KeyboardButton::ascii_key("w")) { - // Command-Q or Command-W: quit the application or close the window, - // respectively. For now, we treat them both the same: close the - // window. - user_close_request(); - } - } - send_key_event(button, true); - } else { - send_key_event(button, false); - } - - return CallNextEventHandler(my_handler, event); - // return noErr; -} - -/** - * - */ -void osxGraphicsWindow:: -system_set_window_foreground(bool foreground) { - WindowProperties properties; - properties.set_foreground(foreground); - system_changed_properties(properties); -} - -/** - * - */ -void osxGraphicsWindow:: -system_point_to_local_point(Point &global_point) { - if (_osx_window != NULL) { - GrafPtr savePort; - Boolean port_changed = QDSwapPort(GetWindowPort(_osx_window), &savePort); - - GlobalToLocal(&global_point); - - if (port_changed) { - QDSwapPort(savePort, NULL); - } - } -} - -/** - * - */ -OSStatus osxGraphicsWindow:: -handle_window_mouse_events(EventHandlerCallRef my_handler, EventRef event) { - WindowRef window = NULL; - OSStatus result = eventNotHandledErr; - UInt32 kind = GetEventKind(event); - EventMouseButton button = 0; - Point global_point = {0, 0}; - UInt32 modifiers = 0; - Rect rect_port; - SInt32 this_wheel_delta; - EventMouseWheelAxis wheelAxis; - - // cerr <<" Start Mouse Event " << _ID << "\n"; - - // Mac OS X v10.1 and later should this be front window??? - GetEventParameter(event, kEventParamWindowRef, typeWindowRef, NULL, - sizeof(WindowRef), NULL, &window); - - if (!_is_fullscreen && (window == NULL || window != _osx_window)) { - if (kind == kEventMouseMoved) { - set_pointer_out_of_window(); - } - return eventNotHandledErr; - } - - GetWindowPortBounds(window, &rect_port); - - // result = CallNextEventHandler(my_handler, event); if (eventNotHandledErr - // == result) - { // only handle events not already handled (prevents weird resize interaction) - switch (kind) { - // Whenever mouse button state changes, generate the appropriate Panda - // downup events to represent the change. - - case kEventMouseDown: - case kEventMouseUp: - { - GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); - if (_properties.get_mouse_mode() == WindowProperties::M_relative) { - HIPoint delta; - GetEventParameter(event, kEventParamMouseDelta, typeHIPoint, NULL, sizeof(HIPoint), NULL, (void*) &delta); - - MouseData currMouse = get_pointer(0); - delta.x += currMouse.get_x(); - delta.y += currMouse.get_y(); - set_pointer_in_window((int)delta.x, (int)delta.y); - } else { - GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL , (void*) &global_point); - system_point_to_local_point(global_point); - set_pointer_in_window((int)global_point.h, (int)global_point.v); - } - - UInt32 new_buttons = GetCurrentEventButtonState(); - handle_button_delta(new_buttons); - } - result = noErr; - break; - - case kEventMouseMoved: - case kEventMouseDragged: - if (_properties.get_mouse_mode() == WindowProperties::M_relative) { - HIPoint delta; - GetEventParameter(event, kEventParamMouseDelta, typeHIPoint, NULL, sizeof(HIPoint), NULL, (void*) &delta); - - MouseData currMouse = get_pointer(0); - delta.x += currMouse.get_x(); - delta.y += currMouse.get_y(); - set_pointer_in_window((int)delta.x, (int)delta.y); - } else { - GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, (void*) &global_point); - system_point_to_local_point(global_point); - - if (kind == kEventMouseMoved && - (global_point.h < 0 || global_point.v < 0)) { - // Moving into the titlebar region. - set_pointer_out_of_window(); - } else { - // Moving within the window itself (or dragging anywhere). - set_pointer_in_window((int)global_point.h, (int)global_point.v); - } - } - result = noErr; - break; - - case kEventMouseWheelMoved: - GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(this_wheel_delta), NULL, &this_wheel_delta); - GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(wheelAxis), NULL, &wheelAxis); - GetEventParameter(event, kEventParamMouseLocation,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &global_point); - system_point_to_local_point(global_point); - - if (wheelAxis == kEventMouseWheelAxisX) { - set_pointer_in_window((int)global_point.h, (int)global_point.v); - _wheel_hdelta += this_wheel_delta; - SInt32 wheel_scale = osx_mouse_wheel_scale; - while (_wheel_hdelta > wheel_scale) { - _input_devices[0].button_down(MouseButton::wheel_left()); - _input_devices[0].button_up(MouseButton::wheel_left()); - _wheel_hdelta -= wheel_scale; - } - while (_wheel_hdelta < -wheel_scale) { - _input_devices[0].button_down(MouseButton::wheel_right()); - _input_devices[0].button_up(MouseButton::wheel_right()); - _wheel_hdelta += wheel_scale; - } - } - if (wheelAxis == kEventMouseWheelAxisY) { - set_pointer_in_window((int)global_point.h, (int)global_point.v); - _wheel_vdelta += this_wheel_delta; - SInt32 wheel_scale = osx_mouse_wheel_scale; - while (_wheel_vdelta > wheel_scale) { - _input_devices[0].button_down(MouseButton::wheel_up()); - _input_devices[0].button_up(MouseButton::wheel_up()); - _wheel_vdelta -= wheel_scale; - } - while (_wheel_vdelta < -wheel_scale) { - _input_devices[0].button_down(MouseButton::wheel_down()); - _input_devices[0].button_up(MouseButton::wheel_down()); - _wheel_vdelta += wheel_scale; - } - } - result = noErr; - break; - } - // result = noErr; - } - - return result; -} - -/** - * MAC Key Codes to Panda Key Codes - */ -ButtonHandle osxGraphicsWindow:: -osx_translate_key(UInt32 key, EventRef event) { - ButtonHandle nk = ButtonHandle::none(); - switch (key) { - case 0: nk = KeyboardButton::ascii_key('a'); break; - case 11: nk = KeyboardButton::ascii_key('b'); break; - case 8: nk = KeyboardButton::ascii_key('c'); break; - case 2: nk = KeyboardButton::ascii_key('d'); break; - case 14: nk = KeyboardButton::ascii_key('e'); break; - case 3: nk = KeyboardButton::ascii_key('f'); break; - case 5: nk = KeyboardButton::ascii_key('g'); break; - case 4: nk = KeyboardButton::ascii_key('h'); break; - case 34: nk = KeyboardButton::ascii_key('i'); break; - case 38: nk = KeyboardButton::ascii_key('j'); break; - case 40: nk = KeyboardButton::ascii_key('k'); break; - case 37: nk = KeyboardButton::ascii_key('l'); break; - case 46: nk = KeyboardButton::ascii_key('m'); break; - case 45: nk = KeyboardButton::ascii_key('n'); break; - case 31: nk = KeyboardButton::ascii_key('o'); break; - case 35: nk = KeyboardButton::ascii_key('p'); break; - case 12: nk = KeyboardButton::ascii_key('q'); break; - case 15: nk = KeyboardButton::ascii_key('r'); break; - case 1: nk = KeyboardButton::ascii_key('s'); break; - case 17: nk = KeyboardButton::ascii_key('t'); break; - case 32: nk = KeyboardButton::ascii_key('u'); break; - case 9: nk = KeyboardButton::ascii_key('v'); break; - case 13: nk = KeyboardButton::ascii_key('w'); break; - case 7: nk = KeyboardButton::ascii_key('x'); break; - case 16: nk = KeyboardButton::ascii_key('y'); break; - case 6: nk = KeyboardButton::ascii_key('z'); break; - - // top row numbers - case 29: nk = KeyboardButton::ascii_key('0'); break; - case 18: nk = KeyboardButton::ascii_key('1'); break; - case 19: nk = KeyboardButton::ascii_key('2'); break; - case 20: nk = KeyboardButton::ascii_key('3'); break; - case 21: nk = KeyboardButton::ascii_key('4'); break; - case 23: nk = KeyboardButton::ascii_key('5'); break; - case 22: nk = KeyboardButton::ascii_key('6'); break; - case 26: nk = KeyboardButton::ascii_key('7'); break; - case 28: nk = KeyboardButton::ascii_key('8'); break; - case 25: nk = KeyboardButton::ascii_key('9'); break; - - // key pad ... do they really map to the top number in panda ? - case 82: nk = KeyboardButton::ascii_key('0'); break; - case 83: nk = KeyboardButton::ascii_key('1'); break; - case 84: nk = KeyboardButton::ascii_key('2'); break; - case 85: nk = KeyboardButton::ascii_key('3'); break; - case 86: nk = KeyboardButton::ascii_key('4'); break; - case 87: nk = KeyboardButton::ascii_key('5'); break; - case 88: nk = KeyboardButton::ascii_key('6'); break; - case 89: nk = KeyboardButton::ascii_key('7'); break; - case 91: nk = KeyboardButton::ascii_key('8'); break; - case 92: nk = KeyboardButton::ascii_key('9'); break; - - // case 36: nk = KeyboardButton::ret(); break; no return in panda ??? - case 49: nk = KeyboardButton::space(); break; - case 51: nk = KeyboardButton::backspace(); break; - case 48: nk = KeyboardButton::tab(); break; - case 53: nk = KeyboardButton::escape(); break; - case 76: nk = KeyboardButton::enter(); break; - case 36: nk = KeyboardButton::enter(); break; - - case 123: nk = KeyboardButton::left(); break; - case 124: nk = KeyboardButton::right(); break; - case 125: nk = KeyboardButton::down(); break; - case 126: nk = KeyboardButton::up(); break; - case 116: nk = KeyboardButton::page_up(); break; - case 121: nk = KeyboardButton::page_down(); break; - case 115: nk = KeyboardButton::home(); break; - case 119: nk = KeyboardButton::end(); break; - case 114: nk = KeyboardButton::help(); break; - case 117: nk = KeyboardButton::del(); break; - - // case 71: nk = KeyboardButton::num_lock() break; - - case 122: nk = KeyboardButton::f1(); break; - case 120: nk = KeyboardButton::f2(); break; - case 99: nk = KeyboardButton::f3(); break; - case 118: nk = KeyboardButton::f4(); break; - case 96: nk = KeyboardButton::f5(); break; - case 97: nk = KeyboardButton::f6(); break; - case 98: nk = KeyboardButton::f7(); break; - case 100: nk = KeyboardButton::f8(); break; - case 101: nk = KeyboardButton::f9(); break; - case 109: nk = KeyboardButton::f10(); break; - case 103: nk = KeyboardButton::f11(); break; - case 111: nk = KeyboardButton::f12(); break; - - case 105: nk = KeyboardButton::f13(); break; - case 107: nk = KeyboardButton::f14(); break; - case 113: nk = KeyboardButton::f15(); break; - case 106: nk = KeyboardButton::f16(); break; - - // shiftable chartablet - case 50: nk = KeyboardButton::ascii_key('`'); break; - case 27: nk = KeyboardButton::ascii_key('-'); break; - case 24: nk = KeyboardButton::ascii_key('='); break; - case 33: nk = KeyboardButton::ascii_key('['); break; - case 30: nk = KeyboardButton::ascii_key(']'); break; - case 42: nk = KeyboardButton::ascii_key('\\'); break; - case 41: nk = KeyboardButton::ascii_key(';'); break; - case 39: nk = KeyboardButton::ascii_key('\''); break; - case 43: nk = KeyboardButton::ascii_key(','); break; - case 47: nk = KeyboardButton::ascii_key('.'); break; - case 44: nk = KeyboardButton::ascii_key('/'); break; - - default: - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << " Untranslated KeyCode: " << key - << " (0x" << hex << key << dec << ")\n"; - } - - // not sure this is right .. but no mapping for keypad and such this at - // least does a best gess.. - - char charCode = 0; - if (GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, nil, sizeof(charCode), nil, &charCode) == noErr) { - nk = KeyboardButton::ascii_key(charCode); - } - } - return nk; -} - -/** - * Used to emulate key events for the MAC key modifiers. - */ -void osxGraphicsWindow:: -handle_modifier_delta(UInt32 new_modifiers) { - UInt32 changed = _last_key_modifiers ^ new_modifiers; - - if ((changed & (shiftKey | rightShiftKey)) != 0) { - send_key_event(KeyboardButton::shift(),(new_modifiers & (shiftKey | rightShiftKey)) != 0) ; - } - - if ((changed & (optionKey | rightOptionKey)) != 0) { - send_key_event(KeyboardButton::alt(),(new_modifiers & (optionKey | rightOptionKey)) != 0); - } - - if ((changed & (controlKey | rightControlKey)) != 0) { - send_key_event(KeyboardButton::control(),(new_modifiers & (controlKey | rightControlKey)) != 0); - } - - if ((changed & cmdKey) != 0) { - send_key_event(KeyboardButton::meta(),(new_modifiers & cmdKey) != 0); - } - - if ((changed & alphaLock) != 0) { - send_key_event(KeyboardButton::caps_lock(),(new_modifiers & alphaLock) != 0); - } - - // save current state - _last_key_modifiers = new_modifiers; -} - -/** - * Used to emulate button events - */ -void osxGraphicsWindow:: -handle_button_delta(UInt32 new_buttons) { - UInt32 changed = _last_buttons ^ new_buttons; - - if (changed & 0x01) { - if (new_buttons & 0x01) { - _input_devices[0].button_down(MouseButton::one()); - } else { - _input_devices[0].button_up(MouseButton::one()); - } - } - - if (changed & 0x04) { - if (new_buttons & 0x04) { - _input_devices[0].button_down(MouseButton::two()); - } else { - _input_devices[0].button_up(MouseButton::two()); - } - } - - if (changed & 0x02) { - if (new_buttons & 0x02) { - _input_devices[0].button_down(MouseButton::three()); - } else { - _input_devices[0].button_up(MouseButton::three()); - } - } - - _last_buttons = new_buttons; -} - -/** - * Forces the pointer to the indicated position within the window, if - * possible. - * - * Returns true if successful, false on failure. This may fail if the mouse - * is not currently within the window, or if the API doesn't support this - * operation. - */ -bool osxGraphicsWindow:: -move_pointer(int device, int x, int y) { - if (_osx_window == NULL) { - return false; - } - - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "move_pointer " << device <<" "<< x <<" "<< y <<"\n"; - } - - Point pt = { 0, 0 }; - pt.h = x; - pt.v = y; - set_pointer_in_window(x, y); - - if (_properties.get_mouse_mode() == WindowProperties::M_absolute) { - local_point_to_system_point(pt); - CGPoint new_position = { 0, 0 }; - new_position.x = pt.h; - new_position.y = pt.v; - mouse_mode_relative(); - CGWarpMouseCursorPosition(new_position); - mouse_mode_absolute(); - } - - return true; -} - -/** - * - */ -bool osxGraphicsWindow:: -do_reshape_request(int x_origin, int y_origin, bool has_origin, - int x_size, int y_size) { - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "Do Reshape\n"; - } - - if (_properties.get_fullscreen()) { - return false; - } - - // A coordinate of -2 means to center the window on screen. - if (x_origin == -2 || y_origin == -2 || x_origin == -1 || y_origin == -1) { - if (y_origin == -2) { - y_origin = (_pipe->get_display_height() - y_size) / 2; - } - if (x_origin == -2) { - x_origin = (_pipe->get_display_width() - x_size) / 2; - } - if (y_origin == -1) { - y_origin = 50; - } - if (x_origin == -1) { - x_origin = 10; - } - _properties.set_origin(x_origin, y_origin); - system_changed_properties(_properties); - } - - /* - if (_properties.has_parent_window()) { - if (has_origin) { - NSWindow* parentWindow = (NSWindow *)_properties.get_parent_window(); - NSRect parentFrame = [parentWindow frame]; - - MoveWindow(_osx_window, x_origin+parentFrame.origin.x, y_origin+parentFrame.origin.y, false); - } - } else */ - { - // We sometimes get a bogus origin of (0, 0). As a special hack, treat - // this as a special case, and ignore it. - if (has_origin) { - if (x_origin != 0 || y_origin != 0) { - MoveWindow(_osx_window, x_origin, y_origin, false); - } - } - } - - if (!_properties.get_undecorated()) { - // Constrain the window to the available desktop size. - Rect bounds; - GetAvailableWindowPositioningBounds(GetMainDevice(), &bounds); - - x_size = min(x_size, bounds.right - bounds.left); - y_size = min(y_size, bounds.bottom - bounds.top); - } - - SizeWindow(_osx_window, x_size, y_size, false); - - system_changed_size(x_size, y_size); - return true; -} - -/** - * Applies the requested set of properties to the window, if possible, for - * instance to request a change in size or minimization status. - * - * The window properties are applied immediately, rather than waiting until - * the next frame. This implies that this method may *only* be called from - * within the window thread. - * - * The properties that have been applied are cleared from the structure by - * this function; so on return, whatever remains in the properties structure - * are those that were unchanged for some reason (probably because the - * underlying interface does not support changing that property on an open - * window). - */ -void osxGraphicsWindow:: -set_properties_now(WindowProperties &properties) { - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "------------------------------------------------------\n"; - osxdisplay_cat.debug() - << "set_properties_now " << properties << "\n"; - } - - GraphicsWindow::set_properties_now(properties); - - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "set_properties_now After Base Class" << properties << "\n"; - } - - // for some changes .. a full rebuild is required for the OS layer Window. - // I think it is the chrome attribute and full screen behaviour. - bool need_full_rebuild = false; - - // if we are not full and transitioning to full - if (properties.has_fullscreen() && - properties.get_fullscreen() != _properties.get_fullscreen()) { - need_full_rebuild = true; - } - - // If we are fullscreen and requesting a size change - if (_properties.get_fullscreen() && - (properties.has_size() && - (properties.get_x_size() != _properties.get_x_size() || - properties.get_y_size() != _properties.get_y_size()))) { - need_full_rebuild = true; - } - - // If we are fullscreen and requesting a minimize change - if (_properties.get_fullscreen() && - (properties.has_minimized() && - (properties.get_minimized() != _properties.get_minimized()))) { - need_full_rebuild = true; - } - - if (need_full_rebuild) { - // Logic here is .. take a union of the properties .. with the new allowed - // to overwrite the old states. and start a bootstrap of a new window .. - - // get a copy of my properties.. - WindowProperties req_properties(_properties); - release_system_resources(false); - req_properties.add_properties(properties); - - os_open_window(req_properties); - - // Now we've handled all of the requested properties. - properties.clear(); - } - - if (properties.has_title()) { - _properties.set_title(properties.get_title()); - - if (_osx_window) { - SetWindowTitleWithCFString(_osx_window, - CFStringCreateWithCString(NULL,properties.get_title().c_str(), - kCFStringEncodingMacRoman)); - } - properties.clear_title(); - } - - // An icon filename means to load up the icon and save it. We can't - // necessarily apply it immediately; it will get applied later, in the - // window event handler. - if (properties.has_icon_filename()) { - if (set_icon_filename(properties.get_icon_filename())) { - properties.clear_icon_filename(); - } - } - - // decorated .. if this changes it reqires a new window - if (properties.has_undecorated()) { - _properties.set_undecorated(properties.get_undecorated()); - properties.clear_undecorated(); - } - - if (properties.has_cursor_hidden()) { - _properties.set_cursor_hidden(properties.get_cursor_hidden()); - _cursor_hidden = properties.get_cursor_hidden(); - if (_cursor_hidden) { - if (!_display_hide_cursor) { - CGDisplayHideCursor(kCGDirectMainDisplay); - _display_hide_cursor = true; - } - } else { - if (_display_hide_cursor) { - CGDisplayShowCursor(kCGDirectMainDisplay); - _display_hide_cursor = false; - } - } - properties.clear_cursor_hidden(); - } - - if (properties.has_minimized()) { - if (_properties.get_minimized() != properties.get_minimized()) { - CollapseWindow(_osx_window, properties.get_minimized()); - _properties.set_minimized(properties.get_minimized()); - _properties.set_foreground(!properties.get_minimized()); - } - properties.clear_minimized(); - } - - if (properties.has_mouse_mode()) { - switch (properties.get_mouse_mode()) { - case WindowProperties::M_absolute: - CGAssociateMouseAndMouseCursorPosition(true); - _properties.set_mouse_mode(WindowProperties::M_absolute); - properties.clear_mouse_mode(); - break; - - case WindowProperties::M_relative: - CGAssociateMouseAndMouseCursorPosition(false); - _properties.set_mouse_mode(WindowProperties::M_relative); - properties.clear_mouse_mode(); - break; - - case WindowProperties::M_confined: - break; - } - } - - if (osxdisplay_cat.is_debug()) { - osxdisplay_cat.debug() - << "set_properties_now Out....." << _properties << "\n"; - } - - return; -} - -/** - * - */ -void osxGraphicsWindow:: -local_point_to_system_point(Point &local_point) { - if (_osx_window != NULL) { - GrafPtr save_port; - Boolean port_changed = QDSwapPort(GetWindowPort(_osx_window), &save_port); - - LocalToGlobal(&local_point); - - if (port_changed) { - QDSwapPort(save_port, NULL); - } - } -} - -/** - * detaches mouse. Only mouse delta from now on. - */ -void osxGraphicsWindow:: -mouse_mode_relative() { - CGAssociateMouseAndMouseCursorPosition(false); -} - - -/** - * reattaches mouse to location - */ -void osxGraphicsWindow:: -mouse_mode_absolute() { - CGAssociateMouseAndMouseCursorPosition(true); -} diff --git a/panda/src/osxdisplay/p3osxdisplay_composite1.cxx b/panda/src/osxdisplay/p3osxdisplay_composite1.cxx deleted file mode 100644 index 6247d97d78..0000000000 --- a/panda/src/osxdisplay/p3osxdisplay_composite1.cxx +++ /dev/null @@ -1,4 +0,0 @@ -#include "config_osxdisplay.cxx" -#include "osxGraphicsBuffer.cxx" -#include "osxGraphicsPipe.cxx" -#include "osxGraphicsStateGuardian.cxx" diff --git a/panda/src/osxdisplay/resize_box.rgb b/panda/src/osxdisplay/resize_box.rgb deleted file mode 100644 index 216efe10d944df87b9b5c3360b889942a2381e68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1683 zcmeIyzb`{k6u|NOydV9A7Kub876XgKA`y$QS`1b!W{FJQ|(ay&f~K59|>-~5Ra2nxmolg9XO zIKu{JkTJ%4!a2%V!7RoxgidfmK?!qU;9p`F^BCasS6tu_t02ysz%Y8?lDCf~^po?5 zBP?Tt&);#4W2|EVQy2yDUO?Uf*1(+qf)j8ppX>P4=RM#QMJ!?(V;Dq=01fIxFR00M zBOA3{v}t6bwjQrJiu!*&Uu(!kv~IqanAV+akf5*eF%sifRvdO7zcK$gu)U@;T~eqz zn$)CY3bhW3kz#ezhBWP&VojqmvQ^284g036ffSyWVkPhD6`S@nid!)y+jpBHVQDP} zX1m58o)(alQbjYuQd^Ep$tG!5LUyk5BDYcLKMd=MY$K3Tm}s}sa#YXKUzqIOP~^R` uXVu1p*$b-;x9LgQX4_Tl5^c?xa=eIc+m(H`tlN&a-sV)}LL9@_TkHc>@-x=} diff --git a/panda/src/osxdisplay/resize_box.rgb.c b/panda/src/osxdisplay/resize_box.rgb.c deleted file mode 100644 index eecce8c1e5..0000000000 --- a/panda/src/osxdisplay/resize_box.rgb.c +++ /dev/null @@ -1,167 +0,0 @@ - -/* - * This table was generated by the command: - * - * bin2c -static -string -n resize_box -o resize_box.rgb.c resize_box.rgb - */ - -#include - -static const unsigned char resize_box[] = { - 0x01, 0xda, 0x01, 0x01, 0x00, 0x03, 0x00, 0x10, 0x00, 0x10, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x81, 0x00, - 0x00, 0x06, 0x38, 0x00, 0x00, 0x05, 0xf2, 0x00, 0x00, 0x05, 0xb0, - 0x00, 0x00, 0x05, 0x7a, 0x00, 0x00, 0x05, 0x41, 0x00, 0x00, 0x05, - 0x0b, 0x00, 0x00, 0x04, 0xd9, 0x00, 0x00, 0x04, 0xb3, 0x00, 0x00, - 0x04, 0x8a, 0x00, 0x00, 0x04, 0x64, 0x00, 0x00, 0x04, 0x42, 0x00, - 0x00, 0x04, 0x30, 0x00, 0x00, 0x04, 0x1e, 0x00, 0x00, 0x04, 0x0c, - 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x86, 0x00, 0x00, 0x06, - 0x4b, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x05, 0xc1, 0x00, 0x00, - 0x05, 0x88, 0x00, 0x00, 0x05, 0x50, 0x00, 0x00, 0x05, 0x19, 0x00, - 0x00, 0x04, 0xe6, 0x00, 0x00, 0x04, 0xbd, 0x00, 0x00, 0x04, 0x95, - 0x00, 0x00, 0x04, 0x6e, 0x00, 0x00, 0x04, 0x4b, 0x00, 0x00, 0x04, - 0x35, 0x00, 0x00, 0x04, 0x23, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x00, 0x06, 0x8b, 0x00, 0x00, 0x06, 0x5e, 0x00, - 0x00, 0x06, 0x16, 0x00, 0x00, 0x05, 0xd2, 0x00, 0x00, 0x05, 0x96, - 0x00, 0x00, 0x05, 0x5f, 0x00, 0x00, 0x05, 0x27, 0x00, 0x00, 0x04, - 0xf3, 0x00, 0x00, 0x04, 0xc7, 0x00, 0x00, 0x04, 0xa0, 0x00, 0x00, - 0x04, 0x78, 0x00, 0x00, 0x04, 0x54, 0x00, 0x00, 0x04, 0x3a, 0x00, - 0x00, 0x04, 0x28, 0x00, 0x00, 0x04, 0x16, 0x00, 0x00, 0x04, 0x06, - 0x00, 0x00, 0x06, 0x90, 0x00, 0x00, 0x06, 0x71, 0x00, 0x00, 0x06, - 0x28, 0x00, 0x00, 0x05, 0xe3, 0x00, 0x00, 0x05, 0xa4, 0x00, 0x00, - 0x05, 0x6e, 0x00, 0x00, 0x05, 0x35, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x04, 0xd1, 0x00, 0x00, 0x04, 0xab, 0x00, 0x00, 0x04, 0x82, - 0x00, 0x00, 0x04, 0x5d, 0x00, 0x00, 0x04, 0x3f, 0x00, 0x00, 0x04, - 0x2d, 0x00, 0x00, 0x04, 0x1b, 0x00, 0x00, 0x04, 0x09, 0x00, 0x00, - 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, - 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, - 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, - 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, - 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, - 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, - 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, - 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, - 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, - 0x00, 0x0b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, - 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x0f, 0xec, 0x01, 0x00, 0x00, 0x0f, 0xec, 0x01, 0x00, - 0x00, 0x0f, 0xec, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0f, 0xec, - 0x01, 0x00, 0x00, 0x0f, 0xec, 0x01, 0x00, 0x00, 0x0f, 0xec, 0x01, - 0x00, 0x00, 0x10, 0x00, 0x00, 0x0f, 0xec, 0x01, 0x00, 0x00, 0x0f, - 0xec, 0x01, 0x00, 0x00, 0x0f, 0xec, 0x01, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x0d, 0xec, 0x81, 0xcf, 0x01, 0xec, 0x01, 0x00, 0x00, 0x0d, - 0xec, 0x81, 0xcf, 0x01, 0xec, 0x01, 0x00, 0x00, 0x0d, 0xec, 0x81, - 0xcf, 0x01, 0xec, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x81, 0xff, 0x02, - 0x00, 0x00, 0x0c, 0xec, 0x82, 0xcf, 0x80, 0x01, 0xec, 0x01, 0x00, - 0x00, 0x0c, 0xec, 0x82, 0xcf, 0x80, 0x01, 0xec, 0x01, 0x00, 0x00, - 0x0c, 0xec, 0x82, 0xcf, 0x80, 0x01, 0xec, 0x01, 0x00, 0x00, 0x0c, - 0x00, 0x82, 0xff, 0xff, 0x02, 0x00, 0x00, 0x0b, 0xec, 0x83, 0xca, - 0x7e, 0xec, 0x01, 0xec, 0x01, 0x00, 0x00, 0x0b, 0xec, 0x83, 0xca, - 0x7e, 0xec, 0x01, 0xec, 0x01, 0x00, 0x00, 0x0b, 0xec, 0x83, 0xca, - 0x7e, 0xec, 0x01, 0xec, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x82, 0xff, - 0xff, 0x03, 0x00, 0x00, 0x0a, 0xec, 0x82, 0xca, 0x7e, 0x03, 0xec, - 0x01, 0x00, 0x00, 0x0a, 0xec, 0x82, 0xca, 0x7e, 0x03, 0xec, 0x01, - 0x00, 0x00, 0x0a, 0xec, 0x82, 0xca, 0x7e, 0x03, 0xec, 0x01, 0x00, - 0x00, 0x0a, 0x00, 0x82, 0xff, 0xff, 0x04, 0x00, 0x00, 0x09, 0xec, - 0x85, 0xcc, 0x80, 0xec, 0xec, 0xcf, 0x01, 0xec, 0x01, 0x00, 0x00, - 0x09, 0xec, 0x85, 0xcc, 0x80, 0xec, 0xec, 0xcf, 0x01, 0xec, 0x01, - 0x00, 0x00, 0x09, 0xec, 0x85, 0xcc, 0x80, 0xec, 0xec, 0xcf, 0x01, - 0xec, 0x01, 0x00, 0x00, 0x09, 0x00, 0x85, 0xff, 0xff, 0x00, 0x00, - 0xff, 0x02, 0x00, 0x00, 0x08, 0xec, 0x86, 0xca, 0x80, 0xec, 0xec, - 0xcf, 0x80, 0x01, 0xec, 0x01, 0x00, 0x00, 0x08, 0xec, 0x86, 0xca, - 0x80, 0xec, 0xec, 0xcf, 0x80, 0x01, 0xec, 0x01, 0x00, 0x00, 0x08, - 0xec, 0x86, 0xca, 0x80, 0xec, 0xec, 0xcf, 0x80, 0x01, 0xec, 0x01, - 0x00, 0x00, 0x08, 0x00, 0x86, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0x02, 0x00, 0x00, 0x07, 0xec, 0x87, 0xc6, 0x7e, 0xec, 0xec, 0xc9, - 0x7e, 0xec, 0x01, 0xec, 0x01, 0x00, 0x00, 0x07, 0xec, 0x87, 0xc6, - 0x7e, 0xec, 0xec, 0xc9, 0x7e, 0xec, 0x01, 0xec, 0x01, 0x00, 0x00, - 0x07, 0xec, 0x87, 0xc6, 0x7e, 0xec, 0xec, 0xc9, 0x7e, 0xec, 0x01, - 0xec, 0x01, 0x00, 0x00, 0x07, 0x00, 0x86, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0x03, 0x00, 0x00, 0x06, 0xec, 0x86, 0xc6, 0x7e, 0xec, - 0xec, 0xc9, 0x7e, 0x03, 0xec, 0x01, 0x00, 0x00, 0x06, 0xec, 0x86, - 0xc6, 0x7e, 0xec, 0xec, 0xc9, 0x7e, 0x03, 0xec, 0x01, 0x00, 0x00, - 0x06, 0xec, 0x86, 0xc6, 0x7e, 0xec, 0xec, 0xc9, 0x7e, 0x03, 0xec, - 0x01, 0x00, 0x00, 0x06, 0x00, 0x86, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x04, 0x00, 0x00, 0x05, 0xec, 0x89, 0xc8, 0x80, 0xec, 0xec, - 0xcd, 0x80, 0xec, 0xec, 0xcd, 0x01, 0xec, 0x01, 0x00, 0x00, 0x05, - 0xec, 0x89, 0xc8, 0x80, 0xec, 0xec, 0xcd, 0x80, 0xec, 0xec, 0xcd, - 0x01, 0xec, 0x01, 0x00, 0x00, 0x05, 0xec, 0x89, 0xc8, 0x80, 0xec, - 0xec, 0xcd, 0x80, 0xec, 0xec, 0xcd, 0x01, 0xec, 0x01, 0x00, 0x00, - 0x05, 0x00, 0x89, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, - 0xff, 0x02, 0x00, 0x00, 0x04, 0xec, 0x8a, 0xcd, 0x80, 0xec, 0xec, - 0xcd, 0x80, 0xec, 0xec, 0xcd, 0x80, 0x01, 0xec, 0x01, 0x00, 0x00, - 0x04, 0xec, 0x8a, 0xcd, 0x80, 0xec, 0xec, 0xcd, 0x80, 0xec, 0xec, - 0xcd, 0x80, 0x01, 0xec, 0x01, 0x00, 0x00, 0x04, 0xec, 0x8a, 0xcd, - 0x80, 0xec, 0xec, 0xcd, 0x80, 0xec, 0xec, 0xcd, 0x80, 0x01, 0xec, - 0x01, 0x00, 0x00, 0x04, 0x00, 0x8a, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x03, 0xec, 0x8b, - 0xc9, 0x7e, 0xec, 0xec, 0xc9, 0x7e, 0xec, 0xec, 0xc9, 0x7e, 0xec, - 0x01, 0xec, 0x01, 0x00, 0x00, 0x03, 0xec, 0x8b, 0xc9, 0x7e, 0xec, - 0xec, 0xc9, 0x7e, 0xec, 0xec, 0xc9, 0x7e, 0xec, 0x01, 0xec, 0x01, - 0x00, 0x00, 0x03, 0xec, 0x8b, 0xc9, 0x7e, 0xec, 0xec, 0xc9, 0x7e, - 0xec, 0xec, 0xc9, 0x7e, 0xec, 0x01, 0xec, 0x01, 0x00, 0x00, 0x03, - 0x00, 0x8a, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x03, 0x00, 0x00, 0x0f, 0xec, 0x01, 0x00, 0x00, 0x0f, 0xec, - 0x01, 0x00, 0x00, 0x0f, 0xec, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00 -}; - -static const size_t resize_box_len = 1683; - diff --git a/panda/src/pandabase/pandasymbols.h b/panda/src/pandabase/pandasymbols.h index 3f529dab27..1ea001eb63 100644 --- a/panda/src/pandabase/pandasymbols.h +++ b/panda/src/pandabase/pandasymbols.h @@ -122,7 +122,6 @@ #define BUILDING_PANDA_COCOADISPLAY #define BUILDING_PANDA_GLGSG #define BUILDING_PANDA_GLXDISPLAY - #define BUILDING_PANDA_OSXDISPLAY #define BUILDING_PANDA_WGLDISPLAY #endif @@ -340,14 +339,6 @@ #define EXPTP_PANDA_NET IMPORT_TEMPL #endif -#ifdef BUILDING_PANDA_OSXDISPLAY - #define EXPCL_PANDA_OSXDISPLAY EXPORT_CLASS - #define EXPTP_PANDA_OSXDISPLAY EXPORT_TEMPL -#else - #define EXPCL_PANDA_OSXDISPLAY IMPORT_CLASS - #define EXPTP_PANDA_OSXDISPLAY IMPORT_TEMPL -#endif - #ifdef BUILDING_PANDA_PARAMETRICS #define EXPCL_PANDA_PARAMETRICS EXPORT_CLASS #define EXPTP_PANDA_PARAMETRICS EXPORT_TEMPL diff --git a/panda/src/tinydisplay/config_tinydisplay.cxx b/panda/src/tinydisplay/config_tinydisplay.cxx index 9740001c01..9b69b9bd00 100644 --- a/panda/src/tinydisplay/config_tinydisplay.cxx +++ b/panda/src/tinydisplay/config_tinydisplay.cxx @@ -16,8 +16,6 @@ #include "tinyXGraphicsWindow.h" #include "tinyWinGraphicsPipe.h" #include "tinyWinGraphicsWindow.h" -#include "tinyOsxGraphicsPipe.h" -#include "tinyOsxGraphicsWindow.h" #include "tinySDLGraphicsPipe.h" #include "tinySDLGraphicsWindow.h" #include "tinyOffscreenGraphicsPipe.h" @@ -40,26 +38,6 @@ ConfigureFn(config_tinydisplay) { init_libtinydisplay(); } -ConfigVariableBool show_resize_box -("show-resize-box", true, - PRC_DESC("When this variable is true, then resizable OSX Panda windows will " - "be rendered with a resize control in the lower-right corner. " - "This is specially handled by Panda, since otherwise the 3-d " - "window would completely hide any resize control drawn by the " - "OS. Set this variable false to allow this control to be hidden.")); - -ConfigVariableBool osx_disable_event_loop -("osx-disable-event-loop", false, - PRC_DESC("Set this true to disable the window event loop for the Panda " - "windows. This makes sense only in a publish environment where " - "the window event loop is already handled by another part of the " - "app.")); - -ConfigVariableInt osx_mouse_wheel_scale -("osx-mouse-wheel-scale", 1, - PRC_DESC("Specify the number of units to spin the Mac mouse wheel to " - "represent a single wheel_up or wheel_down message.")); - ConfigVariableBool td_ignore_mipmaps ("td-ignore-mipmaps", false, PRC_DESC("Configure this true to disable use of mipmaps on the " @@ -117,14 +95,6 @@ init_libtinydisplay() { ps->set_system_tag("TinyPanda", "native_window_system", "Win"); #endif -#if defined(IS_OSX) && !defined(BUILD_IPHONE) && defined(HAVE_CARBON) && !__LP64__ - TinyOsxGraphicsPipe::init_type(); - TinyOsxGraphicsWindow::init_type(); - selection->add_pipe_type(TinyOsxGraphicsPipe::get_class_type(), - TinyOsxGraphicsPipe::pipe_constructor); - ps->set_system_tag("TinyPanda", "native_window_system", "OSX"); -#endif - #ifdef HAVE_SDL TinySDLGraphicsPipe::init_type(); TinySDLGraphicsWindow::init_type(); @@ -150,10 +120,6 @@ get_pipe_type_p3tinydisplay() { return TinyWinGraphicsPipe::get_class_type().get_index(); #endif -#if defined(IS_OSX) && !defined(BUILD_IPHONE) && defined(HAVE_CARBON) && !__LP64__ - return TinyOsxGraphicsPipe::get_class_type().get_index(); -#endif - #ifdef HAVE_X11 return TinyXGraphicsPipe::get_class_type().get_index(); #endif diff --git a/panda/src/tinydisplay/config_tinydisplay.h b/panda/src/tinydisplay/config_tinydisplay.h index 2750d9cad3..d4d1225b94 100644 --- a/panda/src/tinydisplay/config_tinydisplay.h +++ b/panda/src/tinydisplay/config_tinydisplay.h @@ -25,10 +25,6 @@ NotifyCategoryDecl(tinydisplay, EXPCL_TINYDISPLAY, EXPTP_TINYDISPLAY); extern EXPCL_TINYDISPLAY void init_libtinydisplay(); extern "C" EXPCL_TINYDISPLAY int get_pipe_type_p3tinydisplay(); -extern ConfigVariableBool show_resize_box; -extern ConfigVariableBool osx_disable_event_loop; -extern ConfigVariableInt osx_mouse_wheel_scale; - extern ConfigVariableInt td_texture_ram; extern ConfigVariableBool td_ignore_mipmaps; extern ConfigVariableBool td_ignore_clamp; diff --git a/panda/src/tinydisplay/p3tinydisplay_composite2.cxx b/panda/src/tinydisplay/p3tinydisplay_composite2.cxx index 1d71c075aa..f020bbe8f1 100644 --- a/panda/src/tinydisplay/p3tinydisplay_composite2.cxx +++ b/panda/src/tinydisplay/p3tinydisplay_composite2.cxx @@ -1,11 +1,5 @@ -// We have to include this early, before anyone includes -// netinet/tcp.h, which will define TCP_NODELAY and other symbols and -// confuse the Apple system headers. -#include "tinyOsxGraphicsPipe.h" - #include "tinyGraphicsStateGuardian.cxx" #include "tinyOffscreenGraphicsPipe.cxx" -#include "tinyOsxGraphicsPipe.cxx" #include "tinySDLGraphicsPipe.cxx" #include "tinySDLGraphicsWindow.cxx" #include "tinyTextureContext.cxx" diff --git a/panda/src/tinydisplay/tinyOsxGraphicsPipe.I b/panda/src/tinydisplay/tinyOsxGraphicsPipe.I deleted file mode 100644 index ac88123073..0000000000 --- a/panda/src/tinydisplay/tinyOsxGraphicsPipe.I +++ /dev/null @@ -1,12 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file tinyOsxGraphicsPipe.I - * @author drose - * @date 2008-05-12 - */ diff --git a/panda/src/tinydisplay/tinyOsxGraphicsPipe.cxx b/panda/src/tinydisplay/tinyOsxGraphicsPipe.cxx deleted file mode 100644 index 349fad4398..0000000000 --- a/panda/src/tinydisplay/tinyOsxGraphicsPipe.cxx +++ /dev/null @@ -1,252 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file tinyOsxGraphicsPipe.cxx - * @author drose - * @date 2008-05-12 - */ - -#include "pandabase.h" - -#if defined(IS_OSX) && !defined(BUILD_IPHONE) && defined(HAVE_CARBON) && !__LP64__ - -#include "tinyOsxGraphicsPipe.h" -#include "config_tinydisplay.h" -#include "tinyOsxGraphicsWindow.h" -#include "tinyGraphicsBuffer.h" -#include "pnmImage.h" -#include "subprocessWindow.h" -#include "nativeWindowHandle.h" - -TypeHandle TinyOsxGraphicsPipe::_type_handle; - -/** - * - */ -TinyOsxGraphicsPipe:: -TinyOsxGraphicsPipe() { - CGRect display_bounds = CGDisplayBounds(kCGDirectMainDisplay); - _display_width = CGRectGetWidth(display_bounds); - _display_height = CGRectGetHeight(display_bounds); -} - -/** - * - */ -TinyOsxGraphicsPipe:: -~TinyOsxGraphicsPipe() { -} - -/** - * Returns the name of the rendering interface associated with this - * GraphicsPipe. This is used to present to the user to allow him/her to - * choose between several possible GraphicsPipes available on a particular - * platform, so the name should be meaningful and unique for a given platform. - */ -std::string TinyOsxGraphicsPipe:: -get_interface_name() const { - return "TinyPanda"; -} - -/** - * This function is passed to the GraphicsPipeSelection object to allow the - * user to make a default TinyOsxGraphicsPipe. - */ -PT(GraphicsPipe) TinyOsxGraphicsPipe:: -pipe_constructor() { - return new TinyOsxGraphicsPipe; -} - -/** - * Creates a new Quartz bitmap image with the data in the indicated PNMImage. - * The caller should eventually free this image via CGImageRelease. - */ -CGImageRef TinyOsxGraphicsPipe:: -create_cg_image(const PNMImage &pnm_image) { - size_t width = pnm_image.get_x_size(); - size_t height = pnm_image.get_y_size(); - -#ifdef PGM_BIGGRAYS - size_t bytes_per_component = 2; -#else - size_t bytes_per_component = 1; -#endif - size_t bits_per_component = bytes_per_component * 8; - size_t num_components = pnm_image.get_num_channels(); - - size_t bits_per_pixel = num_components * bits_per_component; - size_t bytes_per_row = num_components * bytes_per_component * width; - - size_t num_bytes = bytes_per_row * height; - bool has_alpha; - bool is_grayscale; - - CFStringRef color_space_name = nullptr; - switch (pnm_image.get_color_type()) { - case PNMImage::CT_grayscale: - color_space_name = kCGColorSpaceGenericGray; - has_alpha = false; - is_grayscale = true; - break; - - case PNMImage::CT_two_channel: - color_space_name = kCGColorSpaceGenericGray; - has_alpha = true; - is_grayscale = true; - break; - - case PNMImage::CT_color: - color_space_name = kCGColorSpaceGenericRGB; - has_alpha = false; - is_grayscale = false; - break; - - case PNMImage::CT_four_channel: - color_space_name = kCGColorSpaceGenericRGB; - has_alpha = true; - is_grayscale = false; - break; - - case PNMImage::CT_invalid: - // Shouldn't get here. - nassertr(false, nullptr); - break; - } - nassertr(color_space_name != nullptr, nullptr); - - CGColorSpaceRef color_space = CGColorSpaceCreateWithName(color_space_name); - nassertr(color_space != nullptr, nullptr); - - CGBitmapInfo bitmap_info = 0; -#ifdef PGM_BIGGRAYS - bitmap_info |= kCGBitmapByteOrder16Host; -#endif - if (has_alpha) { - bitmap_info |= kCGImageAlphaLast; - } - - // Now convert the pixel data to a format friendly to CGImageCreate(). - char *char_array = (char *)PANDA_MALLOC_ARRAY(num_bytes); - - xelval *dp = (xelval *)char_array; - for (size_t yi = 0; yi < height; ++yi) { - for (size_t xi = 0; xi < width; ++xi) { - if (is_grayscale) { - *dp++ = (xelval)(pnm_image.get_gray(xi, yi) * PGM_MAXMAXVAL); - } else { - *dp++ = (xelval)(pnm_image.get_red(xi, yi) * PGM_MAXMAXVAL); - *dp++ = (xelval)(pnm_image.get_green(xi, yi) * PGM_MAXMAXVAL); - *dp++ = (xelval)(pnm_image.get_blue(xi, yi) * PGM_MAXMAXVAL); - } - if (has_alpha) { - *dp++ = (xelval)(pnm_image.get_alpha(xi, yi) * PGM_MAXMAXVAL); - } - } - } - nassertr((void *)dp == (void *)(char_array + num_bytes), nullptr); - - CGDataProviderRef provider = - CGDataProviderCreateWithData(nullptr, char_array, num_bytes, release_data); - nassertr(provider != nullptr, nullptr); - - CGImageRef image = CGImageCreate - (width, height, bits_per_component, bits_per_pixel, bytes_per_row, - color_space, bitmap_info, provider, - nullptr, false, kCGRenderingIntentDefault); - nassertr(image != nullptr, nullptr); - - CGColorSpaceRelease(color_space); - CGDataProviderRelease(provider); - - return image; -} - -/** - * This callback is assigned to delete the data array allocated within - * create_cg_image(). - */ -void TinyOsxGraphicsPipe:: -release_data(void *info, const void *data, size_t size) { - char *char_array = (char *)data; - PANDA_FREE_ARRAY(char_array); -} - -/** - * Creates a new window or buffer on the pipe, if possible. This routine is - * only called from GraphicsEngine::make_output. - */ -PT(GraphicsOutput) TinyOsxGraphicsPipe:: -make_output(const std::string &name, - const FrameBufferProperties &fb_prop, - const WindowProperties &win_prop, - int flags, - GraphicsEngine *engine, - GraphicsStateGuardian *gsg, - GraphicsOutput *host, - int retry, - bool &precertify) { - - if (!_is_valid) { - return nullptr; - } - - TinyGraphicsStateGuardian *tinygsg = 0; - if (gsg != 0) { - DCAST_INTO_R(tinygsg, gsg, nullptr); - } - - // First thing to try: a TinyOsxGraphicsWindow - - if (retry == 0) { - if (((flags&BF_require_parasite)!=0)|| - ((flags&BF_refuse_window)!=0)|| - ((flags&BF_resizeable)!=0)|| - ((flags&BF_size_track_host)!=0)|| - ((flags&BF_rtt_cumulative)!=0)|| - ((flags&BF_can_bind_color)!=0)|| - ((flags&BF_can_bind_every)!=0)) { - return nullptr; - } - if ((flags & BF_fb_props_optional)==0) { - if ((fb_prop.get_aux_rgba() > 0)|| - (fb_prop.get_aux_hrgba() > 0)|| - (fb_prop.get_aux_float() > 0)) { - return nullptr; - } - } - WindowHandle *window_handle = win_prop.get_parent_window(); - if (window_handle != nullptr) { - tinydisplay_cat.info() - << "Got parent_window " << *window_handle << "\n"; -#ifdef SUPPORT_SUBPROCESS_WINDOW - WindowHandle::OSHandle *os_handle = window_handle->get_os_handle(); - if (os_handle != nullptr && - os_handle->is_of_type(NativeWindowHandle::SubprocessHandle::get_class_type())) { - return new SubprocessWindow(engine, this, name, fb_prop, win_prop, - flags, gsg, host); - } -#endif // SUPPORT_SUBPROCESS_WINDOW - } - return new TinyOsxGraphicsWindow(engine, this, name, fb_prop, win_prop, - flags, gsg, host); - } - - // Second thing to try: a TinyGraphicsBuffer - if (retry == 1) { - if (((flags&BF_require_parasite)!=0)|| - ((flags&BF_require_window)!=0)) { - return nullptr; - } - return new TinyGraphicsBuffer(engine, this, name, fb_prop, win_prop, flags, gsg, host); - } - - // Nothing else left to try. - return nullptr; -} - -#endif // IS_OSX diff --git a/panda/src/tinydisplay/tinyOsxGraphicsPipe.h b/panda/src/tinydisplay/tinyOsxGraphicsPipe.h deleted file mode 100644 index 14cc0aded0..0000000000 --- a/panda/src/tinydisplay/tinyOsxGraphicsPipe.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file tinyOsxGraphicsPipe.h - * @author drose - * @date 2008-05-12 - */ - -#ifndef TINYOSXGRAPHICSPIPE_H -#define TINYOSXGRAPHICSPIPE_H - -#include "pandabase.h" - -#if defined(IS_OSX) && !defined(BUILD_IPHONE) && defined(HAVE_CARBON) && !__LP64__ - -// We have to include this early, before anyone includes netinettcp.h, which -// will define TCP_NODELAY and other symbols and confuse the Apple system -// headers. -#include - -#include "graphicsPipe.h" -#include "tinyGraphicsStateGuardian.h" - -/** - * This graphics pipe represents the interface for creating TinyPanda graphics - * windows on a Mac client. - */ -class EXPCL_TINYDISPLAY TinyOsxGraphicsPipe : public GraphicsPipe { -public: - TinyOsxGraphicsPipe(); - virtual ~TinyOsxGraphicsPipe(); - - virtual std::string get_interface_name() const; - static PT(GraphicsPipe) pipe_constructor(); - - static CGImageRef create_cg_image(const PNMImage &pnm_image); - -private: - static void release_data(void *info, const void *data, size_t size); - -protected: - virtual PT(GraphicsOutput) make_output(const std::string &name, - const FrameBufferProperties &fb_prop, - const WindowProperties &win_prop, - int flags, - GraphicsEngine *engine, - GraphicsStateGuardian *gsg, - GraphicsOutput *host, - int retry, - bool &precertify); - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - GraphicsPipe::init_type(); - register_type(_type_handle, "TinyOsxGraphicsPipe", - GraphicsPipe::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; -}; - -#include "tinyOsxGraphicsPipe.I" - -#endif // IS_OSX - -#endif diff --git a/panda/src/tinydisplay/tinyOsxGraphicsWindow.I b/panda/src/tinydisplay/tinyOsxGraphicsWindow.I deleted file mode 100644 index 4f9c2c76f2..0000000000 --- a/panda/src/tinydisplay/tinyOsxGraphicsWindow.I +++ /dev/null @@ -1,20 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file tinyOsxGraphicsWindow.I - * @author drose - * @date 2008-05-12 - */ - -inline void TinyOsxGraphicsWindow::SendKeyEvent( ButtonHandle key, bool down) -{ - if(down) - _input_devices[0].button_down(key); - else - _input_devices[0].button_up(key); -} diff --git a/panda/src/tinydisplay/tinyOsxGraphicsWindow.h b/panda/src/tinydisplay/tinyOsxGraphicsWindow.h deleted file mode 100644 index 71682c9a3b..0000000000 --- a/panda/src/tinydisplay/tinyOsxGraphicsWindow.h +++ /dev/null @@ -1,146 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file tinyOsxGraphicsWindow.h - * @author drose - * @date 2008-05-12 - */ - -#ifndef TINYOSXGRAPHICSWINDOW_H -#define TINYOSXGRAPHICSWINDOW_H - -#include "pandabase.h" - -#if defined(IS_OSX) && !defined(BUILD_IPHONE) && defined(HAVE_CARBON) && !__LP64__ - -#include - -#include "graphicsWindow.h" -#include "buttonHandle.h" -#include "tinyGraphicsStateGuardian.h" - -/** - * Opens a window on OS X to display the TinyPanda software rendering. - */ -class TinyOsxGraphicsWindow : public GraphicsWindow { -public: - TinyOsxGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, - const std::string &name, - const FrameBufferProperties &fb_prop, - const WindowProperties &win_prop, - int flags, - GraphicsStateGuardian *gsg, - GraphicsOutput *host); - virtual ~TinyOsxGraphicsWindow(); - - virtual bool move_pointer(int device, int x, int y); - - virtual bool begin_frame(FrameMode mode, Thread *current_thread); - virtual void end_frame(FrameMode mode, Thread *current_thread); - virtual void begin_flip(); - virtual void process_events(); - virtual bool supports_pixel_zoom() const; - - virtual bool do_reshape_request(int x_origin, int y_origin, bool has_origin, - int x_size, int y_size); - - virtual void mouse_mode_absolute(); - virtual void mouse_mode_relative(); - - virtual void set_properties_now(WindowProperties &properties); - -private: - void ReleaseSystemResources(); - inline void SendKeyEvent( ButtonHandle key, bool down); - -protected: - virtual void close_window(); - virtual bool open_window(); - -private: - - bool OSOpenWindow(WindowProperties &properties); - - // a singleton .. for the events to find the right pipe to push the event - // into - - -public: // do not call direct .. - OSStatus handleKeyInput (EventHandlerCallRef myHandler, EventRef event, Boolean keyDown); - OSStatus handleTextInput (EventHandlerCallRef myHandler, EventRef event); - OSStatus handleWindowMouseEvents (EventHandlerCallRef myHandler, EventRef event); - ButtonHandle OSX_TranslateKey( UInt32 key, EventRef event ); - static TinyOsxGraphicsWindow * GetCurrentOSxWindow (WindowRef hint); - - void HandleModifireDeleta(UInt32 modifiers); - void HandleButtonDelta(UInt32 new_buttons); - void DoResize(void); - - OSStatus event_handler(EventHandlerCallRef myHandler, EventRef event); - - virtual void user_close_request(); - void SystemCloseWindow(); - void SystemSetWindowForground(bool forground); - void SystemPointToLocalPoint(Point &qdGlobalPoint); - void LocalPointToSystemPoint(Point &qdLocalPoint); - bool set_icon_filename(const Filename &icon_filename); - - void set_pointer_in_window(int x, int y); - void set_pointer_out_of_window(); - -private: - void create_frame_buffer(); - -private: - ZBuffer *_frame_buffer; - -private: - UInt32 _last_key_modifiers; - UInt32 _last_buttons; - WindowRef _osx_window; - bool _is_fullscreen; - - CGImageRef _pending_icon; - CGImageRef _current_icon; - - int _ID; - static TinyOsxGraphicsWindow *FullScreenWindow; - - CFDictionaryRef _originalMode; - - // True if _properties.get_cursor_hidden() is true. - bool _cursor_hidden; - - // True if the cursor is actually hidden right now via system calls. - bool _display_hide_cursor; - - SInt32 _wheel_delta; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - GraphicsWindow::init_type(); - register_type(_type_handle, "TinyOsxGraphicsWindow", - GraphicsWindow::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; -}; - -#include "tinyOsxGraphicsWindow.I" - -#endif // IS_OSX - -#endif diff --git a/panda/src/tinydisplay/tinyOsxGraphicsWindow.mm b/panda/src/tinydisplay/tinyOsxGraphicsWindow.mm deleted file mode 100644 index d1df628415..0000000000 --- a/panda/src/tinydisplay/tinyOsxGraphicsWindow.mm +++ /dev/null @@ -1,1734 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file tinyOsxGraphicsWindow.mm - */ - -#include "pandabase.h" - -#if defined(IS_OSX) && !defined(BUILD_IPHONE) && defined(HAVE_CARBON) && !__LP64__ - -#include -#include - -#include "tinyOsxGraphicsWindow.h" -#include "config_tinydisplay.h" -#include "tinyOsxGraphicsPipe.h" -#include "pStatTimer.h" -#include "keyboardButton.h" -#include "mouseButton.h" -#include "tinyGraphicsStateGuardian.h" -#include "throw_event.h" -#include "pnmImage.h" -#include "virtualFileSystem.h" -#include "config_putil.h" - -#include - -#include "pmutex.h" -// #include "mutexHolder.h" - - -Mutex &OSXGloablMutex() { - static Mutex m("OSXWIN_Mutex"); - return m; -} - -struct work1 { - volatile bool work_done; -}; - -#define PANDA_CREATE_WINDOW 101 -static void Post_Event_Wait(unsigned short type, unsigned int data1 , unsigned int data2 , int target_window ) { - work1 w; - w.work_done = false; - NSEvent *ev = [NSEvent otherEventWithType:NSApplicationDefined - location:NSZeroPoint - modifierFlags:0 - timestamp:0.0f - windowNumber:target_window - context:nil - subtype:type - data1:data1 - data2:(int)&w]; - - [NSApp postEvent:ev atStart:NO]; - while (!w.work_done) - usleep(10); - -} - - -TypeHandle TinyOsxGraphicsWindow::_type_handle; -TinyOsxGraphicsWindow * TinyOsxGraphicsWindow::FullScreenWindow = NULL; - - -#define USER_CONTAINER - -#include - -#ifdef USER_CONTAINER - -std::set< WindowRef > MyWindows; -void AddAWindow( WindowRef window) { - MyWindows.insert(window); -} -bool checkmywindow(WindowRef window) { - return MyWindows.find(window) != MyWindows.end(); -} -#else - -void AddAWindow( WindowRef window) { -} - -bool checkmywindow(WindowRef window) { - return true; -} - -#endif - - - -/** - * How to find the active window for events on osx.. - * - */ -TinyOsxGraphicsWindow* TinyOsxGraphicsWindow::GetCurrentOSxWindow(WindowRef window) { - if (FullScreenWindow != NULL) - return FullScreenWindow; - - if (NULL == window) // HID use this path - { - // Assume first we are a child window. If we cant find a window of - // that class, then we are standalone and can jsut grab the front - // window. - window = GetFrontWindowOfClass(kSimpleWindowClass, TRUE); - if (NULL == window) - window = FrontNonFloatingWindow(); - } - - if (window && checkmywindow(window)) { - return (TinyOsxGraphicsWindow *)GetWRefCon (window); - } else { - return NULL; - } -} - -/** - * The standard window event handler for non-fullscreen windows. - */ -OSStatus TinyOsxGraphicsWindow:: -event_handler(EventHandlerCallRef myHandler, EventRef event) { - - OSStatus result = eventNotHandledErr; - UInt32 the_class = GetEventClass(event); - UInt32 kind = GetEventKind(event); - - WindowRef window = NULL; - GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, - sizeof(window), NULL, &window); - - UInt32 attributes = 0; - GetEventParameter(event, kEventParamAttributes, typeUInt32, NULL, - sizeof(attributes), NULL, &attributes); - - if (tinydisplay_cat.is_spam()) { - tinydisplay_cat.spam() << ClockObject::get_global_clock()->get_real_time() << " event_handler: " << (void *)this << ", " << window << ", " << the_class << ", " << kind << "\n"; - } - - switch (the_class) { - case kEventClassMouse: - result = handleWindowMouseEvents (myHandler, event); - break; - - case kEventClassWindow: - switch (kind) { - case kEventWindowCollapsing: - /* - Rect r; - GetWindowPortBounds (window, &r); - CompositeGLBufferIntoWindow( get_context(), &r, GetWindowPort (window)); - UpdateCollapsedWindowDockTile (window); - */ - SystemSetWindowForground(false); - break; - case kEventWindowActivated: // called on click activation and initially - SystemSetWindowForground(true); - DoResize(); - break; - case kEventWindowDeactivated: - SystemSetWindowForground(false); - break; - case kEventWindowClose: // called when window is being closed (close box) - // This is a message from the window manager indicating that the - // user has requested to close the window. - user_close_request(); - result = noErr; - break; - case kEventWindowShown: // called on initial show (not on un-minimize) - if (window == FrontNonFloatingWindow ()) - SetUserFocusWindow (window); - break; - - case kEventWindowBoundsChanging: - // Gives us a chance to intercept resize attempts - if (attributes & kWindowBoundsChangeSizeChanged) { - // If the window is supposed to be fixed-size, enforce this. - if (_properties.get_fixed_size()) { - Rect bounds; - GetEventParameter(event, kEventParamCurrentBounds, - typeQDRectangle, NULL, sizeof(bounds), NULL, &bounds); - bounds.right = bounds.left + _properties.get_x_size(); - bounds.bottom = bounds.top + _properties.get_y_size(); - SetEventParameter(event, kEventParamCurrentBounds, - typeQDRectangle, sizeof(bounds), &bounds); result = noErr; - } - } - break; - - case kEventWindowBoundsChanged: // called for resize and moves (drag) - DoResize(); - break; - case kEventWindowZoomed: - break; - case kEventWindowCollapsed: - { - WindowProperties properties; - properties.set_minimized(true); - system_changed_properties(properties); - } - break; - case kEventWindowExpanded: - { - WindowProperties properties; - properties.set_minimized(false); - system_changed_properties(properties); - } - break; - } - break; - } - - return result; -} - -/** - * The user has requested to close the window, for instance with Cmd-W, or by - * clicking on the close button. - */ -void TinyOsxGraphicsWindow::user_close_request() { - string close_request_event = get_close_request_event(); - if (!close_request_event.empty()) { - // In this case, the app has indicated a desire to intercept the request - // and process it directly. - throw_event(close_request_event); - } else { - // In this case, the default case, the app does not intend to service the - // request, so we do by closing the window. - close_window(); - } -} - -/** - * The Windows is closed by a OS resource not by a internal request - * - */ -void TinyOsxGraphicsWindow::SystemCloseWindow() { - if (tinydisplay_cat.is_debug()) - tinydisplay_cat.debug() << "System Closing Window \n"; - ReleaseSystemResources(); -}; - -/** - * The C callback for Window Events .. - * - * We only hook this up for non fullscreen window... so we only handle system - * window events.. - * - */ -static pascal OSStatus windowEvtHndlr(EventHandlerCallRef myHandler, EventRef event, void *userData) { -#pragma unused (userData) - -// volatile().lock(); - - WindowRef window = NULL; - GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window); - - if (window != NULL) { - TinyOsxGraphicsWindow *osx_win = TinyOsxGraphicsWindow::GetCurrentOSxWindow(window); - if (osx_win != (TinyOsxGraphicsWindow *)NULL) { - // OSXGloablMutex().release(); - return osx_win->event_handler(myHandler, event); - } - } - - // OSXGloablMutex().release(); - return eventNotHandledErr; -} - -/** - * The C callback for Window Events .. - * - * We only hook this up for none fullscreen window... so we only handle system - * window events.. - * - */ -void TinyOsxGraphicsWindow::DoResize(void) { - tinydisplay_cat.info() << "In Resize....." << _properties << "\n"; - - // only in window mode .. not full screen - if (_osx_window != NULL && !_is_fullscreen && _properties.has_size()) { - Rect rectPort = {0,0,0,0}; - CGRect viewRect = {{0.0f, 0.0f}, {0.0f, 0.0f}}; - - GetWindowPortBounds (_osx_window, &rectPort); - viewRect.size.width = (PN_stdfloat) (rectPort.right - rectPort.left); - viewRect.size.height = (PN_stdfloat) (rectPort.bottom - rectPort.top); - // tell panda - WindowProperties properties; - properties.set_size((int)viewRect.size.width,(int)viewRect.size.height); - properties.set_origin((int) rectPort.left,(int)rectPort.top); - system_changed_properties(properties); - ZB_resize(_frame_buffer, NULL, _properties.get_x_size(), _properties.get_y_size()); - - if (tinydisplay_cat.is_debug()) { - tinydisplay_cat.debug() << " Resizing Window " << viewRect.size.width << " " << viewRect.size.height << "\n"; - } - } -}; - -/** - * The C callback for APlication Events.. - * - * Hooked once for application - * - */ -static pascal OSStatus appEvtHndlr (EventHandlerCallRef myHandler, EventRef event, void* userData) { -#pragma unused (myHandler) - OSStatus result = eventNotHandledErr; - { - - // OSXGloablMutex().lock(); - - TinyOsxGraphicsWindow *osx_win = NULL; - WindowRef window = NULL; - UInt32 the_class = GetEventClass (event); - UInt32 kind = GetEventKind (event); - - GetEventParameter(event, kEventParamWindowRef, typeWindowRef, NULL, sizeof(WindowRef), NULL, (void*) &window); - osx_win = TinyOsxGraphicsWindow::GetCurrentOSxWindow(window); - if (osx_win == NULL) { - // OSXGloablMutex().release(); - return eventNotHandledErr; - } - - switch (the_class) { - case kEventClassTextInput: - if (kind == kEventTextInputUnicodeForKeyEvent) { - osx_win->handleTextInput(myHandler, event); - } - // result = noErr; can not report handled .. the os will not sent the - // raw key strokes then if (osx_win->handleTextInput(myHandler, event) - // == noErr) result = noErr; - break; - case kEventClassKeyboard: - { - switch (kind) { - case kEventRawKeyRepeat: - case kEventRawKeyDown: - result = osx_win->handleKeyInput (myHandler, event, true); - break; - case kEventRawKeyUp: - result = osx_win->handleKeyInput (myHandler, event, false); - break; - case kEventRawKeyModifiersChanged: - { - UInt32 newModifiers; - OSStatus error = GetEventParameter(event, kEventParamKeyModifiers,typeUInt32, NULL,sizeof(UInt32), NULL, &newModifiers); - if (error == noErr) { - osx_win->HandleModifireDeleta(newModifiers); - result = noErr; - } - } - break; - } - } - break; - - case kEventClassMouse: - // tinydisplay_cat.info() << "Mouse movement handled by Application - // handler\n"; if (TinyOsxGraphicsWindow::FullScreenWindow != NULL) - result = osx_win->handleWindowMouseEvents (myHandler, event); - // result = noErr; - break; - } - - // OSXGloablMutex().release(); - } - - return result; -} - -/** - * Trap Unicode Input. - * - - * - */ -OSStatus TinyOsxGraphicsWindow::handleTextInput (EventHandlerCallRef myHandler, EventRef theTextEvent) { - UniChar *text = NULL; - UInt32 actualSize = 0; - - OSStatus ret = GetEventParameter (theTextEvent, kEventParamTextInputSendText, typeUnicodeText, NULL, 0, &actualSize, NULL); - if (ret != noErr) { - return ret; - } - - text = (UniChar*)NewPtr(actualSize); - if (text!= NULL) { - ret = GetEventParameter (theTextEvent, kEventParamTextInputSendText,typeUnicodeText, NULL, actualSize, NULL, text); - if (ret != noErr) { - return ret; - } - - for (unsigned int x = 0; x < actualSize/sizeof(UniChar); ++x) { - _input_devices[0]->keystroke(text[x]); - } - DisposePtr((char *)text); - } - - return ret; -} -/** - * Clean up the OS level messes.. - */ -void TinyOsxGraphicsWindow::ReleaseSystemResources() { - if (_is_fullscreen) { - _is_fullscreen = false; - FullScreenWindow = NULL; - - if (_originalMode != NULL) - CGDisplaySwitchToMode( kCGDirectMainDisplay, _originalMode ); - - CGDisplayRelease( kCGDirectMainDisplay ); - - _originalMode = NULL; - } - - if (_osx_window != NULL) { - SetWRefCon (_osx_window, (long int) NULL); - HideWindow (_osx_window); - DisposeWindow(_osx_window); - _osx_window = NULL; - } - - if (_pending_icon != NULL) { - CGImageRelease(_pending_icon); - _pending_icon = NULL; - } - if (_current_icon != NULL) { - CGImageRelease(_current_icon); - _current_icon = NULL; - } - - WindowProperties properties; - properties.set_foreground(false); - properties.set_open(false); - properties.set_cursor_filename(Filename()); - system_changed_properties(properties); - - _is_fullscreen = false; - _osx_window = NULL; -} - - -static int id_seed = 100; - -/** - * - */ -TinyOsxGraphicsWindow::TinyOsxGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, - const string &name, - const FrameBufferProperties &fb_prop, - const WindowProperties &win_prop, - int flags, - GraphicsStateGuardian *gsg, - GraphicsOutput *host) : - GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host), - _osx_window(NULL), - _is_fullscreen(false), - _pending_icon(NULL), - _current_icon(NULL), - _ID(id_seed++), - _originalMode(NULL) { - PT(InputDevice) device = - GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard/mouse"); - _input_devices.push_back(device); - device->set_pointer_in_window(0, 0); - _last_key_modifiers = 0; - _last_buttons = 0; - - _cursor_hidden = false; - _display_hide_cursor = false; - _wheel_delta = 0; - - _frame_buffer = NULL; - update_pixel_factor(); - - if (tinydisplay_cat.is_debug()) - tinydisplay_cat.debug() << "TinyOsxGraphicsWindow::TinyOsxGraphicsWindow() -" <<_ID << "\n"; -} - -/** - * - */ -TinyOsxGraphicsWindow::~TinyOsxGraphicsWindow() { - if (tinydisplay_cat.is_debug()) - tinydisplay_cat.debug() << "TinyOsxGraphicsWindow::~TinyOsxGraphicsWindow() -" <<_ID << "\n"; - - // Make sure the window callback won't come back to this (destructed) object - // any more. - if (_osx_window) { - SetWRefCon (_osx_window, (long) NULL); - } - - ReleaseSystemResources(); -} - -/** - * Called internally to load up an icon file that should be applied to the - * window. Returns true on success, false on failure. - */ -bool TinyOsxGraphicsWindow::set_icon_filename(const Filename &icon_filename) { - VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); - - Filename icon_pathname = icon_filename; - if (!vfs->resolve_filename(icon_pathname, get_model_path())) { - // The filename doesn't exist along the search path. - if (icon_pathname.is_fully_qualified() && vfs->exists(icon_pathname)) { - // But it does exist locally, so accept it. - } else { - tinydisplay_cat.warning() - << "Could not find icon filename " << icon_filename << "\n"; - return false; - } - } - - - PNMImage pnmimage; - if (!pnmimage.read(icon_pathname)) { - tinydisplay_cat.warning() - << "Could not read icon filename " << icon_pathname << "\n"; - return false; - } - - CGImageRef icon_image = TinyOsxGraphicsPipe::create_cg_image(pnmimage); - if (icon_image == NULL) { - return false; - } - - if (_pending_icon != NULL) { - CGImageRelease(_pending_icon); - _pending_icon = NULL; - } - _pending_icon = icon_image; - return true; -} - -/** - * Indicates the mouse pointer is seen within the window. - */ -void TinyOsxGraphicsWindow:: -set_pointer_in_window(int x, int y) { - _input_devices[0]->set_pointer_in_window(x, y); - - if (_cursor_hidden != _display_hide_cursor) { - if (_cursor_hidden) { - CGDisplayHideCursor(kCGDirectMainDisplay); - _display_hide_cursor = true; - } else { - CGDisplayShowCursor(kCGDirectMainDisplay); - _display_hide_cursor = false; - } - } -} - -/** - * Indicates the mouse pointer is no longer within the window. - */ -void TinyOsxGraphicsWindow:: -set_pointer_out_of_window() { - _input_devices[0]->set_pointer_out_of_window(); - - if (_display_hide_cursor) { - CGDisplayShowCursor(kCGDirectMainDisplay); - _display_hide_cursor = false; - } -} - - -/** - * 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 TinyOsxGraphicsWindow::begin_frame(FrameMode mode, Thread *current_thread) { - PStatTimer timer(_make_current_pcollector); - - begin_frame_spam(mode); - if (_gsg == (GraphicsStateGuardian *)NULL || - (_osx_window == NULL && !_is_fullscreen)) { - // not powered up .. just abort.. - return false; - } - - // Now is a good time to apply the icon change that may have recently been - // requested. By this point, we should be able to get a handle to the dock - // context. - if (_pending_icon != NULL) { - CGContextRef context = BeginCGContextForApplicationDockTile(); - if (context != NULL) { - SetApplicationDockTileImage(_pending_icon); - EndCGContextForApplicationDockTile(context); - - if (_current_icon != NULL) { - CGImageRelease(_current_icon); - _current_icon = NULL; - } - _current_icon = _pending_icon; - _pending_icon = NULL; - } - } - - TinyGraphicsStateGuardian *tinygsg; - DCAST_INTO_R(tinygsg, _gsg, false); - - tinygsg->_current_frame_buffer = _frame_buffer; - tinygsg->reset_if_new(); - - _gsg->set_current_properties(&get_fb_properties()); - return _gsg->begin_frame(current_thread); -} - -/** - * This function will be called within the draw thread after rendering is - * completed for a given frame. It should do whatever finalization is - * required. - */ -void TinyOsxGraphicsWindow::end_frame(FrameMode mode, Thread *current_thread) { - end_frame_spam(mode); - - _gsg->end_frame(current_thread); - - if (mode == FM_render) { - - copy_to_textures(); - - trigger_flip(); - clear_cube_map_selection(); - } -} - -/** - * This function will be called within the draw thread after end_frame() has - * been called on all windows, to initiate the exchange of the front and back - * buffers. - * - * This should instruct the window to prepare for the flip at the next video - * sync, but it should not wait. - * - * We have the two separate functions, begin_flip() and end_flip(), to make it - * easier to flip all of the windows at the same time. - */ -void TinyOsxGraphicsWindow::begin_flip() { - if (_osx_window == NULL) { - return; - } - - QDErr err; - - // blit rendered framebuffer into window backing store - Rect src_rect = {0, 0, _frame_buffer->ysize, _frame_buffer->xsize}; - Rect ddrc_rect = {0, 0, _frame_buffer->ysize, _frame_buffer->xsize}; - if (get_pixel_factor() != 1.0) { - src_rect.right = get_fb_x_size(); - src_rect.bottom = get_fb_y_size(); - } - - // create a GWorld containing our image - GWorldPtr pGWorld; - err = NewGWorldFromPtr(&pGWorld, k32BGRAPixelFormat, &src_rect, 0, 0, 0, - (char *)_frame_buffer->pbuf, _frame_buffer->linesize); - if (err != noErr) { - tinydisplay_cat.error() - << " error in NewGWorldFromPtr, called from begin_flip()\n"; - return; - } - - GrafPtr out_port = GetWindowPort(_osx_window); - GrafPtr portSave = NULL; - Boolean portChanged = QDSwapPort(out_port, &portSave); - - { - static PStatCollector b2("Wait:Flip:Begin:CopyBits"); - PStatTimer t2(b2); - CopyBits(GetPortBitMapForCopyBits(pGWorld), - GetPortBitMapForCopyBits(out_port), - &src_rect, &ddrc_rect, srcCopy, 0); - } - - if (portChanged) { - QDSwapPort(portSave, NULL); - } - - DisposeGWorld(pGWorld); -} - -/** - * Closes the window right now. Called from the window thread. - */ -void TinyOsxGraphicsWindow::close_window() { - SystemCloseWindow(); - - WindowProperties properties; - properties.set_open(false); - system_changed_properties(properties); - - ReleaseSystemResources(); - _gsg.clear(); - GraphicsWindow::close_window(); -} - -/* - * HACK ALLERT ************ Undocumented OSX calls... I can not find any other - * way to get the mouse focus to a window in OSX.. extern "C" { struct - * CPSProcessSerNum { UInt32 lo; UInt32 hi; }; - */ - -// extern OSErr CPSGetCurrentProcess(CPSProcessSerNum *psn); extern OSErr -// CPSEnableForegroundOperation( struct CPSProcessSerNum *psn); extern OSErr -// CPSSetProcessName ( struct CPSProcessSerNum *psn, char *processname); -// extern OSErr CPSSetFrontProcess( struct CPSProcessSerNum *psn); }; - -/** - * 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 TinyOsxGraphicsWindow::open_window() { - // GSG CreationInitialization - TinyGraphicsStateGuardian *tinygsg; - if (_gsg == 0) { - // There is no old gsg. Create a new one. - tinygsg = new TinyGraphicsStateGuardian(_engine, _pipe, NULL); - _gsg = tinygsg; - } else { - DCAST_INTO_R(tinygsg, _gsg, false); - } - - create_frame_buffer(); - if (_frame_buffer == NULL) { - tinydisplay_cat.error() - << "Could not create frame buffer.\n"; - return false; - } - - tinygsg->_current_frame_buffer = _frame_buffer; - - tinygsg->reset_if_new(); - if (!tinygsg->is_valid()) { - close_window(); - return false; - } - - WindowProperties req_properties = _properties; - // OSXGloablMutex().lock(); - bool answer = OSOpenWindow(req_properties); - // OSXGloablMutex().release(); - return answer; -} - - -bool TinyOsxGraphicsWindow::OSOpenWindow(WindowProperties &req_properties) { - OSErr err = noErr; - - if (_current_icon != NULL && _pending_icon == NULL) { - // If we already have an icon specified, we'll need to reapply it when - // the window is successfully created. - _pending_icon = _current_icon; - _current_icon = NULL; - } - - static bool GlobalInits = false; - if (!GlobalInits) { - // one time aplication inits.. to get a window open from a standalone - // aplication.. - - EventHandlerRef application_event_ref_ref1; - EventTypeSpec list1[] = - { - // { kEventClassCommand, kEventProcessCommand }, { - // kEventClassCommand, kEventCommandUpdateStatus }, - { kEventClassMouse, kEventMouseDown },// handle trackball functionality globaly because there is only a single user - { kEventClassMouse, kEventMouseUp }, - { kEventClassMouse, kEventMouseMoved }, - { kEventClassMouse, kEventMouseDragged }, - { kEventClassMouse, kEventMouseWheelMoved } , - { kEventClassKeyboard, kEventRawKeyDown }, - { kEventClassKeyboard, kEventRawKeyUp } , - { kEventClassKeyboard, kEventRawKeyRepeat }, - { kEventClassKeyboard, kEventRawKeyModifiersChanged } , - { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent}, - }; - - EventHandlerUPP gEvtHandler = NewEventHandlerUPP(appEvtHndlr); - err = InstallApplicationEventHandler (gEvtHandler, GetEventTypeCount (list1) , list1, this, &application_event_ref_ref1 ); - GlobalInits = true; - - ProcessSerialNumber psn = { 0, kCurrentProcess }; - - // Determine if we're running from a bundle. - CFDictionaryRef dref = - ProcessInformationCopyDictionary(&psn, kProcessDictionaryIncludeAllInformationMask); - // If the dictionary doesn't have "BundlePath" (or the BundlePath is the - // same as the executable path), then we're not running from a bundle, and - // we need to call TransformProcessType to make the process a "foreground" - // application, with its own icon in the dock and such. - - bool has_bundle = false; - - CFStringRef bundle_path = (CFStringRef)CFDictionaryGetValue(dref, CFSTR("BundlePath")); - if (bundle_path != NULL) { - // OK, we have a bundle path. We're probably running in a bundle . . . - has_bundle = true; - - // . . . unless it turns out it's the same as the executable path. - CFStringRef exe_path = (CFStringRef)CFDictionaryGetValue(dref, kCFBundleExecutableKey); - if (exe_path != NULL) { - if (CFStringCompare(bundle_path, exe_path, kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - has_bundle = false; - } - CFRelease(exe_path); - } - - CFRelease(bundle_path); - } - - if (!has_bundle) { - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - } - SetFrontProcess(&psn); - } - - - bool wants_fullscreen = req_properties.has_fullscreen() && req_properties.get_fullscreen(); - if (req_properties.get_minimized()) { - // A minimized window can't be fullscreen. - wants_fullscreen = false; - } - - if (wants_fullscreen) { - tinydisplay_cat.info() << "Creating full screen\n"; - - // capture the main display - CGDisplayCapture(kCGDirectMainDisplay); - // if sized try and switch it.. - if (req_properties.has_size()) { - _originalMode = CGDisplayCurrentMode(kCGDirectMainDisplay); - CFDictionaryRef newMode = CGDisplayBestModeForParameters(kCGDirectMainDisplay, 32, req_properties.get_x_size(), req_properties.get_y_size(), 0); - if (newMode == NULL) { - tinydisplay_cat.error() - << "Invalid fullscreen size: " << req_properties.get_x_size() - << ", " << req_properties.get_y_size() - << "\n"; - } else { - CGDisplaySwitchToMode(kCGDirectMainDisplay, newMode); - - // Set our new window size according to the size we actually got. - SInt32 width, height; - CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(newMode, kCGDisplayWidth), kCFNumberSInt32Type, &width); - CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(newMode, kCGDisplayHeight), kCFNumberSInt32Type, &height); - - _properties.set_size(width, height); - } - } - - _properties.set_fullscreen(true); - _properties.set_minimized(false); - _properties.set_foreground(true); - - _is_fullscreen = true; - FullScreenWindow = this; - req_properties.clear_fullscreen(); - } else { - int x_origin = 10; - int y_origin = 50; - if (req_properties.has_origin()) { - y_origin = req_properties.get_y_origin(); - x_origin = req_properties.get_x_origin(); - } - - int x_size = 512; - int y_size = 512; - if (req_properties.has_size()) { - x_size = req_properties.get_x_size(); - y_size = req_properties.get_y_size(); - } - - // A coordinate of -2 means to center the window on screen. - if (y_origin == -2 || x_origin == -2) { - if (y_origin == -2) { - y_origin = (_pipe->get_display_height() - y_size) / 2; - } - if (x_origin == -2) { - x_origin = (_pipe->get_display_width() - x_size) / 2; - } - } - - // A coordinate of -1 means a default location. - if (y_origin == -1) { - y_origin = 50; - } - if (x_origin == -1) { - x_origin = 10; - } - - _properties.set_origin(x_origin, y_origin); - _properties.set_size(x_size, y_size); - - Rect r; - r.top = y_origin; - r.left = x_origin; - r.right = r.left + x_size; - r.bottom = r.top + y_size; - - /* - if (req_properties.has_parent_window()) { - tinydisplay_cat.info() << "Creating child window\n"; - - CreateNewWindow(kSimpleWindowClass, kWindowNoAttributes, &r, &_osx_window); - AddAWindow(_osx_window); - - _properties.set_fixed_size(true); - tinydisplay_cat.info() << "Child window created\n"; - } - else */ - { - int attributes = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute; - if (req_properties.has_fixed_size() && req_properties.get_fixed_size()) { - attributes &= ~kWindowResizableAttribute; - } - - if (req_properties.has_undecorated() && req_properties.get_undecorated()) { // create a unmovable .. no edge window.. - tinydisplay_cat.info() << "Creating undecorated window\n"; - - // We don't want a resize box either. - attributes &= ~kWindowResizableAttribute; - attributes |= kWindowNoTitleBarAttribute; - CreateNewWindow(kDocumentWindowClass, attributes, &r, &_osx_window); - } - else - { // create a window with crome and sizing and sucj - // In this case, we want to constrain the window to the available size. - Rect bounds; - GetAvailableWindowPositioningBounds(GetMainDevice(), &bounds); - - r.left = max(r.left, bounds.left); - r.right = min(r.right, bounds.right); - r.top = max(r.top, bounds.top); - r.bottom = min(r.bottom, bounds.bottom); - - tinydisplay_cat.info() << "Creating standard window\n"; - CreateNewWindow(kDocumentWindowClass, attributes, &r, &_osx_window); - AddAWindow(_osx_window); - } - } - - - if (_osx_window) { - - EventHandlerUPP gWinEvtHandler; // window event handler - EventTypeSpec list[] = - { - { kEventClassWindow, kEventWindowCollapsing }, - { kEventClassWindow, kEventWindowShown }, - { kEventClassWindow, kEventWindowActivated }, - { kEventClassWindow, kEventWindowDeactivated }, - { kEventClassWindow, kEventWindowClose }, - { kEventClassWindow, kEventWindowBoundsChanging }, - { kEventClassWindow, kEventWindowBoundsChanged }, - - { kEventClassWindow, kEventWindowCollapsed }, - { kEventClassWindow, kEventWindowExpanded }, - { kEventClassWindow, kEventWindowZoomed }, - { kEventClassWindow, kEventWindowClosed }, - }; - - SetWRefCon (_osx_window, (long) this); // point to the window record in the ref con of the window - gWinEvtHandler = NewEventHandlerUPP(windowEvtHndlr); - InstallWindowEventHandler(_osx_window, gWinEvtHandler, GetEventTypeCount(list), list, (void*)this, NULL); // add event handler - - /*if (!req_properties.has_parent_window()) */ - { - ShowWindow (_osx_window); - } - /* - else - { - - NSWindow* parentWindow = (NSWindow *)req_properties.get_parent_window(); - // NSView* aView = [[parentWindow contentView] - // viewWithTag:378]; NSRect aRect = [aView - // frame]; NSPoint origin = [parentWindow - // convertBaseToScreen:aRect.origin]; - - // NSWindow* childWindow = [[NSWindow alloc] - // initWithWindowRef:_osx_window]; - - - Post_Event_Wait(PANDA_CREATE_WINDOW,(unsigned long) _osx_window,1,[parentWindow windowNumber]); - - // [childWindow setFrameOrigin:origin]; [childWindow - // setAcceptsMouseMovedEvents:YES]; [childWindow - // setBackgroundColor:[NSColor blackColor]]; this seems to block till - // the parent accepts the connection ? [parentWindow - // addChildWindow:childWindow ordered:NSWindowAbove]; [childWindow - // orderFront:nil]; - - - _properties.set_parent_window(req_properties.get_parent_window()); - req_properties.clear_parent_window(); - - } */ - - if (req_properties.has_fullscreen()) { - _properties.set_fullscreen(false); - req_properties.clear_fullscreen(); - } - - if (req_properties.has_undecorated()) { - _properties.set_undecorated(req_properties.get_undecorated()); - req_properties.clear_undecorated(); - } - - _properties.set_minimized(false); - _properties.set_foreground(true); - - if (req_properties.has_minimized()) { - CollapseWindow(_osx_window, req_properties.get_minimized()); - _properties.set_minimized(req_properties.get_minimized()); - _properties.set_foreground(!req_properties.get_minimized()); - req_properties.clear_minimized(); - } - } - - // Now measure the size and placement of the window we actually ended up - // with. - Rect rectPort = {0,0,0,0}; - GetWindowPortBounds (_osx_window, &rectPort); - _properties.set_origin((int) rectPort.left, (int) rectPort.top); - _properties.set_size((int) (rectPort.right - rectPort.left), (int) (rectPort.bottom - rectPort.top)); - req_properties.clear_size(); - req_properties.clear_origin(); - } - - if (req_properties.has_icon_filename()) { - set_icon_filename(req_properties.get_icon_filename()); - } - - _properties.set_open(true); - - if (_properties.has_size()) - set_size_and_recalc(_properties.get_x_size(), _properties.get_y_size()); - - - return (err == noErr); -} - -/** - * Required Event upcall . Used to dispatch Window and Aplication Events back - * into panda - * - */ -void TinyOsxGraphicsWindow::process_events() { - GraphicsWindow::process_events(); - - if (!osx_disable_event_loop) { - EventRef theEvent; - EventTargetRef theTarget = GetEventDispatcherTarget(); - - /*if (!_properties.has_parent_window())*/ - { - while (ReceiveNextEvent(0, NULL, kEventDurationNoWait, true, &theEvent)== noErr) { - SendEventToEventTarget (theEvent, theTarget); - ReleaseEvent(theEvent); - } - } - } -}; - -/** - * Returns true if a call to set_pixel_zoom() will be respected, false if it - * will be ignored. If this returns false, then get_pixel_factor() will - * always return 1.0, regardless of what value you specify for - * set_pixel_zoom(). - * - * This may return false if the underlying renderer doesn't support pixel - * zooming, or if you have called this on a DisplayRegion that doesn't have - * both set_clear_color() and set_clear_depth() enabled. - */ -bool TinyOsxGraphicsWindow:: -supports_pixel_zoom() const { - return true; -} - -/** - * Required Event upcall . Used to dispatch Window and Aplication Events back - * into panda - */ -OSStatus TinyOsxGraphicsWindow::handleKeyInput (EventHandlerCallRef myHandler, EventRef event, Boolean keyDown) { - // key input handler - - if (tinydisplay_cat.is_debug()) { - UInt32 keyCode; - GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); - - tinydisplay_cat.debug() - << ClockObject::get_global_clock()->get_real_time() - << " handleKeyInput: " << (void *)this << ", " << keyCode - << ", " << (int)keyDown << "\n"; - } - - // CallNextEventHandler(myHandler, event); - - // We don't check the result of the above function. In principle, this - // should return eventNotHandledErr if the key event is not handled by the - // OS, but in practice, testing this just seems to eat the Escape keypress - // meaninglessly. Keypresses like F11 that are already mapped in the - // desktop seem to not even come into this function in the first place. - UInt32 newModifiers = 0; - OSStatus error = GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &newModifiers); - if (error == noErr) { - HandleModifireDeleta(newModifiers); - } - - UInt32 keyCode; - GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); - ButtonHandle button = OSX_TranslateKey(keyCode, event); - - if (keyDown) { - if ((newModifiers & cmdKey) != 0) { - if (button == KeyboardButton::ascii_key('q') || button == KeyboardButton::ascii_key('w')) { - // Command-Q or Command-W: quit the application or close the window, - // respectively. For now, we treat them both the same: close the - // window. - user_close_request(); - } - } - SendKeyEvent(button, true); - } else { - SendKeyEvent(button, false); - } - return CallNextEventHandler(myHandler, event); -// return noErr; -} - -/** - * - */ -void TinyOsxGraphicsWindow::SystemSetWindowForground(bool forground) { - WindowProperties properties; - properties.set_foreground(forground); - system_changed_properties(properties); -} - -/** - * - */ -void TinyOsxGraphicsWindow::SystemPointToLocalPoint(Point &qdGlobalPoint) { - if (_osx_window != NULL) { - GrafPtr savePort; - Boolean portChanged = QDSwapPort(GetWindowPort(_osx_window), &savePort); - - GlobalToLocal(&qdGlobalPoint); - - if (portChanged) - QDSwapPort(savePort, NULL); - } -} - -/** - * - */ - OSStatus TinyOsxGraphicsWindow::handleWindowMouseEvents (EventHandlerCallRef myHandler, EventRef event) { - WindowRef window = NULL; - OSStatus result = eventNotHandledErr; - UInt32 kind = GetEventKind (event); - Point qdGlobalPoint = {0, 0}; - UInt32 modifiers = 0; - Rect rectPort; - SInt32 this_wheel_delta; - EventMouseWheelAxis wheelAxis; - - // cerr <<" Start Mouse Event " << _ID << "\n"; - - // Mac OS X v10.1 and later should this be front window??? - GetEventParameter(event, kEventParamWindowRef, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window); - - if (!_is_fullscreen && (window == NULL || window != _osx_window )) { - if (kind == kEventMouseMoved) { - set_pointer_out_of_window(); - } - return eventNotHandledErr; - } - - - - GetWindowPortBounds (window, &rectPort); - - // result = CallNextEventHandler(myHandler, event); if (eventNotHandledErr - // == result) { only handle events not already handled (prevents wierd - // resize interaction) - switch (kind) { - // Whenever mouse button state changes, generate the appropriate Panda - // downup events to represent the change. - - case kEventMouseDown: - case kEventMouseUp: - { - GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); - if (_properties.get_mouse_mode() == WindowProperties::M_relative) { - GetEventParameter(event, kEventParamMouseDelta,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &qdGlobalPoint); - MouseData currMouse = get_pointer(0); - qdGlobalPoint.h += currMouse.get_x(); - qdGlobalPoint.v += currMouse.get_y(); - } - else - { - GetEventParameter(event, kEventParamMouseLocation,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &qdGlobalPoint); - SystemPointToLocalPoint(qdGlobalPoint); - } - - set_pointer_in_window((int)qdGlobalPoint.h, (int)qdGlobalPoint.v); - - UInt32 new_buttons = GetCurrentEventButtonState(); - HandleButtonDelta(new_buttons); - } - result = noErr; - break; - - case kEventMouseMoved: - case kEventMouseDragged: - if (_properties.get_mouse_mode()==WindowProperties::M_relative) { - GetEventParameter(event, kEventParamMouseDelta,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &qdGlobalPoint); - - MouseData currMouse=get_pointer(0); - qdGlobalPoint.h+=currMouse.get_x(); - qdGlobalPoint.v+=currMouse.get_y(); - } else { - GetEventParameter(event, kEventParamMouseLocation,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &qdGlobalPoint); - SystemPointToLocalPoint(qdGlobalPoint); - } - if (kind == kEventMouseMoved && - (qdGlobalPoint.h < 0 || qdGlobalPoint.v < 0)) { - // Moving into the titlebar region. - set_pointer_out_of_window(); - } else { - // Moving within the window itself (or dragging anywhere). - set_pointer_in_window((int)qdGlobalPoint.h, (int)qdGlobalPoint.v); - } - result = noErr; - - break; - - case kEventMouseWheelMoved: - GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(this_wheel_delta), NULL, &this_wheel_delta); - GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(wheelAxis), NULL, &wheelAxis ); - GetEventParameter(event, kEventParamMouseLocation,typeQDPoint, NULL, sizeof(Point),NULL , (void*) &qdGlobalPoint); - SystemPointToLocalPoint(qdGlobalPoint); - - if (wheelAxis == kEventMouseWheelAxisY) { - set_pointer_in_window((int)qdGlobalPoint.h, (int)qdGlobalPoint.v); - _wheel_delta += this_wheel_delta; - SInt32 wheel_scale = osx_mouse_wheel_scale; - while (_wheel_delta > wheel_scale) { - _input_devices[0]->button_down(MouseButton::wheel_up()); - _input_devices[0]->button_up(MouseButton::wheel_up()); - _wheel_delta -= wheel_scale; - } - while (_wheel_delta < -wheel_scale) { - _input_devices[0]->button_down(MouseButton::wheel_down()); - _input_devices[0]->button_up(MouseButton::wheel_down()); - _wheel_delta += wheel_scale; - } - } - result = noErr; - break; - } - // result = noErr; - - return result; - } - -/** - * MAC Key Codes to Panda Key Codes - */ - ButtonHandle TinyOsxGraphicsWindow::OSX_TranslateKey(UInt32 key, EventRef event) { - - ButtonHandle nk = ButtonHandle::none(); - switch ( key ) { - case 0: nk = KeyboardButton::ascii_key('a'); break; - case 11: nk = KeyboardButton::ascii_key('b'); break; - case 8: nk = KeyboardButton::ascii_key('c'); break; - case 2: nk = KeyboardButton::ascii_key('d'); break; - case 14: nk = KeyboardButton::ascii_key('e'); break; - case 3: nk = KeyboardButton::ascii_key('f'); break; - case 5: nk = KeyboardButton::ascii_key('g'); break; - case 4: nk = KeyboardButton::ascii_key('h'); break; - case 34: nk = KeyboardButton::ascii_key('i'); break; - case 38: nk = KeyboardButton::ascii_key('j'); break; - case 40: nk = KeyboardButton::ascii_key('k'); break; - case 37: nk = KeyboardButton::ascii_key('l'); break; - case 46: nk = KeyboardButton::ascii_key('m'); break; - case 45: nk = KeyboardButton::ascii_key('n'); break; - case 31: nk = KeyboardButton::ascii_key('o'); break; - case 35: nk = KeyboardButton::ascii_key('p'); break; - case 12: nk = KeyboardButton::ascii_key('q'); break; - case 15: nk = KeyboardButton::ascii_key('r'); break; - case 1: nk = KeyboardButton::ascii_key('s'); break; - case 17: nk = KeyboardButton::ascii_key('t'); break; - case 32: nk = KeyboardButton::ascii_key('u'); break; - case 9: nk = KeyboardButton::ascii_key('v'); break; - case 13: nk = KeyboardButton::ascii_key('w'); break; - case 7: nk = KeyboardButton::ascii_key('x'); break; - case 16: nk = KeyboardButton::ascii_key('y'); break; - case 6: nk = KeyboardButton::ascii_key('z'); break; - - // top row numbers - case 29: nk = KeyboardButton::ascii_key('0'); break; - case 18: nk = KeyboardButton::ascii_key('1'); break; - case 19: nk = KeyboardButton::ascii_key('2'); break; - case 20: nk = KeyboardButton::ascii_key('3'); break; - case 21: nk = KeyboardButton::ascii_key('4'); break; - case 23: nk = KeyboardButton::ascii_key('5'); break; - case 22: nk = KeyboardButton::ascii_key('6'); break; - case 26: nk = KeyboardButton::ascii_key('7'); break; - case 28: nk = KeyboardButton::ascii_key('8'); break; - case 25: nk = KeyboardButton::ascii_key('9'); break; - - // key pad ... do they really map to the top number in panda ? - case 82: nk = KeyboardButton::ascii_key('0'); break; - case 83: nk = KeyboardButton::ascii_key('1'); break; - case 84: nk = KeyboardButton::ascii_key('2'); break; - case 85: nk = KeyboardButton::ascii_key('3'); break; - case 86: nk = KeyboardButton::ascii_key('4'); break; - case 87: nk = KeyboardButton::ascii_key('5'); break; - case 88: nk = KeyboardButton::ascii_key('6'); break; - case 89: nk = KeyboardButton::ascii_key('7'); break; - case 91: nk = KeyboardButton::ascii_key('8'); break; - case 92: nk = KeyboardButton::ascii_key('9'); break; - - - // case 36: nk = KeyboardButton::ret(); break; no - // return in panda ??? - case 49: nk = KeyboardButton::space(); break; - case 51: nk = KeyboardButton::backspace(); break; - case 48: nk = KeyboardButton::tab(); break; - case 53: nk = KeyboardButton::escape(); break; - case 76: nk = KeyboardButton::enter(); break; - case 36: nk = KeyboardButton::enter(); break; - - case 123: nk = KeyboardButton::left(); break; - case 124: nk = KeyboardButton::right(); break; - case 125: nk = KeyboardButton::down(); break; - case 126: nk = KeyboardButton::up(); break; - case 116: nk = KeyboardButton::page_up(); break; - case 121: nk = KeyboardButton::page_down(); break; - case 115: nk = KeyboardButton::home(); break; - case 119: nk = KeyboardButton::end(); break; - case 114: nk = KeyboardButton::help(); break; - case 117: nk = KeyboardButton::del(); break; - - // case 71: nk = KeyboardButton::num_lock() break; - - case 122: nk = KeyboardButton::f1(); break; - case 120: nk = KeyboardButton::f2(); break; - case 99: nk = KeyboardButton::f3(); break; - case 118: nk = KeyboardButton::f4(); break; - case 96: nk = KeyboardButton::f5(); break; - case 97: nk = KeyboardButton::f6(); break; - case 98: nk = KeyboardButton::f7(); break; - case 100: nk = KeyboardButton::f8(); break; - case 101: nk = KeyboardButton::f9(); break; - case 109: nk = KeyboardButton::f10(); break; - case 103: nk = KeyboardButton::f11(); break; - case 111: nk = KeyboardButton::f12(); break; - - case 105: nk = KeyboardButton::f13(); break; - case 107: nk = KeyboardButton::f14(); break; - case 113: nk = KeyboardButton::f15(); break; - case 106: nk = KeyboardButton::f16(); break; - - // shiftable chartablet - case 50: nk = KeyboardButton::ascii_key('`'); break; - case 27: nk = KeyboardButton::ascii_key('-'); break; - case 24: nk = KeyboardButton::ascii_key('='); break; - case 33: nk = KeyboardButton::ascii_key('['); break; - case 30: nk = KeyboardButton::ascii_key(']'); break; - case 42: nk = KeyboardButton::ascii_key('\\'); break; - case 41: nk = KeyboardButton::ascii_key(';'); break; - case 39: nk = KeyboardButton::ascii_key('\''); break; - case 43: nk = KeyboardButton::ascii_key(','); break; - case 47: nk = KeyboardButton::ascii_key('.'); break; - case 44: nk = KeyboardButton::ascii_key('/'); break; - - default: - if (tinydisplay_cat.is_debug()) { - tinydisplay_cat.debug() - << " Untranslated KeyCode: " << key - << " (0x" << hex << key << dec << ")\n"; - } - - // not sure this is right .. but no mapping for keypad and such this at - // least does a best gess.. - - char charCode = 0; - if (GetEventParameter( event, kEventParamKeyMacCharCodes, typeChar, nil, sizeof( charCode ), nil, &charCode ) == noErr) - nk = KeyboardButton::ascii_key(charCode); - } - return nk; - } -/** - * Used to emulate key events for the MAC key Modifiers.. - */ - void TinyOsxGraphicsWindow::HandleModifireDeleta(UInt32 newModifiers) { - UInt32 changed = _last_key_modifiers ^ newModifiers; - - if ((changed & (shiftKey | rightShiftKey)) != 0) - SendKeyEvent(KeyboardButton::shift(),(newModifiers & (shiftKey | rightShiftKey)) != 0) ; - - if ((changed & (optionKey | rightOptionKey)) != 0) - SendKeyEvent(KeyboardButton::alt(),(newModifiers & (optionKey | rightOptionKey)) != 0); - - - if ((changed & (controlKey | rightControlKey)) != 0) - SendKeyEvent(KeyboardButton::control(),(newModifiers & (controlKey | rightControlKey)) != 0); - - if ((changed & cmdKey) != 0) - SendKeyEvent(KeyboardButton::meta(),(newModifiers & cmdKey) != 0); - - if ((changed & alphaLock) != 0) - SendKeyEvent(KeyboardButton::caps_lock(),(newModifiers & alphaLock) != 0); - - // save current state - _last_key_modifiers = newModifiers; - }; - -/** - * Used to emulate buttons events - */ -void TinyOsxGraphicsWindow:: -HandleButtonDelta(UInt32 new_buttons) { - UInt32 changed = _last_buttons ^ new_buttons; - - if (changed & 0x01) { - if (new_buttons & 0x01) { - _input_devices[0]->button_down(MouseButton::one()); - } else { - _input_devices[0]->button_up(MouseButton::one()); - } - } - - if (changed & 0x04) { - if (new_buttons & 0x04) { - _input_devices[0]->button_down(MouseButton::two()); - } else { - _input_devices[0]->button_up(MouseButton::two()); - } - } - - if (changed & 0x02) { - if (new_buttons & 0x02) { - _input_devices[0]->button_down(MouseButton::three()); - } else { - _input_devices[0]->button_up(MouseButton::three()); - } - } - - _last_buttons = new_buttons; -} - -/** - * Forces the pointer to the indicated position within the window, if - * possible. - * - * Returns true if successful, false on failure. This may fail if the mouse - * is not currently within the window, or if the API doesn't support this - * operation. - */ -bool TinyOsxGraphicsWindow::move_pointer(int device, int x, int y) { - if (_osx_window == NULL) { - return false; - } - - if (tinydisplay_cat.is_debug()) { - tinydisplay_cat.debug() << "move_pointer " << device <<" "<< x <<" "<< y <<"\n"; - } - - Point pt = {0, 0}; - pt.h = x; - pt.v = y; - set_pointer_in_window(x, y); - - if (_properties.get_mouse_mode() == WindowProperties::M_absolute) { - LocalPointToSystemPoint(pt); - CGPoint newCursorPosition = {0, 0}; - newCursorPosition.x = pt.h; - newCursorPosition.y = pt.v; - mouse_mode_relative(); - CGWarpMouseCursorPosition(newCursorPosition); - mouse_mode_absolute(); - } - - return true; -}; - -bool TinyOsxGraphicsWindow::do_reshape_request(int x_origin, int y_origin, bool has_origin, int x_size, int y_size) { - tinydisplay_cat.info() << "Do Reshape\n"; - - if (_properties.get_fullscreen()) { - return false; - } - - // A coordinate of -2 means to center the window on screen. - if (x_origin == -2 || y_origin == -2 || x_origin == -1 || y_origin == -1) { - if (y_origin == -2) { - y_origin = (_pipe->get_display_height() - y_size) / 2; - } - if (x_origin == -2) { - x_origin = (_pipe->get_display_width() - x_size) / 2; - } - if (y_origin == -1) { - y_origin = 50; - } - if (x_origin == -1) { - x_origin = 10; - } - _properties.set_origin(x_origin, y_origin); - system_changed_properties(_properties); - } - - /* - if (_properties.has_parent_window()) { - if (has_origin) { - NSWindow* parentWindow = (NSWindow *)_properties.get_parent_window(); - NSRect parentFrame = [parentWindow frame]; - - MoveWindow(_osx_window, x_origin+parentFrame.origin.x, y_origin+parentFrame.origin.y, false); - } - } - else*/ - { - // We sometimes get a bogus origin of (0, 0). As a special hack, treat - // this as a special case, and ignore it. - if (has_origin) { - if (x_origin != 0 || y_origin != 0) { - MoveWindow(_osx_window, x_origin, y_origin, false); - } - } - } - - if (!_properties.get_undecorated()) { - // Constrain the window to the available desktop size. - Rect bounds; - GetAvailableWindowPositioningBounds(GetMainDevice(), &bounds); - - x_size = min(x_size, bounds.right - bounds.left); - y_size = min(y_size, bounds.bottom - bounds.top); - } - - SizeWindow(_osx_window, x_size, y_size, false); - - system_changed_size(x_size, y_size); - ZB_resize(_frame_buffer, NULL, _properties.get_x_size(), _properties.get_y_size()); - return true; -} - -/** - * Applies the requested set of properties to the window, if possible, for - * instance to request a change in size or minimization status. - * - * The window properties are applied immediately, rather than waiting until - * the next frame. This implies that this method may *only* be called from - * within the window thread. - * - * The properties that have been applied are cleared from the structure by - * this function; so on return, whatever remains in the properties structure - * are those that were unchanged for some reason (probably because the - * underlying interface does not support changing that property on an open - * window). - */ -void TinyOsxGraphicsWindow::set_properties_now(WindowProperties &properties) { - if (tinydisplay_cat.is_debug()) { - tinydisplay_cat.debug() - << "------------------------------------------------------\n"; - tinydisplay_cat.debug() - << "set_properties_now " << properties << "\n"; - } - - GraphicsWindow::set_properties_now(properties); - - if (tinydisplay_cat.is_debug()) { - tinydisplay_cat.debug() - << "set_properties_now After Base Class" << properties << "\n"; - } - - // for some changes .. a full rebuild is required for the OS layer Window. - // I think it is the crome atribute and full screen behaviour. - bool need_full_rebuild = false; - - // if we are not full and transitioning to full - if (properties.has_fullscreen() && - properties.get_fullscreen() != _properties.get_fullscreen()) { - need_full_rebuild = true; - } - - // If we are fullscreen and requesting a size change - if (_properties.get_fullscreen() && - (properties.has_size() && - (properties.get_x_size() != _properties.get_x_size() || - properties.get_y_size() != _properties.get_y_size()))) { - need_full_rebuild = true; - } - - // If we are fullscreen and requesting a minimize change - if (_properties.get_fullscreen() && - (properties.has_minimized() && - (properties.get_minimized() != _properties.get_minimized()))) { - need_full_rebuild = true; - } - - if (need_full_rebuild) { - // Logic here is .. take a union of the properties .. with the new - // allowed to overwrite the old states. and start a bootstrap of a new - // window .. - - // get a copy of my properties.. - WindowProperties req_properties(_properties); - ReleaseSystemResources(); - req_properties.add_properties(properties); - - OSOpenWindow(req_properties); - - // Now we've handled all of the requested properties. - properties.clear(); - } - - if (properties.has_title()) { - _properties.set_title(properties.get_title()); - if (_osx_window) { - SetWindowTitleWithCFString(_osx_window, - CFStringCreateWithCString(NULL,properties.get_title().c_str(), - kCFStringEncodingMacRoman)); - } - properties.clear_title(); - } - - // An icon filename means to load up the icon and save it. We can't - // necessarily apply it immediately; it will get applied later, in the - // window event handler. - if (properties.has_icon_filename()) { - if (set_icon_filename(properties.get_icon_filename())) { - properties.clear_icon_filename(); - } - } - - // decorated .. if this changes it reqires a new window - if (properties.has_undecorated()) { - _properties.set_undecorated(properties.get_undecorated()); - properties.clear_undecorated(); - } - - if (properties.has_cursor_hidden()) { - _properties.set_cursor_hidden(properties.get_cursor_hidden()); - _cursor_hidden = properties.get_cursor_hidden(); - if (_cursor_hidden && _input_devices[0]->has_pointer()) { - if (!_display_hide_cursor) { - CGDisplayHideCursor(kCGDirectMainDisplay); - _display_hide_cursor = true; - } - } else { - if (_display_hide_cursor) { - CGDisplayShowCursor(kCGDirectMainDisplay); - _display_hide_cursor = false; - } - } - properties.clear_cursor_hidden(); - } - - if (properties.has_minimized()) { - if (_properties.get_minimized() != properties.get_minimized()) { - CollapseWindow(_osx_window, properties.get_minimized()); - _properties.set_minimized(properties.get_minimized()); - _properties.set_foreground(!properties.get_minimized()); - } - properties.clear_minimized(); - } - - if (tinydisplay_cat.is_debug()) { - tinydisplay_cat.debug() - << "set_properties_now Out....." << _properties << "\n"; - } - - return; -} - -/** - - */ -void TinyOsxGraphicsWindow::LocalPointToSystemPoint(Point &qdLocalPoint) { - if (_osx_window != NULL) { - GrafPtr savePort; - Boolean portChanged = QDSwapPort(GetWindowPort(_osx_window), &savePort); - - LocalToGlobal( &qdLocalPoint ); - - if (portChanged) { - QDSwapPort(savePort, NULL); - } - } -} - -/** - * Detaches mouse. Only mouse delta from now on. - */ -void TinyOsxGraphicsWindow::mouse_mode_relative() { - CGAssociateMouseAndMouseCursorPosition(false); -} - -/** - * Reattaches mouse to location - */ -void TinyOsxGraphicsWindow::mouse_mode_absolute() { - CGAssociateMouseAndMouseCursorPosition(true); -} - -/** - * Creates a suitable frame buffer for the current window size. - */ -void TinyOsxGraphicsWindow:: -create_frame_buffer() { - if (_frame_buffer != NULL) { - ZB_close(_frame_buffer); - _frame_buffer = NULL; - } - - _frame_buffer = ZB_open(_properties.get_x_size(), _properties.get_y_size(), ZB_MODE_RGBA, 0, 0, 0, 0); -} - -#endif // IS_OSX From b1018d52ee04b9eea22b0ec3ac0a59bd73c1c4d7 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Jan 2019 17:44:17 -0500 Subject: [PATCH 020/144] makepanda: remove ability to target Mac OS X 10.6 "Snow Leopard" This effectively ends support for 32-bit Intel Macs. It switches the standard library to libc++, allowing us to use features from C++11. There are some known bugs with older versions of libc++ (such as the istream::eof() bug); we may end up raising the minimum further (eg. to 10.9) soon if the situation becomes untenable. Fixes #300 --- README.md | 5 +-- makepanda/makepanda.py | 96 ++++++++++++------------------------------ 2 files changed, 29 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index a5422499d8..bc2b9b436b 100644 --- a/README.md +++ b/README.md @@ -135,9 +135,8 @@ you may build Panda3D using a command like the following: python makepanda/makepanda.py --everything --installer ``` -In order to make a universal build, pass the --universal flag. You may also -target a specific minimum macOS version using the --osxtarget flag followed -by the release number, eg. 10.6 or 10.7. +You may target a specific minimum macOS version using the --osxtarget flag +followed by the release number, eg. 10.7 or 10.9. If the build was successful, makepanda will have generated a .dmg file in the source directory containing the installer. Simply open it and run the diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index b39c09dce4..d4da013852 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -63,7 +63,6 @@ MAJOR_VERSION=None COREAPI_VERSION=None PLUGIN_VERSION=None OSXTARGET=None -OSX_ARCHS=[] HOST_URL=None global STRDXSDKVERSION, BOOUSEINTELCOMPILER STRDXSDKVERSION = 'default' @@ -142,7 +141,6 @@ def usage(problem): print(" --host URL (set the host url (runtime build only))") print(" --threads N (use the multithreaded build system. see manual)") print(" --osxtarget N (the OS X version number to build for (OS X only))") - print(" --universal (build universal binaries (OS X only))") print(" --override \"O=V\" (override dtool_config/prc option value)") print(" --static (builds libraries for static linking)") print(" --target X (experimental cross-compilation (android only))") @@ -170,7 +168,7 @@ def usage(problem): def parseopts(args): global INSTALLER,WHEEL,RUNTESTS,RTDIST,RUNTIME,GENMAN,DISTRIBUTOR,VERSION - global COMPRESSOR,THREADCOUNT,OSXTARGET,OSX_ARCHS,HOST_URL + global COMPRESSOR,THREADCOUNT,OSXTARGET,HOST_URL global DEBVERSION,WHLVERSION,RPMRELEASE,GIT_COMMIT,P3DSUFFIX,RTDIST_VERSION global STRDXSDKVERSION, WINDOWS_SDK, MSVC_VERSION, BOOUSEINTELCOMPILER global COPY_PYTHON @@ -178,7 +176,7 @@ def parseopts(args): # Options for which to display a deprecation warning. removedopts = [ "use-touchinput", "no-touchinput", "no-awesomium", "no-directscripts", - "no-carbon", + "no-carbon", "universal", ] # All recognized options. @@ -188,14 +186,13 @@ def parseopts(args): "version=","lzma","no-python","threads=","outputdir=","override=", "static","host=","debversion=","rpmrelease=","p3dsuffix=","rtdist-version=", "directx-sdk=", "windows-sdk=", "msvc-version=", "clean", "use-icl", - "universal", "target=", "arch=", "git-commit=", "no-copy-python", + "target=", "arch=", "git-commit=", "no-copy-python", ] + removedopts anything = 0 optimize = "" target = None target_arch = None - universal = False clean_build = False for pkg in PkgListGet(): longopts.append("use-" + pkg.lower()) @@ -221,7 +218,6 @@ def parseopts(args): elif (option=="--threads"): THREADCOUNT=int(value) elif (option=="--outputdir"): SetOutputDir(value.strip()) elif (option=="--osxtarget"): OSXTARGET=value.strip() - elif (option=="--universal"): universal = True elif (option=="--target"): target = value.strip() elif (option=="--arch"): target_arch = value.strip() elif (option=="--nocolor"): DisableColors() @@ -303,25 +299,6 @@ def parseopts(args): if target is not None or target_arch is not None: SetTarget(target, target_arch) - if universal: - if target_arch: - exit("--universal is incompatible with --arch") - - OSX_ARCHS.append("i386") - if OSXTARGET: - osxver = OSXTARGET - else: - maj, min = platform.mac_ver()[0].split('.')[:2] - osxver = int(maj), int(min) - - if osxver[1] < 6: - OSX_ARCHS.append("ppc") - else: - OSX_ARCHS.append("x86_64") - - elif HasTargetArch(): - OSX_ARCHS.append(GetTargetArch()) - try: SetOptimize(int(optimize)) assert GetOptimize() in [1, 2, 3, 4] @@ -433,22 +410,7 @@ elif target == 'darwin': maj, min = platform.mac_ver()[0].split('.')[:2] osxver = int(maj), int(min) - arch_tag = None - if not OSX_ARCHS: - arch_tag = GetTargetArch() - elif len(OSX_ARCHS) == 1: - arch_tag = OSX_ARCHS[0] - elif frozenset(OSX_ARCHS) == frozenset(('i386', 'ppc')): - arch_tag = 'fat' - elif frozenset(OSX_ARCHS) == frozenset(('x86_64', 'i386')): - arch_tag = 'intel' - elif frozenset(OSX_ARCHS) == frozenset(('x86_64', 'ppc64')): - arch_tag = 'fat64' - elif frozenset(OSX_ARCHS) == frozenset(('x86_64', 'i386', 'ppc')): - arch_tag = 'fat32' - else: - raise RuntimeError('No arch tag for arch combination %s' % OSX_ARCHS) - + arch_tag = GetTargetArch() PLATFORM = 'macosx-{0}.{1}-{2}'.format(osxver[0], osxver[1], arch_tag) elif target == 'linux' and (os.path.isfile("/lib/libc-2.5.so") or os.path.isfile("/lib64/libc-2.5.so")) and os.path.isdir("/opt/python"): @@ -934,7 +896,6 @@ if (COMPILER=="GCC"): if not PkgSkip("FFMPEG"): if GetTarget() == "darwin": - LibName("FFMPEG", "-Wl,-read_only_relocs,suppress") LibName("FFMPEG", "-framework VideoDecodeAcceleration") elif os.path.isfile(GetThirdpartyDir() + "ffmpeg/lib/libavcodec.a"): # Needed when linking ffmpeg statically on Linux. @@ -1347,9 +1308,11 @@ def CompileCxx(obj,src,opts): cmd += " -isysroot " + SDK["MACOSX"] cmd += " -mmacosx-version-min=%d.%d" % (OSXTARGET) - for arch in OSX_ARCHS: - if 'NOARCH:' + arch.upper() not in opts: - cmd += " -arch %s" % arch + # Use libc++ to enable C++11 features. + cmd += " -stdlib=libc++" + + arch = GetTargetArch() + cmd += " -arch %s" % arch if "SYSROOT" in SDK: if GetTarget() != "android": @@ -1867,9 +1830,11 @@ def CompileLink(dll, obj, opts): cmd += " -isysroot " + SDK["MACOSX"] + " -Wl,-syslibroot," + SDK["MACOSX"] cmd += " -mmacosx-version-min=%d.%d" % (OSXTARGET) - for arch in OSX_ARCHS: - if 'NOARCH:' + arch.upper() not in opts: - cmd += " -arch %s" % arch + # Use libc++ to enable C++11 features. + cmd += " -stdlib=libc++" + + arch = GetTargetArch() + cmd += " -arch %s" % arch elif GetTarget() == 'android': arch = GetTargetArch() @@ -2120,10 +2085,10 @@ def Package(target, inputs, opts): if SDK.get("MACOSX"): command += " -R \"%s\"" % SDK["MACOSX"] - for arch in OSX_ARCHS: - if arch == "x86_64": - arch = "amd64" - command += " -P osx_%s" % arch + arch = GetTargetArch() + if arch == "x86_64": + arch = "amd64" + command += " -P osx_%s" % arch command += " -i \"" + GetOutputDir() + "/stage\"" if (P3DSUFFIX): @@ -5009,10 +4974,10 @@ if (PkgSkip("BULLET")==0 and not RUNTIME): # if (PkgSkip("PHYSX")==0): - OPTS=['DIR:panda/src/physx', 'BUILDING:PANDAPHYSX', 'PHYSX', 'NOARCH:PPC'] + OPTS=['DIR:panda/src/physx', 'BUILDING:PANDAPHYSX', 'PHYSX'] TargetAdd('p3physx_composite.obj', opts=OPTS, input='p3physx_composite.cxx') - OPTS=['DIR:panda/src/physx', 'PHYSX', 'NOARCH:PPC'] + OPTS=['DIR:panda/src/physx', 'PHYSX'] IGATEFILES=GetDirectoryContents('panda/src/physx', ["*.h", "*_composite*.cxx"]) TargetAdd('libpandaphysx.in', opts=OPTS, input=IGATEFILES) TargetAdd('libpandaphysx.in', opts=['IMOD:panda3d.physx', 'ILIB:libpandaphysx', 'SRCDIR:panda/src/physx']) @@ -5022,15 +4987,15 @@ if (PkgSkip("PHYSX")==0): # if (PkgSkip("PHYSX")==0): - OPTS=['DIR:panda/metalibs/pandaphysx', 'BUILDING:PANDAPHYSX', 'PHYSX', 'NOARCH:PPC', 'PYTHON'] + OPTS=['DIR:panda/metalibs/pandaphysx', 'BUILDING:PANDAPHYSX', 'PHYSX', 'PYTHON'] TargetAdd('pandaphysx_pandaphysx.obj', opts=OPTS, input='pandaphysx.cxx') TargetAdd('libpandaphysx.dll', input='pandaphysx_pandaphysx.obj') TargetAdd('libpandaphysx.dll', input='p3physx_composite.obj') TargetAdd('libpandaphysx.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libpandaphysx.dll', opts=['WINUSER', 'PHYSX', 'NOARCH:PPC', 'PYTHON']) + TargetAdd('libpandaphysx.dll', opts=['WINUSER', 'PHYSX', 'PYTHON']) - OPTS=['DIR:panda/metalibs/pandaphysx', 'PHYSX', 'NOARCH:PPC'] + OPTS=['DIR:panda/metalibs/pandaphysx', 'PHYSX'] PyTargetAdd('physx_module.obj', input='libpandaphysx.in') PyTargetAdd('physx_module.obj', opts=OPTS) PyTargetAdd('physx_module.obj', opts=['IMOD:panda3d.physx', 'ILIB:physx', 'IMPORT:panda3d.core']) @@ -5040,7 +5005,7 @@ if (PkgSkip("PHYSX")==0): PyTargetAdd('physx.pyd', input='libpandaphysx.dll') PyTargetAdd('physx.pyd', input='libp3interrogatedb.dll') PyTargetAdd('physx.pyd', input=COMMON_PANDA_LIBS) - PyTargetAdd('physx.pyd', opts=['WINUSER', 'PHYSX', 'NOARCH:PPC']) + PyTargetAdd('physx.pyd', opts=['WINUSER', 'PHYSX']) # # DIRECTORY: panda/src/physics/ @@ -6452,16 +6417,9 @@ if not PkgSkip("PANDATOOL"): for VER in MAYAVERSIONS: VNUM = VER[4:] if not PkgSkip(VER) and not PkgSkip("PANDATOOL") and not PkgSkip("EGG"): - if GetTarget() == 'darwin' and int(VNUM) >= 2012: - ARCH_OPTS = ['NOARCH:PPC', 'NOARCH:I386'] - if len(OSX_ARCHS) != 0 and 'x86_64' not in OSX_ARCHS: - continue - elif GetTarget() == 'darwin' and int(VNUM) >= 2009: - ARCH_OPTS = ['NOARCH:PPC'] - elif GetTarget() == 'darwin': - ARCH_OPTS = ['NOARCH:X86_64'] - else: - ARCH_OPTS = [] + if GetTarget() == 'darwin' and int(VNUM) < 2009: + # No x86_64 support. + continue OPTS=['DIR:pandatool/src/mayaprogs', 'DIR:pandatool/src/maya', 'DIR:pandatool/src/mayaegg', 'DIR:pandatool/src/cvscopy', 'BUILDING:MISC', VER] + ARCH_OPTS TargetAdd('mayaeggimport'+VNUM+'_mayaeggimport.obj', opts=OPTS, input='mayaEggImport.cxx') From 7c6e677a23eb76e02230881431cf773f9153a942 Mon Sep 17 00:00:00 2001 From: Brian Lach Date: Thu, 10 Jan 2019 01:29:24 +0100 Subject: [PATCH 021/144] dtoolbase: add std::initializer_list constructors for pvector, epvector, pdeque, plist, pset, pmultiset Closes #520 --- dtool/src/dtoolbase/epvector.h | 3 +++ dtool/src/dtoolbase/pdeque.h | 3 ++- dtool/src/dtoolbase/plist.h | 2 ++ dtool/src/dtoolbase/pset.h | 4 ++++ dtool/src/dtoolbase/pvector.h | 2 ++ 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/dtool/src/dtoolbase/epvector.h b/dtool/src/dtoolbase/epvector.h index e743ea4060..f97c80cda3 100644 --- a/dtool/src/dtoolbase/epvector.h +++ b/dtool/src/dtoolbase/epvector.h @@ -20,6 +20,8 @@ #include +#include + /** * Unfortunately, on Windows, std::vector can't be used for classes with * explicitly alignment requirements, due to a minor mistake in the template @@ -46,6 +48,7 @@ public: epvector(size_type n, TypeHandle type_handle = pvector_type_handle) : base_class(n, Type(), allocator()) { } epvector(size_type n, const Type &value, TypeHandle type_handle = pvector_type_handle) : base_class(n, value, allocator()) { } epvector(const Type *begin, const Type *end, TypeHandle type_handle = pvector_type_handle) : base_class(begin, end, allocator()) { } + epvector(std::initializer_list init, TypeHandle type_handle = pvector_type_handle) : base_class(std::move(init), allocator()) { } }; #else // HAVE_EIGEN diff --git a/dtool/src/dtoolbase/pdeque.h b/dtool/src/dtoolbase/pdeque.h index e7e9f96c28..2b5e5793aa 100644 --- a/dtool/src/dtoolbase/pdeque.h +++ b/dtool/src/dtoolbase/pdeque.h @@ -18,7 +18,7 @@ #include "pallocator.h" #include "register_type.h" #include - +#include #if !defined(USE_STL_ALLOCATOR) || defined(CPPPARSER) // If we're not using custom allocators, just use the standard class @@ -40,6 +40,7 @@ public: pdeque(TypeHandle type_handle = pdeque_type_handle) : std::deque >(allocator(type_handle)) { } pdeque(size_type n, TypeHandle type_handle = pdeque_type_handle) : std::deque >(n, Type(), allocator(type_handle)) { } pdeque(size_type n, const Type &value, TypeHandle type_handle = pdeque_type_handle) : std::deque >(n, value, allocator(type_handle)) { } + pdeque(std::initializer_list init, TypeHandle type_handle = pdeque_type_handle) : std::deque >(std::move(init), allocator(type_handle)) { } }; #endif // USE_STL_ALLOCATOR diff --git a/dtool/src/dtoolbase/plist.h b/dtool/src/dtoolbase/plist.h index 12d29880f3..b9810342b5 100644 --- a/dtool/src/dtoolbase/plist.h +++ b/dtool/src/dtoolbase/plist.h @@ -18,6 +18,7 @@ #include "pallocator.h" #include "register_type.h" #include +#include #if !defined(USE_STL_ALLOCATOR) || defined(CPPPARSER) // If we're not using custom allocators, just use the standard class @@ -40,6 +41,7 @@ public: plist(TypeHandle type_handle = plist_type_handle) : base_class(allocator(type_handle)) { } plist(size_type n, TypeHandle type_handle = plist_type_handle) : base_class(n, Type(), allocator(type_handle)) { } plist(size_type n, const Type &value, TypeHandle type_handle = plist_type_handle) : base_class(n, value, allocator(type_handle)) { } + plist(std::initializer_list init, TypeHandle type_handle = plist_type_handle) : base_class(std::move(init), allocator(type_handle)) { } typedef typename base_class::iterator iterator; typedef typename base_class::const_iterator const_iterator; diff --git a/dtool/src/dtoolbase/pset.h b/dtool/src/dtoolbase/pset.h index ff54486dfe..feece41b5b 100644 --- a/dtool/src/dtoolbase/pset.h +++ b/dtool/src/dtoolbase/pset.h @@ -24,6 +24,8 @@ #include #endif +#include + #if !defined(USE_STL_ALLOCATOR) || defined(CPPPARSER) // If we're not using custom allocators, just use the standard class // definition. @@ -52,6 +54,7 @@ public: typedef std::set base_class; pset(TypeHandle type_handle = pset_type_handle) : base_class(Compare(), allocator(type_handle)) { } pset(const Compare &comp, TypeHandle type_handle = pset_type_handle) : base_class(comp, type_handle) { } + pset(std::initializer_list init, TypeHandle type_handle = pset_type_handle) : base_class(std::move(init), allocator(type_handle)) { } #ifdef USE_TAU std::pair @@ -110,6 +113,7 @@ public: typedef pallocator_single allocator; pmultiset(TypeHandle type_handle = pset_type_handle) : std::multiset(Compare(), allocator(type_handle)) { } pmultiset(const Compare &comp, TypeHandle type_handle = pset_type_handle) : std::multiset(comp, type_handle) { } + pmultiset(std::initializer_list init, TypeHandle type_handle = pset_type_handle) : std::multiset(std::move(init), allocator(type_handle)) { } }; #ifdef HAVE_STL_HASH diff --git a/dtool/src/dtoolbase/pvector.h b/dtool/src/dtoolbase/pvector.h index 4199506d13..be60897d21 100644 --- a/dtool/src/dtoolbase/pvector.h +++ b/dtool/src/dtoolbase/pvector.h @@ -15,6 +15,7 @@ #define PVECTOR_H #include +#include #include "dtoolbase.h" #include "pallocator.h" @@ -51,6 +52,7 @@ public: explicit pvector(size_type n, TypeHandle type_handle = pvector_type_handle) : base_class(n, Type(), allocator(type_handle)) { } explicit pvector(size_type n, const Type &value, TypeHandle type_handle = pvector_type_handle) : base_class(n, value, allocator(type_handle)) { } pvector(const Type *begin, const Type *end, TypeHandle type_handle = pvector_type_handle) : base_class(begin, end, allocator(type_handle)) { } + pvector(std::initializer_list init, TypeHandle type_handle = pvector_type_handle) : base_class(std::move(init), allocator(type_handle)) { } pvector &operator =(const pvector ©) { base_class::operator =(copy); From 0ff40944a762b82c217a9988f84bd3178bc43a37 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 10 Jan 2019 13:30:02 +0100 Subject: [PATCH 022/144] makepanda: fix a regression building with Maya on macOS [skip ci] --- makepanda/makepanda.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index d4da013852..f029b14868 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -6421,7 +6421,7 @@ for VER in MAYAVERSIONS: # No x86_64 support. continue - OPTS=['DIR:pandatool/src/mayaprogs', 'DIR:pandatool/src/maya', 'DIR:pandatool/src/mayaegg', 'DIR:pandatool/src/cvscopy', 'BUILDING:MISC', VER] + ARCH_OPTS + OPTS=['DIR:pandatool/src/mayaprogs', 'DIR:pandatool/src/maya', 'DIR:pandatool/src/mayaegg', 'DIR:pandatool/src/cvscopy', 'BUILDING:MISC', VER] TargetAdd('mayaeggimport'+VNUM+'_mayaeggimport.obj', opts=OPTS, input='mayaEggImport.cxx') TargetAdd('mayaeggimport'+VNUM+'.mll', input='mayaegg'+VNUM+'_loader.obj') TargetAdd('mayaeggimport'+VNUM+'.mll', input='mayaeggimport'+VNUM+'_mayaeggimport.obj') @@ -6429,7 +6429,7 @@ for VER in MAYAVERSIONS: TargetAdd('mayaeggimport'+VNUM+'.mll', input=COMMON_PANDA_LIBS) #if GetTarget() == 'windows': # TargetAdd('mayaeggimport'+VNUM+'.mll', input='libp3pystub.lib') - TargetAdd('mayaeggimport'+VNUM+'.mll', opts=['ADVAPI', VER]+ARCH_OPTS) + TargetAdd('mayaeggimport'+VNUM+'.mll', opts=['ADVAPI', VER]) TargetAdd('mayaloader'+VNUM+'_config_mayaloader.obj', opts=OPTS, input='config_mayaloader.cxx') TargetAdd('libp3mayaloader'+VNUM+'.dll', input='mayaloader'+VNUM+'_config_mayaloader.obj') @@ -6453,7 +6453,7 @@ for VER in MAYAVERSIONS: TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3pandatoolbase.lib') TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libpandaegg.dll') TargetAdd('libp3mayaloader'+VNUM+'.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libp3mayaloader'+VNUM+'.dll', opts=['ADVAPI', VER]+ARCH_OPTS) + TargetAdd('libp3mayaloader'+VNUM+'.dll', opts=['ADVAPI', VER]) TargetAdd('mayapview'+VNUM+'_mayaPview.obj', opts=OPTS, input='mayaPview.cxx') TargetAdd('libmayapview'+VNUM+'.mll', input='mayapview'+VNUM+'_mayaPview.obj') @@ -6464,7 +6464,7 @@ for VER in MAYAVERSIONS: TargetAdd('libmayapview'+VNUM+'.mll', input=COMMON_EGG2X_LIBS) else: TargetAdd('libmayapview'+VNUM+'.mll', input=COMMON_EGG2X_LIBS) - TargetAdd('libmayapview'+VNUM+'.mll', opts=['ADVAPI', VER]+ARCH_OPTS) + TargetAdd('libmayapview'+VNUM+'.mll', opts=['ADVAPI', VER]) TargetAdd('maya2egg'+VNUM+'_mayaToEgg.obj', opts=OPTS, input='mayaToEgg.cxx') TargetAdd('maya2egg'+VNUM+'_bin.exe', input='maya2egg'+VNUM+'_mayaToEgg.obj') @@ -6474,7 +6474,7 @@ for VER in MAYAVERSIONS: TargetAdd('maya2egg'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS) else: TargetAdd('maya2egg'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS) - TargetAdd('maya2egg'+VNUM+'_bin.exe', opts=['ADVAPI', VER]+ARCH_OPTS) + TargetAdd('maya2egg'+VNUM+'_bin.exe', opts=['ADVAPI', VER]) TargetAdd('egg2maya'+VNUM+'_eggToMaya.obj', opts=OPTS, input='eggToMaya.cxx') TargetAdd('egg2maya'+VNUM+'_bin.exe', input='egg2maya'+VNUM+'_eggToMaya.obj') @@ -6484,7 +6484,7 @@ for VER in MAYAVERSIONS: TargetAdd('egg2maya'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS) else: TargetAdd('egg2maya'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS) - TargetAdd('egg2maya'+VNUM+'_bin.exe', opts=['ADVAPI', VER]+ARCH_OPTS) + TargetAdd('egg2maya'+VNUM+'_bin.exe', opts=['ADVAPI', VER]) TargetAdd('mayacopy'+VNUM+'_mayaCopy.obj', opts=OPTS, input='mayaCopy.cxx') TargetAdd('mayacopy'+VNUM+'_bin.exe', input='mayacopy'+VNUM+'_mayaCopy.obj') @@ -6494,28 +6494,28 @@ for VER in MAYAVERSIONS: TargetAdd('mayacopy'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS) else: TargetAdd('mayacopy'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS) - TargetAdd('mayacopy'+VNUM+'_bin.exe', opts=['ADVAPI', VER]+ARCH_OPTS) + TargetAdd('mayacopy'+VNUM+'_bin.exe', opts=['ADVAPI', VER]) TargetAdd('mayasavepview'+VNUM+'_mayaSavePview.obj', opts=OPTS, input='mayaSavePview.cxx') TargetAdd('libmayasavepview'+VNUM+'.mll', input='mayasavepview'+VNUM+'_mayaSavePview.obj') - TargetAdd('libmayasavepview'+VNUM+'.mll', opts=['ADVAPI', VER]+ARCH_OPTS) + TargetAdd('libmayasavepview'+VNUM+'.mll', opts=['ADVAPI', VER]) TargetAdd('mayapath'+VNUM+'.obj', opts=OPTS, input='mayapath.cxx') TargetAdd('maya2egg'+VNUM+'.exe', input='mayapath'+VNUM+'.obj') TargetAdd('maya2egg'+VNUM+'.exe', input='libpandaexpress.dll') TargetAdd('maya2egg'+VNUM+'.exe', input=COMMON_DTOOL_LIBS) - TargetAdd('maya2egg'+VNUM+'.exe', opts=['ADVAPI']+ARCH_OPTS) + TargetAdd('maya2egg'+VNUM+'.exe', opts=['ADVAPI']) TargetAdd('egg2maya'+VNUM+'.exe', input='mayapath'+VNUM+'.obj') TargetAdd('egg2maya'+VNUM+'.exe', input='libpandaexpress.dll') TargetAdd('egg2maya'+VNUM+'.exe', input=COMMON_DTOOL_LIBS) - TargetAdd('egg2maya'+VNUM+'.exe', opts=['ADVAPI']+ARCH_OPTS) + TargetAdd('egg2maya'+VNUM+'.exe', opts=['ADVAPI']) TargetAdd('mayacopy'+VNUM+'.exe', input='mayapath'+VNUM+'.obj') TargetAdd('mayacopy'+VNUM+'.exe', input='libpandaexpress.dll') TargetAdd('mayacopy'+VNUM+'.exe', input=COMMON_DTOOL_LIBS) - TargetAdd('mayacopy'+VNUM+'.exe', opts=['ADVAPI']+ARCH_OPTS) + TargetAdd('mayacopy'+VNUM+'.exe', opts=['ADVAPI']) # # DIRECTORY: contrib/src/ai/ From ba6a51dbc18cc376ae557be1394789ccba887501 Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 11 Jan 2019 00:05:59 +0700 Subject: [PATCH 023/144] 1.10.0 release readme update Closes #525 --- README.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a5422499d8..596c134f46 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ Panda3D Panda3D is a game engine, a framework for 3D rendering and game development for Python and C++ programs. Panda3D is open-source and free for any purpose, including commercial ventures, thanks to its -[liberal license](https://www.panda3d.org/license.php). To learn more about -Panda3D's capabilities, visit the [gallery](https://www.panda3d.org/gallery.php) -and the [feature list](https://www.panda3d.org/features.php). To learn how to -use Panda3D, check the [documentation](https://www.panda3d.org/documentation.php) +[liberal license](https://www.panda3d.org/license/). To learn more about +Panda3D's capabilities, visit the [gallery](https://www.panda3d.org/gallery/) +and the [feature list](https://www.panda3d.org/features/). To learn how to +use Panda3D, check the [documentation](https://www.panda3d.org/documentation/) resources. If you get stuck, ask for help from our active -[community](https://www.panda3d.org/community.php). +[community](https://discourse.panda3d.org). Panda3D is licensed under the Modified BSD License. See the LICENSE file for more details. @@ -21,7 +21,16 @@ more details. Installing Panda3D ================== -By far, the easiest way to install the latest development build of Panda3D +The latest Panda3D SDK can be downloaded from +(this page)[https://www.panda3d.org/download/sdk-1-10-0/]. +If you are familiar with installing Python packages, you can use +the following comand: + +```bash +pip install panda3d +``` + +The easiest way to install the latest development build of Panda3D into an existing Python installation is using the following command: ```bash @@ -31,9 +40,7 @@ pip install --pre --extra-index-url https://archive.panda3d.org/ panda3d If this command fails, please make sure your version of pip is up-to-date. If you prefer to install the full SDK with all tools, the latest development -builds can be obtained from this page: - -https://www.panda3d.org/download.php?sdk&version=devel +builds can be obtained from (this page)[https://www.panda3d.org/download/]. These are automatically kept up-to-date with the latest GitHub version of Panda. @@ -96,7 +103,7 @@ python makepanda/makepanda.py --everything --installer --no-egl --no-gles --no-g You will probably see some warnings saying that it's unable to find several dependency packages. You should determine which ones you want to include in your build and install the respective development packages. You may visit -[this manual page](https://www.panda3d.org/manual/index.php/Dependencies) +[this manual page](https://www.panda3d.org/manual/?title=Third-party_dependencies_and_license_info) for an overview of the various dependencies. If you are on Ubuntu, this command should cover the most frequently From 83e41262bd17241c8ecdedf713c245b84791bd96 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 10 Jan 2019 21:33:31 +0100 Subject: [PATCH 024/144] makewheel: use all supported Python versions as classifier Otherwise, PyPI wil pick the ones for the first uploaded wheel, which means that Panda3D will not be indexed under all Python versions on PyPI. Also add a few more classifiers. --- makepanda/makewheel.py | 5 ----- setup.cfg | 11 +++++++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/makepanda/makewheel.py b/makepanda/makewheel.py index 18f92379b8..6dd2b32ef4 100644 --- a/makepanda/makewheel.py +++ b/makepanda/makewheel.py @@ -526,11 +526,6 @@ def makewheel(version, output_dir, platform=None): # Update relevant METADATA entries METADATA['version'] = version - version_classifiers = [ - "Programming Language :: Python :: {0}".format(*sys.version_info), - "Programming Language :: Python :: {0}.{1}".format(*sys.version_info), - ] - METADATA['classifiers'].extend(version_classifiers) # Build out the metadata details = METADATA["extensions"]["python.details"] diff --git a/setup.cfg b/setup.cfg index 8a1a50afe0..a51084e2e8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,10 +13,21 @@ classifiers = Operating System :: OS Independent Programming Language :: C++ Programming Language :: Python + Programming Language :: Python :: 2 + Programming Language :: Python :: 2.7 + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.4 + Programming Language :: Python :: 3.5 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: Implementation :: CPython Topic :: Games/Entertainment Topic :: Multimedia Topic :: Multimedia :: Graphics Topic :: Multimedia :: Graphics :: 3D Rendering + Topic :: Software Development :: Libraries + Topic :: Software Development :: Libraries :: Application Frameworks + Topic :: Software Development :: Libraries :: Python Modules author = Panda3D Team author_email = etc-panda3d@lists.andrew.cmu.edu From 84a13151049b6acc74e7ecfbe55ae48631378ac1 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 10 Jan 2019 21:41:18 +0100 Subject: [PATCH 025/144] More fixes to work around broken libc++ eof() in Mac OS X 10.7 --- dtool/src/prc/streamReader.cxx | 19 +++++++++++++++---- dtool/src/prc/streamReader_ext.cxx | 4 ++-- panda/src/downloader/decompressor.cxx | 4 ++-- panda/src/downloader/documentSpec.cxx | 4 ++-- panda/src/downloader/httpChannel.cxx | 4 ++-- panda/src/downloader/httpDate.cxx | 2 +- panda/src/downloader/socketStream.cxx | 2 +- panda/src/express/hashVal.cxx | 4 ++-- panda/src/express/make_ca_bundle.cxx | 2 +- panda/src/express/multifile.cxx | 9 ++++----- panda/src/gobj/texture.cxx | 4 ++-- panda/src/pnmimage/pnmimage_base.cxx | 8 ++++---- pandatool/src/miscprogs/binToC.cxx | 2 +- 13 files changed, 39 insertions(+), 29 deletions(-) diff --git a/dtool/src/prc/streamReader.cxx b/dtool/src/prc/streamReader.cxx index 74f278e220..3286eca67a 100644 --- a/dtool/src/prc/streamReader.cxx +++ b/dtool/src/prc/streamReader.cxx @@ -26,6 +26,9 @@ get_string() { // First, get the length of the string size_t size = get_uint16(); + if (size == 0) { + return string(); + } char *buffer = (char *)alloca(size); _in->read(buffer, size); @@ -42,6 +45,9 @@ get_string32() { // First, get the length of the string size_t size = get_uint32(); + if (size == 0) { + return string(); + } char *buffer = (char *)PANDA_MALLOC_ARRAY(size); _in->read(buffer, size); @@ -60,7 +66,7 @@ get_z_string() { string result; int ch = _in->get(); - while (!_in->eof() && !_in->fail() && ch != '\0') { + while (!_in->fail() && ch != EOF && ch != '\0') { result += (char)ch; ch = _in->get(); } @@ -76,6 +82,10 @@ string StreamReader:: get_fixed_string(size_t size) { nassertr(!_in->eof() && !_in->fail(), string()); + if (size == 0) { + return string(); + } + char *buffer = (char *)alloca(size); _in->read(buffer, size); size_t read_bytes = _in->gcount(); @@ -90,8 +100,9 @@ get_fixed_string(size_t size) { */ void StreamReader:: skip_bytes(size_t size) { - nassertv(!_in->eof() && !_in->fail()); + nassertv(!_in->fail()); nassertv((int)size >= 0); + nassertv(size == 0 || !_in->eof()); while (size > 0) { _in->get(); @@ -145,9 +156,9 @@ string StreamReader:: readline() { string line; int ch = _in->get(); - while (!_in->eof() && !_in->fail()) { + while (ch != EOF && !_in->fail()) { line += (char)ch; - if (ch == '\n') { + if (ch == '\n' || _in->eof()) { // Here's the newline character. return line; } diff --git a/dtool/src/prc/streamReader_ext.cxx b/dtool/src/prc/streamReader_ext.cxx index 94c346e370..8e1b2b42ec 100644 --- a/dtool/src/prc/streamReader_ext.cxx +++ b/dtool/src/prc/streamReader_ext.cxx @@ -45,9 +45,9 @@ readline() { std::string line; int ch = in->get(); - while (!in->eof() && !in->fail()) { + while (ch != EOF && !in->fail()) { line += ch; - if (ch == '\n') { + if (ch == '\n' || in->eof()) { // Here's the newline character. break; } diff --git a/panda/src/downloader/decompressor.cxx b/panda/src/downloader/decompressor.cxx index 272279047d..bc4822ee91 100644 --- a/panda/src/downloader/decompressor.cxx +++ b/panda/src/downloader/decompressor.cxx @@ -183,7 +183,7 @@ decompress(const Filename &source_file) { return false; int ch = _decompress->get(); - while (!_decompress->eof() && !_decompress->fail()) { + while (ch != EOF && !_decompress->fail()) { _dest->put(ch); ch = _decompress->get(); } @@ -207,7 +207,7 @@ decompress(Ramfile &source_and_dest_file) { IDecompressStream decompress(&source, false); int ch = decompress.get(); - while (!decompress.eof() && !decompress.fail()) { + while (ch != EOF && !decompress.fail()) { dest.put(ch); ch = decompress.get(); } diff --git a/panda/src/downloader/documentSpec.cxx b/panda/src/downloader/documentSpec.cxx index 6ca2a9b260..34bfe3808d 100644 --- a/panda/src/downloader/documentSpec.cxx +++ b/panda/src/downloader/documentSpec.cxx @@ -66,7 +66,7 @@ input(std::istream &in) { // Scan the tag, up to but not including the closing paren. std::string tag; in >> ch; - while (!in.fail() && !in.eof() && ch != ')') { + while (!in.fail() && ch != EOF && ch != ')') { tag += ch; // We want to include embedded whitespace, so we use get(). ch = in.get(); @@ -81,7 +81,7 @@ input(std::istream &in) { // Scan the date, up to but not including the closing bracket. if (ch != ']') { std::string date; - while (!in.fail() && !in.eof() && ch != ']') { + while (!in.fail() && ch != EOF && ch != ']') { date += ch; ch = in.get(); } diff --git a/panda/src/downloader/httpChannel.cxx b/panda/src/downloader/httpChannel.cxx index 17c12d806a..365c819b0f 100644 --- a/panda/src/downloader/httpChannel.cxx +++ b/panda/src/downloader/httpChannel.cxx @@ -2762,7 +2762,7 @@ bool HTTPChannel:: server_getline(string &str) { nassertr(!_source.is_null(), false); int ch = (*_source)->get(); - while (!(*_source)->eof() && !(*_source)->fail()) { + while (ch != EOF && !(*_source)->fail()) { switch (ch) { case '\n': // end-of-line character, we're done. @@ -2850,7 +2850,7 @@ bool HTTPChannel:: server_get(string &str, size_t num_bytes) { nassertr(!_source.is_null(), false); int ch = (*_source)->get(); - while (!(*_source)->eof() && !(*_source)->fail()) { + while (ch != EOF && !(*_source)->fail()) { _working_get += (char)ch; if (_working_get.length() >= num_bytes) { str = _working_get; diff --git a/panda/src/downloader/httpDate.cxx b/panda/src/downloader/httpDate.cxx index a651b50f89..e49769257f 100644 --- a/panda/src/downloader/httpDate.cxx +++ b/panda/src/downloader/httpDate.cxx @@ -279,7 +279,7 @@ input(std::istream &in) { string date; ch = in.get(); - while (!in.fail() && !in.eof() && ch != '"') { + while (!in.fail() && ch != EOF && ch != '"') { date += ch; ch = in.get(); } diff --git a/panda/src/downloader/socketStream.cxx b/panda/src/downloader/socketStream.cxx index eec65d1857..cd18e7f972 100644 --- a/panda/src/downloader/socketStream.cxx +++ b/panda/src/downloader/socketStream.cxx @@ -56,7 +56,7 @@ do_receive_datagram(Datagram &dg) { // Read the first two bytes: the datagram length. while ((int)_data_so_far.size() < _tcp_header_size) { int ch = _istream->get(); - if (_istream->eof() || _istream->fail()) { + if (ch == EOF || _istream->fail()) { _istream->clear(); return false; } diff --git a/panda/src/express/hashVal.cxx b/panda/src/express/hashVal.cxx index 5d74f1dac4..479f91f752 100644 --- a/panda/src/express/hashVal.cxx +++ b/panda/src/express/hashVal.cxx @@ -50,7 +50,7 @@ input_hex(istream &in) { size_t i = 0; int ch = in.get(); - while (!in.eof() && !in.fail() && isxdigit(ch)) { + while (ch != EOF && !in.fail() && isxdigit(ch)) { if (i < 32) { buffer[i] = (char)ch; } @@ -63,7 +63,7 @@ input_hex(istream &in) { return; } - if (!in.eof()) { + if (ch != EOF) { in.putback((char)ch); } else { in.clear(); diff --git a/panda/src/express/make_ca_bundle.cxx b/panda/src/express/make_ca_bundle.cxx index 0773bb88ec..2a9712b3ce 100644 --- a/panda/src/express/make_ca_bundle.cxx +++ b/panda/src/express/make_ca_bundle.cxx @@ -108,7 +108,7 @@ main(int argc, char *argv[]) { int col = 0; unsigned int ch; ch = in.get(); - while (!in.fail() && !in.eof()) { + while (!in.fail() && ch != EOF) { if (col == 0) { out << "\n "; } else if (col == col_width) { diff --git a/panda/src/express/multifile.cxx b/panda/src/express/multifile.cxx index cdb1c56ec8..4467132b79 100644 --- a/panda/src/express/multifile.cxx +++ b/panda/src/express/multifile.cxx @@ -1785,8 +1785,7 @@ compare_subfile(int index, const Filename &filename) { in2.seekg(0); int byte1 = in1->get(); int byte2 = in2.get(); - while (!in1->fail() && !in1->eof() && - !in2.fail() && !in2.eof()) { + while (!in1->fail() && !in2.fail()) { if (byte1 != byte2) { close_read_subfile(in1); return false; @@ -2497,7 +2496,7 @@ read_index(istream &read, streampos fpos, Multifile *multifile) { StreamReader reader(read); streampos next_index = multifile->word_to_streampos(reader.get_uint32()); - if (read.eof() || read.fail()) { + if (read.fail()) { _flags |= SF_index_invalid; return 0; } @@ -2529,7 +2528,7 @@ read_index(istream &read, streampos fpos, Multifile *multifile) { } size_t name_length = reader.get_uint16(); - if (read.eof() || read.fail()) { + if (read.fail()) { _flags |= SF_index_invalid; return 0; } @@ -2543,7 +2542,7 @@ read_index(istream &read, streampos fpos, Multifile *multifile) { _name = string(name_buffer, name_length); PANDA_FREE_ARRAY(name_buffer); - if (read.eof() || read.fail()) { + if (read.fail()) { _flags |= SF_index_invalid; return 0; } diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 1ba5b891e3..d28e2d208b 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -4158,7 +4158,7 @@ do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only) cdata->_num_mipmap_levels_read = cdata->_ram_images.size(); } - if (in.fail() || in.eof()) { + if (in.fail()) { gobj_cat.error() << filename << ": truncated DDS file.\n"; return false; @@ -4924,7 +4924,7 @@ do_read_ktx(CData *cdata, istream &in, const string &filename, bool header_only) } } - if (in.fail() || in.eof()) { + if (in.fail()) { gobj_cat.error() << filename << ": truncated KTX file.\n"; return false; diff --git a/panda/src/pnmimage/pnmimage_base.cxx b/panda/src/pnmimage/pnmimage_base.cxx index 0fb9bedfc6..d5ef09e415 100644 --- a/panda/src/pnmimage/pnmimage_base.cxx +++ b/panda/src/pnmimage/pnmimage_base.cxx @@ -120,7 +120,7 @@ int pm_readbigshort(istream *in, short *sP) { StreamReader reader(in, false); *sP = reader.get_be_int16(); - return (!in->eof() && !in->fail()) ? 0 : -1; + return (!in->fail()) ? 0 : -1; } int @@ -134,7 +134,7 @@ int pm_readbiglong(istream *in, long *lP) { StreamReader reader(in, false); *lP = reader.get_be_int32(); - return (!in->eof() && !in->fail()) ? 0 : -1; + return (!in->fail()) ? 0 : -1; } int @@ -148,7 +148,7 @@ int pm_readlittleshort(istream *in, short *sP) { StreamReader reader(in, false); *sP = reader.get_int16(); - return (!in->eof() && !in->fail()) ? 0 : -1; + return (!in->fail()) ? 0 : -1; } int @@ -162,7 +162,7 @@ int pm_readlittlelong(istream *in, long *lP) { StreamReader reader(in, false); *lP = reader.get_int32(); - return (!in->eof() && !in->fail()) ? 0 : -1; + return (!in->fail()) ? 0 : -1; } int diff --git a/pandatool/src/miscprogs/binToC.cxx b/pandatool/src/miscprogs/binToC.cxx index f963c08986..6eff47c9d1 100644 --- a/pandatool/src/miscprogs/binToC.cxx +++ b/pandatool/src/miscprogs/binToC.cxx @@ -101,7 +101,7 @@ run() { int col = 0; unsigned int ch; ch = in.get(); - while (!in.fail() && !in.eof()) { + while (!in.fail() && ch != EOF) { if (col == 0) { out << "\n "; } else if (col == col_width) { From e4daa0bf16c5fd439ed4b7396f734f85a4368645 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 10 Jan 2019 21:55:07 +0100 Subject: [PATCH 026/144] tests: test various things that could suffer from libc++ eof() bug --- tests/express/test_hashval.py | 9 ++ tests/express/test_multifile.py | 12 +++ tests/prc/test_stream_reader.py | 157 ++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 tests/express/test_hashval.py create mode 100644 tests/express/test_multifile.py create mode 100644 tests/prc/test_stream_reader.py diff --git a/tests/express/test_hashval.py b/tests/express/test_hashval.py new file mode 100644 index 0000000000..b2334e24d9 --- /dev/null +++ b/tests/express/test_hashval.py @@ -0,0 +1,9 @@ +from panda3d import core +import random + + +def test_hashval_hex(): + hex = '%032x' % random.getrandbits(32 * 4) + val = core.HashVal() + val.input_hex(core.StringStream(hex.encode('ascii'))) + assert str(val) == hex.lower() diff --git a/tests/express/test_multifile.py b/tests/express/test_multifile.py new file mode 100644 index 0000000000..8618688eb2 --- /dev/null +++ b/tests/express/test_multifile.py @@ -0,0 +1,12 @@ +from panda3d.core import Multifile, StringStream, IStreamWrapper + + +def test_multifile_read_empty(): + stream = StringStream(b'pmf\x00\n\r\x01\x00\x01\x00\x01\x00\x00\x00\xdb\x9d7\\\x00\x00\x00\x00') + wrapper = IStreamWrapper(stream) + + m = Multifile() + assert m.open_read(wrapper) + assert m.is_read_valid() + assert m.get_num_subfiles() == 0 + m.close() diff --git a/tests/prc/test_stream_reader.py b/tests/prc/test_stream_reader.py new file mode 100644 index 0000000000..de40e40b80 --- /dev/null +++ b/tests/prc/test_stream_reader.py @@ -0,0 +1,157 @@ +from panda3d.core import StreamReader, StringStream +import pytest + + +def test_streamreader_string(): + # Empty string + stream = StringStream(b'\x00\x00') + reader = StreamReader(stream, False) + assert reader.get_string() == '' + + # String size but no string contents + stream = StringStream(b'\x01\x00') + reader = StreamReader(stream, False) + assert reader.get_string() == '' + + # String of length 1 + stream = StringStream(b'\x01\x00A') + reader = StreamReader(stream, False) + assert reader.get_string() == 'A' + + # String with excess data + stream = StringStream(b'\x01\x00AB') + reader = StreamReader(stream, False) + assert reader.get_string() == 'A' + + # EOF before end of string + stream = StringStream(b'\x03\x00AB') + reader = StreamReader(stream, False) + assert reader.get_string() == 'AB' + + # Preserves null bytes + stream = StringStream(b'\x02\x00\x00\x00') + reader = StreamReader(stream, False) + assert reader.get_string() == '\x00\x00' + + +def test_streamreader_string32(): + # Empty string + stream = StringStream(b'\x00\x00\x00\x00') + reader = StreamReader(stream, False) + assert reader.get_string32() == '' + + # String size but no string contents + stream = StringStream(b'\x01\x00\x00\x00') + reader = StreamReader(stream, False) + assert reader.get_string32() == '' + + # String of length 1 + stream = StringStream(b'\x01\x00\x00\x00A') + reader = StreamReader(stream, False) + assert reader.get_string32() == 'A' + + # String with excess data + stream = StringStream(b'\x01\x00\x00\x00AB') + reader = StreamReader(stream, False) + assert reader.get_string32() == 'A' + + # EOF before end of string + stream = StringStream(b'\x04\x00\x00\x00AB') + reader = StreamReader(stream, False) + assert reader.get_string32() == 'AB' + + # Preserves null bytes + stream = StringStream(b'\x02\x00\x00\x00\x00\x00') + reader = StreamReader(stream, False) + assert reader.get_string32() == '\x00\x00' + + +def test_streamreader_z_string(): + # Empty stream + stream = StringStream(b'') + reader = StreamReader(stream, False) + assert reader.get_z_string() == '' + + # Empty string + stream = StringStream(b'\x00') + reader = StreamReader(stream, False) + assert reader.get_z_string() == '' + + # String of length 1 + stream = StringStream(b'A\x00') + reader = StreamReader(stream, False) + assert reader.get_z_string() == 'A' + + # String with excess data + stream = StringStream(b'ABC\x00AB') + reader = StreamReader(stream, False) + assert reader.get_z_string() == 'ABC' + + # EOF before end of string + stream = StringStream(b'ABC') + reader = StreamReader(stream, False) + assert reader.get_z_string() == 'ABC' + + +def test_streamreader_fixed_string(): + # Zero-length string + stream = StringStream(b'ABC') + reader = StreamReader(stream, False) + assert reader.get_fixed_string(0) == '' + + # Empty stream + stream = StringStream(b'') + reader = StreamReader(stream, False) + assert reader.get_fixed_string(1) == '' + + # Empty string + stream = StringStream(b'\x00') + reader = StreamReader(stream, False) + assert reader.get_fixed_string(1) == '' + + # String of length 1 + stream = StringStream(b'A') + reader = StreamReader(stream, False) + assert reader.get_fixed_string(1) == 'A' + + # String of length 1, excess data + stream = StringStream(b'ABC\x00') + reader = StreamReader(stream, False) + assert reader.get_fixed_string(1) == 'A' + + # EOF before end of string + stream = StringStream(b'AB') + reader = StreamReader(stream, False) + assert reader.get_fixed_string(4) == 'AB' + + +def test_streamreader_readline(): + # Empty stream + stream = StringStream(b'') + reader = StreamReader(stream, False) + assert reader.readline() == b'' + assert reader.readline() == b'' + + # Single line without newline + stream = StringStream(b'A') + reader = StreamReader(stream, False) + assert reader.readline() == b'A' + assert reader.readline() == b'' + + # Single newline + stream = StringStream(b'\n') + reader = StreamReader(stream, False) + assert reader.readline() == b'\n' + assert reader.readline() == b'' + + # Line with text followed by empty line + stream = StringStream(b'A\n\n') + reader = StreamReader(stream, False) + assert reader.readline() == b'A\n' + assert reader.readline() == b'\n' + assert reader.readline() == b'' + + # Preserve null byte + stream = StringStream(b'\x00\x00') + reader = StreamReader(stream, False) + assert reader.readline() == b'\x00\x00' From e1e5b907c105f227eeb2fedee43c949901f9ad4f Mon Sep 17 00:00:00 2001 From: tc Date: Fri, 11 Jan 2019 00:07:17 +0100 Subject: [PATCH 027/144] add aiProcess_GenNormals + aiProcess_GenSmoothNormals --- pandatool/src/assimp/assimpLoader.cxx | 10 ++++++++++ pandatool/src/assimp/config_assimp.cxx | 17 +++++++++++++++++ pandatool/src/assimp/config_assimp.h | 3 +++ 3 files changed, 30 insertions(+) diff --git a/pandatool/src/assimp/assimpLoader.cxx b/pandatool/src/assimp/assimpLoader.cxx index 8533fbaa64..ec0dc40b7d 100644 --- a/pandatool/src/assimp/assimpLoader.cxx +++ b/pandatool/src/assimp/assimpLoader.cxx @@ -129,6 +129,16 @@ read(const Filename &filename) { if (assimp_flip_winding_order) { flags |= aiProcess_FlipWindingOrder; } + if (assimp_gen_normals) { + if (assimp_smooth_normal_angle == 0.0) { + flags |= aiProcess_GenNormals; + } + else { + flags |= aiProcess_GenSmoothNormals; + _importer.SetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, + assimp_smooth_normal_angle); + } + } _scene = _importer.ReadFile(_filename.c_str(), flags); if (_scene == nullptr) { diff --git a/pandatool/src/assimp/config_assimp.cxx b/pandatool/src/assimp/config_assimp.cxx index 2dbf29fa16..2b84d2c63b 100644 --- a/pandatool/src/assimp/config_assimp.cxx +++ b/pandatool/src/assimp/config_assimp.cxx @@ -69,6 +69,23 @@ ConfigVariableBool assimp_flip_winding_order "the Assimp loader. Note that you may need to clear the model-cache " "after changing this.")); +ConfigVariableBool assimp_gen_normals +("assimp-gen-normals", false, + PRC_DESC("Set this true to generate normals (if absent from file) on import. " + "See assimp-smooth-normal-angle for more information. " + "Note that you may need to clear the model-cache after " + "changing this.")); + +ConfigVariableDouble assimp_smooth_normal_angle +("assimp-smooth-normal-angle", 0.0, + PRC_DESC("Set this to anything other than 0.0 in degrees (so 180.0 is PI) to " + "specify the maximum angle that may be between two face normals at " + "the same vertex position that are smoothed together. Sometimes " + "referred to as 'crease angle'. Only has effect if " + "assimp-gen-normals is set to true and the file does not contain " + "normals. Note that you may need to clear the model-cache after " + "changing this.")); + /** * Initializes the library. This must be called at least once before any of * the functions or classes in this library can be used. Normally it will be diff --git a/pandatool/src/assimp/config_assimp.h b/pandatool/src/assimp/config_assimp.h index 16efc8a754..898497eeb2 100644 --- a/pandatool/src/assimp/config_assimp.h +++ b/pandatool/src/assimp/config_assimp.h @@ -16,6 +16,7 @@ #include "pandatoolbase.h" #include "configVariableBool.h" +#include "configVariableDouble.h" #include "dconfig.h" ConfigureDecl(config_assimp, EXPCL_ASSIMP, EXPTP_ASSIMP); @@ -29,6 +30,8 @@ extern ConfigVariableBool assimp_fix_infacing_normals; extern ConfigVariableBool assimp_optimize_meshes; extern ConfigVariableBool assimp_optimize_graph; extern ConfigVariableBool assimp_flip_winding_order; +extern ConfigVariableBool assimp_gen_normals; +extern ConfigVariableDouble assimp_smooth_normal_angle; extern EXPCL_ASSIMP void init_libassimp(); From e8f0e030432bf7fda850a90327ae108f4b95081a Mon Sep 17 00:00:00 2001 From: John Cote Date: Fri, 11 Jan 2019 03:38:56 -0500 Subject: [PATCH 028/144] makepackage: Don't include deploy-stub when building .rpm Attempting to include deploy-stub in the .rpm would cause rpmbuild to fail, as deploy-stub isn't present. Closes #527 --- makepanda/makepackage.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py index ed20117d10..31a45a2bb9 100755 --- a/makepanda/makepackage.py +++ b/makepanda/makepackage.py @@ -438,7 +438,8 @@ def MakeInstallerLinux(version, debversion=None, rpmrelease=1, runtime=False, # Add the binaries in /usr/bin explicitly to the spec file for base in os.listdir(outputdir + "/bin"): - txt += "/usr/bin/%s\n" % (base) + if not base.startswith("deploy-stub"): + txt += "/usr/bin/%s\n" % (base) # Write out the spec file. txt = txt.replace("VERSION", version) From 8c40244ea4658b45cb95cebdfcbeb086af9724e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Derzsi=20D=C3=A1niel?= Date: Fri, 11 Jan 2019 13:46:28 -0800 Subject: [PATCH 029/144] readme: Add fakeroot into Linux build command Fixes #530 [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 596c134f46..99c7c39a5d 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ If you are on Ubuntu, this command should cover the most frequently used third-party packages: ```bash -sudo apt-get install build-essential pkg-config python-dev libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit libgtk2.0-dev libassimp-dev libopenexr-dev +sudo apt-get install build-essential pkg-config fakeroot python-dev libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit libgtk2.0-dev libassimp-dev libopenexr-dev ``` Once Panda3D has built, you can either install the .deb or .rpm package that From 1895abff6637881f52138f6133c1cdac07ba6a0c Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 11 Jan 2019 23:32:37 +0100 Subject: [PATCH 030/144] Remove cvscopy and related tools --- doc/man/fltcopy.1 | 44 -- makepanda/makepanda.py | 38 +- makepanda/makepanda.vcproj | 15 - pandatool/src/cvscopy/cvsCopy.cxx | 501 ---------------- pandatool/src/cvscopy/cvsCopy.h | 89 --- pandatool/src/cvscopy/cvsSourceDirectory.cxx | 237 -------- pandatool/src/cvscopy/cvsSourceDirectory.h | 65 --- pandatool/src/cvscopy/cvsSourceTree.cxx | 546 ------------------ pandatool/src/cvscopy/cvsSourceTree.h | 109 ---- .../src/cvscopy/p3cvscopy_composite1.cxx | 5 - pandatool/src/cvscopy/testCopy.cxx | 65 --- pandatool/src/cvscopy/testCopy.h | 37 -- pandatool/src/fltprogs/fltCopy.cxx | 237 -------- pandatool/src/fltprogs/fltCopy.h | 70 --- pandatool/src/mayaprogs/mayaCopy.cxx | 457 --------------- pandatool/src/mayaprogs/mayaCopy.h | 86 --- 16 files changed, 2 insertions(+), 2599 deletions(-) delete mode 100644 doc/man/fltcopy.1 delete mode 100644 pandatool/src/cvscopy/cvsCopy.cxx delete mode 100644 pandatool/src/cvscopy/cvsCopy.h delete mode 100644 pandatool/src/cvscopy/cvsSourceDirectory.cxx delete mode 100644 pandatool/src/cvscopy/cvsSourceDirectory.h delete mode 100644 pandatool/src/cvscopy/cvsSourceTree.cxx delete mode 100644 pandatool/src/cvscopy/cvsSourceTree.h delete mode 100644 pandatool/src/cvscopy/p3cvscopy_composite1.cxx delete mode 100644 pandatool/src/cvscopy/testCopy.cxx delete mode 100644 pandatool/src/cvscopy/testCopy.h delete mode 100644 pandatool/src/fltprogs/fltCopy.cxx delete mode 100644 pandatool/src/fltprogs/fltCopy.h delete mode 100644 pandatool/src/mayaprogs/mayaCopy.cxx delete mode 100644 pandatool/src/mayaprogs/mayaCopy.h diff --git a/doc/man/fltcopy.1 b/doc/man/fltcopy.1 deleted file mode 100644 index 59632efe50..0000000000 --- a/doc/man/fltcopy.1 +++ /dev/null @@ -1,44 +0,0 @@ -.\" Automatically generated by fltcopy -write-bam -.TH FLTCOPY 1 "27 December 2014" "1.9.0" Panda3D -.SH NAME -fltcopy \- copy MultiGen .flt files into a CVS source hierarchy -.SH SYNOPSIS -\fBfltcopy\fR [opts] file.flt [file.flt ... ] -.SH DESCRIPTION -fltcopy copies one or more MultiGen .flt files into a CVS source hierarchy. Rather than copying the named files immediately into the current directory, it first scans the entire source hierarchy, identifying all the already\-existing files. If the named file to copy matches the name of an already\-existing file in the current directory or elsewhere in the hierarchy, that file is overwritten. Other .flt files, as well as texture files, that are externally referenced by the named .flt file(s) are similarly copied. -.SH OPTIONS -.TP -.BI "\-pr " "path_replace" -Sometimes references to other files (textures, external references) are stored with a full path that is appropriate for some other system, but does not exist here. This option may be used to specify how those invalid paths map to correct paths. Generally, this is of the form 'orig_prefix=replacement_prefix', which indicates a particular initial sequence of characters that should be replaced with a new sequence; e.g. '/c/home/models=/beta/fish'. If the replacement prefix does not begin with a slash, the file will then be searched for along the search path specified by -pp. You may use standard filename matching characters ('*', '?', etc.) in the original prefix, and '**' as a component by itself stands for any number of components. - -This option may be repeated as necessary; each file will be tried against each specified method, in the order in which they appear in the command line, until the file is found. If the file is not found, the last matching prefix is used anyway. -.TP -.BI "\-pp " "dirname" -Adds the indicated directory name to the list of directories to search for filenames referenced by the source file. This is used only for relative paths, or for paths that are made relative by a -pr replacement string that doesn't begin with a leading slash. The model-path is always implicitly searched anyway. -.TP -.B \-f -Force the copy to happen without any input from the user. If a file with the same name exists anywhere in the source hierarchy, it will be overwritten without prompting; if a file does not yet exist, it will be created in the directory named by -d or by -m, as appropriate. -.TP -.B \-i -The opposite of -f, this will prompt the user before each action. The default is only to prompt the user when an action is ambiguous or unusual. -.TP -.BI "\-d " "dirname" -Copy model files that are not already present somewhere in the tree to the indicated directory. The default is the current directory. -.TP -.BI "\-m " "dirname" -Copy texture map files to the indicated directory. The default is src/maps from the root directory. -.TP -.BI "\-root " "dirname" -Specify the root of the CVS source hierarchy. The default is to use the ppremake convention of locating the directory above the -d directory that contains a file called Package.pp. -.TP -.BI "\-key " "filename" -Specify the name of the file that must exist in each directory for it to be considered part of the CVS source hierarchy. The default is the ppremake convention, "Sources.pp". Other likely candidates are "CVS" to search a CVS hierarchy, or "." to include all subdirectories indiscriminately. -.TP -.B \-nc -Do not attempt to add newly-created files to CVS. The default is to add them. -.TP -.BI "\-cvs " "cvs_binary" -Specify how to run the cvs program for adding newly-created files. The default is simply "cvs". -.TP -.B \-h -Display this help page. diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index f029b14868..34829667c2 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -3361,7 +3361,6 @@ if (PkgSkip("PANDATOOL")==0): CopyAllHeaders('pandatool/src/progbase') CopyAllHeaders('pandatool/src/eggbase') CopyAllHeaders('pandatool/src/bam') - CopyAllHeaders('pandatool/src/cvscopy') CopyAllHeaders('pandatool/src/daeegg') CopyAllHeaders('pandatool/src/daeprogs') CopyAllHeaders('pandatool/src/dxf') @@ -5734,15 +5733,6 @@ if not PkgSkip("PANDATOOL"): TargetAdd('egg2bam.exe', input=COMMON_EGG2X_LIBS) TargetAdd('egg2bam.exe', opts=['ADVAPI', 'FFTW']) -# -# DIRECTORY: pandatool/src/cvscopy/ -# - -if not PkgSkip("PANDATOOL"): - OPTS=['DIR:pandatool/src/cvscopy'] - TargetAdd('p3cvscopy_composite1.obj', opts=OPTS, input='p3cvscopy_composite1.cxx') - TargetAdd('libp3cvscopy.lib', input='p3cvscopy_composite1.obj') - # # DIRECTORY: pandatool/src/daeegg/ # @@ -6007,7 +5997,7 @@ if not PkgSkip("PANDATOOL") and not PkgSkip("EGG"): # if not PkgSkip("PANDATOOL"): - OPTS=['DIR:pandatool/src/fltprogs', 'DIR:pandatool/src/flt', 'DIR:pandatool/src/cvscopy'] + OPTS=['DIR:pandatool/src/fltprogs', 'DIR:pandatool/src/flt'] TargetAdd('flt-info_fltInfo.obj', opts=OPTS, input='fltInfo.cxx') TargetAdd('flt-info.exe', input='flt-info_fltInfo.obj') TargetAdd('flt-info.exe', input='libp3flt.lib') @@ -6024,15 +6014,6 @@ if not PkgSkip("PANDATOOL"): TargetAdd('flt-trans.exe', input=COMMON_PANDA_LIBS) TargetAdd('flt-trans.exe', opts=['ADVAPI']) - TargetAdd('fltcopy_fltCopy.obj', opts=OPTS, input='fltCopy.cxx') - TargetAdd('fltcopy.exe', input='fltcopy_fltCopy.obj') - TargetAdd('fltcopy.exe', input='libp3cvscopy.lib') - TargetAdd('fltcopy.exe', input='libp3flt.lib') - TargetAdd('fltcopy.exe', input='libp3progbase.lib') - TargetAdd('fltcopy.exe', input='libp3pandatoolbase.lib') - TargetAdd('fltcopy.exe', input=COMMON_PANDA_LIBS) - TargetAdd('fltcopy.exe', opts=['ADVAPI']) - if not PkgSkip("EGG"): TargetAdd('egg2flt_eggToFlt.obj', opts=OPTS, input='eggToFlt.cxx') TargetAdd('egg2flt.exe', input='egg2flt_eggToFlt.obj') @@ -6421,7 +6402,7 @@ for VER in MAYAVERSIONS: # No x86_64 support. continue - OPTS=['DIR:pandatool/src/mayaprogs', 'DIR:pandatool/src/maya', 'DIR:pandatool/src/mayaegg', 'DIR:pandatool/src/cvscopy', 'BUILDING:MISC', VER] + OPTS=['DIR:pandatool/src/mayaprogs', 'DIR:pandatool/src/maya', 'DIR:pandatool/src/mayaegg', 'BUILDING:MISC', VER] TargetAdd('mayaeggimport'+VNUM+'_mayaeggimport.obj', opts=OPTS, input='mayaEggImport.cxx') TargetAdd('mayaeggimport'+VNUM+'.mll', input='mayaegg'+VNUM+'_loader.obj') TargetAdd('mayaeggimport'+VNUM+'.mll', input='mayaeggimport'+VNUM+'_mayaeggimport.obj') @@ -6486,16 +6467,6 @@ for VER in MAYAVERSIONS: TargetAdd('egg2maya'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS) TargetAdd('egg2maya'+VNUM+'_bin.exe', opts=['ADVAPI', VER]) - TargetAdd('mayacopy'+VNUM+'_mayaCopy.obj', opts=OPTS, input='mayaCopy.cxx') - TargetAdd('mayacopy'+VNUM+'_bin.exe', input='mayacopy'+VNUM+'_mayaCopy.obj') - TargetAdd('mayacopy'+VNUM+'_bin.exe', input='libp3cvscopy.lib') - TargetAdd('mayacopy'+VNUM+'_bin.exe', input='libmaya'+VNUM+'.lib') - if GetTarget() == 'windows': - TargetAdd('mayacopy'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS) - else: - TargetAdd('mayacopy'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS) - TargetAdd('mayacopy'+VNUM+'_bin.exe', opts=['ADVAPI', VER]) - TargetAdd('mayasavepview'+VNUM+'_mayaSavePview.obj', opts=OPTS, input='mayaSavePview.cxx') TargetAdd('libmayasavepview'+VNUM+'.mll', input='mayasavepview'+VNUM+'_mayaSavePview.obj') TargetAdd('libmayasavepview'+VNUM+'.mll', opts=['ADVAPI', VER]) @@ -6512,11 +6483,6 @@ for VER in MAYAVERSIONS: TargetAdd('egg2maya'+VNUM+'.exe', input=COMMON_DTOOL_LIBS) TargetAdd('egg2maya'+VNUM+'.exe', opts=['ADVAPI']) - TargetAdd('mayacopy'+VNUM+'.exe', input='mayapath'+VNUM+'.obj') - TargetAdd('mayacopy'+VNUM+'.exe', input='libpandaexpress.dll') - TargetAdd('mayacopy'+VNUM+'.exe', input=COMMON_DTOOL_LIBS) - TargetAdd('mayacopy'+VNUM+'.exe', opts=['ADVAPI']) - # # DIRECTORY: contrib/src/ai/ # diff --git a/makepanda/makepanda.vcproj b/makepanda/makepanda.vcproj index 9ac171d7a2..2fee06a963 100644 --- a/makepanda/makepanda.vcproj +++ b/makepanda/makepanda.vcproj @@ -4572,17 +4572,6 @@ - - - - - - - - - - - @@ -4750,11 +4739,9 @@ - - @@ -4920,11 +4907,9 @@ - - diff --git a/pandatool/src/cvscopy/cvsCopy.cxx b/pandatool/src/cvscopy/cvsCopy.cxx deleted file mode 100644 index 17dd07eb66..0000000000 --- a/pandatool/src/cvscopy/cvsCopy.cxx +++ /dev/null @@ -1,501 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cvsCopy.cxx - * @author drose - * @date 2000-10-31 - */ - -#include "cvsCopy.h" -#include "cvsSourceDirectory.h" - -#include "pnotify.h" -#include - -using std::string; - -/** - * - */ -CVSCopy:: -CVSCopy() { - _model_dirname = "."; - _key_filename = "Sources.pp"; - _cvs_binary = "cvs"; - _user_aborted = false; - _model_dir = nullptr; - _map_dir = nullptr; - - clear_runlines(); - add_runline("[opts] file [file ... ]"); - - add_option - ("f", "", 80, - "Force the copy to happen without any input from the user. If a file " - "with the same name exists anywhere in the source hierarchy, it will " - "be overwritten without prompting; if a file does not yet exist, it " - "will be created in the directory named by -d or by -m, as appropriate.", - &CVSCopy::dispatch_none, &_force); - - add_option - ("i", "", 80, - "The opposite of -f, this will prompt the user before each action. " - "The default is only to prompt the user when an action is ambiguous " - "or unusual.", - &CVSCopy::dispatch_none, &_interactive); - - add_option - ("d", "dirname", 80, - "Copy model files that are not already present somewhere in the tree " - "to the indicated directory. The default is the current directory.", - &CVSCopy::dispatch_filename, &_got_model_dirname, &_model_dirname); - - add_option - ("m", "dirname", 80, - "Copy texture map files to the indicated directory. The default " - "is src/maps from the root directory.", - &CVSCopy::dispatch_filename, &_got_map_dirname, &_map_dirname); - - add_option - ("root", "dirname", 80, - "Specify the root of the CVS source hierarchy. The default is to " - "use the ppremake convention of locating the directory above the -d " - "directory that contains a file called Package.pp.", - &CVSCopy::dispatch_filename, &_got_root_dirname, &_root_dirname); - - add_option - ("key", "filename", 80, - "Specify the name of the file that must exist in each directory for " - "it to be considered part of the CVS source hierarchy. The default " - "is the ppremake convention, \"Sources.pp\". Other likely candidates " - "are \"CVS\" to search a CVS hierarchy, or \".\" to include " - "all subdirectories indiscriminately.", - &CVSCopy::dispatch_filename, nullptr, &_key_filename); - - add_option - ("nc", "", 80, - "Do not attempt to add newly-created files to CVS. The default " - "is to add them.", - &CVSCopy::dispatch_none, &_no_cvs); - - add_option - ("cvs", "cvs_binary", 80, - "Specify how to run the cvs program for adding newly-created files. " - "The default is simply \"cvs\".", - &CVSCopy::dispatch_string, nullptr, &_cvs_binary); -} - -/** - * Checks for the given filename somewhere in the directory hierarchy, and - * chooses a place to import it. Copies the file by calling copy_file(). - * - * Extra_data may be NULL or a pointer to some user-defined structure; CVSCopy - * simply passes it unchanged to copy_file(). It presumably gives the class a - * hint as to how the file should be copied. Suggested_dir is the suggested - * directory in which to copy the file, if it does not already exist - * elsewhere. - * - * On success, returns the FilePath it was actually copied to. On failure, - * returns an invalid FilePath. - */ -CVSSourceTree::FilePath CVSCopy:: -import(const Filename &source, void *extra_data, - CVSSourceDirectory *suggested_dir) { - CopiedFiles::const_iterator ci; - ci = _copied_files.find(source); - if (ci != _copied_files.end()) { - // We have already copied this file. - return (*ci).second; - } - - if (!source.exists()) { - nout << "Source filename " << source << " does not exist!\n"; - return CVSSourceTree::FilePath(); - } - - string basename = filter_filename(source.get_basename()); - - CVSSourceTree::FilePath path = - _tree.choose_directory(basename, suggested_dir, _force, _interactive); - nassertr(path.is_valid(), path); - - _copied_files[source] = path; - Filename dest = path.get_fullpath(); - - bool new_file = !dest.exists(); - if (!new_file && verify_file(source, dest, path._dir, extra_data)) { - // The file is unchanged. - nout << path.get_path() << " is unchanged.\n"; - - } else { - // The file has changed. - nout << "Copying " << basename << " to " << path.get_path() << "\n"; - - if (!copy_file(source, dest, path._dir, extra_data, new_file)) { - if (!continue_after_error()) { - return CVSSourceTree::FilePath(); - } - } else { - if (new_file) { - cvs_add(dest); - } - } - } - - return path; -} - -/** - * Prompts the user (unless -f was specified) if he wants to continue the copy - * operation after some error has occurred. Returns true to continue, false - * otherwise. - */ -bool CVSCopy:: -continue_after_error() { - if (_force) { - return true; - } - if (_user_aborted) { - return false; - } - - while (true) { - string result = prompt("Error occurred during copy! Continue (y/n)? "); - nassertr(!result.empty(), false); - if (result.size() == 1) { - if (tolower(result[0]) == 'y') { - return true; - } else if (tolower(result[0]) == 'n') { - _user_aborted = true; - return false; - } - } - - nout << "*** Invalid response: " << result << "\n\n"; - } -} - - -/** - * Does something with the additional arguments on the command line (after all - * the -options have been parsed). Returns true if the arguments are good, - * false otherwise. - */ -bool CVSCopy:: -handle_args(Args &args) { - if (args.empty()) { - nout << "You must specify the file(s) to copy from on the command line.\n"; - return false; - } - - for (Args::const_iterator ai = args.begin(); - ai != args.end(); - ++ai) { - _source_files.push_back(Filename::from_os_specific(*ai)); - } - return true; -} - -/** - * This is called after the command line has been completely processed, and it - * gives the program a chance to do some last-minute processing and validation - * of the options and arguments. It should return true if everything is fine, - * false if there is an error. - */ -bool CVSCopy:: -post_command_line() { - if (!scan_hierarchy()) { - return false; - } - - _model_dir = _tree.find_directory(_model_dirname); - if (_model_dir == nullptr) { - if (_got_model_dirname) { - nout << "Warning: model directory " << _model_dirname - << " is not within the source hierarchy.\n"; - } - } - - if (_got_map_dirname) { - _map_dir = _tree.find_directory(_map_dirname); - - if (_map_dir == nullptr) { - nout << "Warning: map directory " << _map_dirname - << " is not within the source hierarchy.\n"; - } - - } else { - _map_dir = _tree.find_relpath("src/maps"); - - if (_map_dir == nullptr) { - nout << "Warning: no directory " << _tree.get_root_dirname() - << "/src/maps.\n"; - _map_dir = _model_dir; - } - } - - return true; -} - - -/** - * Verifies that the file is identical and does not need to be recopied. - * Returns true if the files are identical, false if they differ. - */ -bool CVSCopy:: -verify_file(const Filename &, const Filename &, - CVSSourceDirectory *, void *) { - return false; -} - -/** - * Verifies that the file is identical and does not need to be recopied. - * Returns true if the files are identical, false if they differ. - */ -bool CVSCopy:: -verify_binary_file(Filename source, Filename dest) { - if (source == dest) { - return true; - } - - source.set_binary(); - dest.set_binary(); - - std::ifstream s, d; - if (!source.open_read(s)) { - return false; - } - if (!dest.open_read(d)) { - return false; - } - - int cs, cd; - cs = s.get(); - cd = d.get(); - while (!s.eof() && !s.fail() && !d.eof() && !d.fail()) { - if (cs != cd) { - return false; - } - cs = s.get(); - cd = d.get(); - } - - if (s.fail() || d.fail()) { - // If we had some read error, call the files different. - return false; - } - - // If we haven't reached the end of one of the files yet, that file is - // longer than the other one, and the files are therefore different. - if (!s.eof() || !d.eof()) { - return false; - } - - // Otherwise, the files are the same. - return true; -} - -/** - * Copies a file without modifying it or scanning it in any way. This is - * particularly useful for copying textures. This is provided as a - * convenience function for derived programs because so many model file - * formats will also require copying textures or other black-box files. - */ -bool CVSCopy:: -copy_binary_file(Filename source, Filename dest) { - if (source == dest) { - return true; - } - - source.set_binary(); - dest.set_binary(); - - std::ifstream in; - std::ofstream out; - if (!source.open_read(in)) { - nout << "Cannot read " << source << "\n"; - return false; - } - - dest.unlink(); - if (!dest.open_write(out)) { - nout << "Cannot write " << dest << "\n"; - return false; - } - - int c; - c = in.get(); - while (!in.eof() && !in.fail() && !out.fail()) { - out.put(c); - c = in.get(); - } - - if (!in.eof() && in.fail()) { - nout << "Error reading " << source << "\n"; - return false; - } - if (out.fail()) { - nout << "Error writing " << dest << "\n"; - return false; - } - - return true; -} - -/** - * Invokes CVS to add the indicated filename to the repository, if the user so - * requested. Returns true if successful, false if there is an error. - */ -bool CVSCopy:: -cvs_add(const Filename &filename) { - if (_no_cvs) { - return true; - } - - if (!CVSSourceTree::temp_chdir(filename.get_dirname())) { - nout << "Invalid directory: " << filename.get_dirname() << "\n"; - return false; - } - - string command = _cvs_binary + " add -kb " + - protect_from_shell(filename.get_basename()); - nout << command << "\n"; - int result = system(command.c_str()); - - CVSSourceTree::restore_cwd(); - - if (result != 0) { - nout << "Failure invoking cvs.\n"; - return false; - } - return true; -} - -/** - * Inserts escape characters into the indicated source string to protect it - * from the shell, so that it may be given on the command line. Returns the - * modified string. - */ -string CVSCopy:: -protect_from_shell(const string &source) { - string result; - - for (string::const_iterator pi = source.begin(); pi != source.end(); ++pi) { - switch (*pi) { - case '\\': - case ' ': - case '\'': - case '"': - case '(': - case ')': - case '<': - case '>': - case '|': - case '&': - case '!': - case '$': - case '~': - case '*': - case '?': - case '[': - case ']': - case ';': - result += '\\'; - // fall through - - default: - result += *pi; - } - } - - return result; -} - -/** - * Given a source filename (including the basename only, without a dirname), - * return the appropriate corresponding filename within the source directory. - * This may be used by derived classes to, for instance, strip a version - * number from the filename. - */ -string CVSCopy:: -filter_filename(const string &source) { - return source; -} - -/** - * Starts the scan of the source hierarchy. This identifies all of the files - * in the source hierarchy we're to copy these into, so we can guess where - * referenced files should be placed. Returns true if everything is ok, false - * if there is an error. - */ -bool CVSCopy:: -scan_hierarchy() { - if (!_got_root_dirname) { - // If we didn't get a root directory name, find the directory above this - // one that contains the file "Package.pp". - if (!scan_for_root(_model_dirname)) { - return false; - } - } - - _tree.set_root(_root_dirname); - nout << "Root is " << _tree.get_root_fullpath() << "\n"; - - return _tree.scan(_key_filename); -} - -/** - * Searches for the root of the source directory by looking for the parent - * directory that contains "Package.pp". Returns true on success, false on - * failure. - */ -bool CVSCopy:: -scan_for_root(const string &dirname) { - Filename sources = dirname + "/Sources.pp"; - if (!sources.exists()) { - nout << "Couldn't find " << sources << " in source directory.\n"; - return false; - } - Filename package = dirname + "/Package.pp"; - if (package.exists()) { - // Here's the root! - _root_dirname = dirname; - return true; - } - - return scan_for_root(dirname + "/.."); -} - -/** - * Issues a prompt to the user and waits for a typed response. Returns the - * response (which will not be empty). - */ -string CVSCopy:: -prompt(const string &message) { - nout << std::flush; - while (true) { - std::cerr << message << std::flush; - std::string response; - std::getline(std::cin, response); - - // Remove leading and trailing whitespace. - size_t p = 0; - while (p < response.length() && isspace(response[p])) { - p++; - } - - size_t q = response.length(); - while (q > p && isspace(response[q - 1])) { - q--; - } - - if (q > p) { - return response.substr(p, q - p); - } - } -} diff --git a/pandatool/src/cvscopy/cvsCopy.h b/pandatool/src/cvscopy/cvsCopy.h deleted file mode 100644 index d820edf84d..0000000000 --- a/pandatool/src/cvscopy/cvsCopy.h +++ /dev/null @@ -1,89 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cvsCopy.h - * @author drose - * @date 2000-10-31 - */ - -#ifndef CVSCOPY_H -#define CVSCOPY_H - -#include "pandatoolbase.h" - -#include "cvsSourceTree.h" - -#include "programBase.h" -#include "filename.h" -#include "pvector.h" - -/** - * This is the base class for a family of programs that copy files, typically - * model files like .flt files and their associated textures, into a CVS- - * controlled source tree. - */ -class CVSCopy : public ProgramBase { -public: - CVSCopy(); - - CVSSourceTree::FilePath - import(const Filename &source, void *extra_data, - CVSSourceDirectory *suggested_dir); - - bool continue_after_error(); - -protected: - virtual bool handle_args(Args &args); - virtual bool post_command_line(); - - virtual bool verify_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *dest_dir, - void *extra_data); - virtual bool copy_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *dest_dir, - void *extra_data, bool new_file)=0; - - bool verify_binary_file(Filename source, Filename dest); - bool copy_binary_file(Filename source, Filename dest); - - bool cvs_add(const Filename &filename); - static std::string protect_from_shell(const std::string &source); - - virtual std::string filter_filename(const std::string &source); - -private: - bool scan_hierarchy(); - bool scan_for_root(const std::string &dirname); - std::string prompt(const std::string &message); - -protected: - bool _force; - bool _interactive; - bool _got_model_dirname; - Filename _model_dirname; - bool _got_map_dirname; - Filename _map_dirname; - bool _got_root_dirname; - Filename _root_dirname; - Filename _key_filename; - bool _no_cvs; - std::string _cvs_binary; - bool _user_aborted; - - typedef pvector SourceFiles; - SourceFiles _source_files; - - CVSSourceTree _tree; - CVSSourceDirectory *_model_dir; - CVSSourceDirectory *_map_dir; - - typedef pmap CopiedFiles; - CopiedFiles _copied_files; -}; - -#endif diff --git a/pandatool/src/cvscopy/cvsSourceDirectory.cxx b/pandatool/src/cvscopy/cvsSourceDirectory.cxx deleted file mode 100644 index 0eb741044d..0000000000 --- a/pandatool/src/cvscopy/cvsSourceDirectory.cxx +++ /dev/null @@ -1,237 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cvsSourceDirectory.cxx - * @author drose - * @date 2000-10-31 - */ - -#include "cvsSourceDirectory.h" -#include "cvsSourceTree.h" -#include "string_utils.h" - -#include "pnotify.h" - -using std::string; - -/** - * - */ -CVSSourceDirectory:: -CVSSourceDirectory(CVSSourceTree *tree, CVSSourceDirectory *parent, - const string &dirname) : - _tree(tree), - _parent(parent), - _dirname(dirname) -{ - if (_parent == nullptr) { - _depth = 0; - } else { - _depth = _parent->_depth + 1; - } -} - -/** - * - */ -CVSSourceDirectory:: -~CVSSourceDirectory() { - Children::iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - delete (*ci); - } -} - -/** - * Returns the local name of this particular directory. - */ -string CVSSourceDirectory:: -get_dirname() const { - return _dirname; -} - -/** - * Returns the full pathname to this particular directory. - */ -Filename CVSSourceDirectory:: -get_fullpath() const { - if (_parent == nullptr) { - return _tree->get_root_fullpath(); - } - return Filename(_parent->get_fullpath(), _dirname); -} - -/** - * Returns the relative pathname to this particular directory, as seen from - * the root of the tree. - */ -Filename CVSSourceDirectory:: -get_path() const { - if (_parent == nullptr) { - return _dirname; - } - return Filename(_parent->get_path(), _dirname); -} - -/** - * Returns the relative path to the other directory from this one. This does - * not include a trailing slash. - */ -Filename CVSSourceDirectory:: -get_rel_to(const CVSSourceDirectory *other) const { - const CVSSourceDirectory *a = this; - const CVSSourceDirectory *b = other; - - if (a == b) { - return "."; - } - - string prefix, postfix; - while (a->_depth > b->_depth) { - prefix += "../"; - a = a->_parent; - nassertr(a != nullptr, string()); - } - - while (b->_depth > a->_depth) { - postfix = b->_dirname + "/" + postfix; - b = b->_parent; - nassertr(b != nullptr, string()); - } - - while (a != b) { - prefix += "../"; - postfix = b->_dirname + "/" + postfix; - a = a->_parent; - b = b->_parent; - nassertr(a != nullptr, string()); - nassertr(b != nullptr, string()); - } - - string result = prefix + postfix; - nassertr(!result.empty(), string()); - return result.substr(0, result.length() - 1); -} - -/** - * Returns the number of subdirectories below this directory. - */ -int CVSSourceDirectory:: -get_num_children() const { - return _children.size(); -} - -/** - * Returns the nth subdirectory below this directory. - */ -CVSSourceDirectory *CVSSourceDirectory:: -get_child(int n) const { - nassertr(n >= 0 && n < (int)_children.size(), nullptr); - return _children[n]; -} - -/** - * Returns the source directory that corresponds to the given relative path - * from this directory, or NULL if there is no match. - */ -CVSSourceDirectory *CVSSourceDirectory:: -find_relpath(const string &relpath) { - if (relpath.empty()) { - return this; - } - - size_t slash = relpath.find('/'); - string first = relpath.substr(0, slash); - string rest; - if (slash != string::npos) { - rest = relpath.substr(slash + 1); - } - - if (first.empty() || first == ".") { - return find_relpath(rest); - - } else if (first == "..") { - if (_parent != nullptr) { - return _parent->find_relpath(rest); - } - // Tried to back out past the root directory. - return nullptr; - } - - // Check for a child with the name indicated by first. - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - if (cmp_nocase((*ci)->get_dirname(), first) == 0) { - return (*ci)->find_relpath(rest); - } - } - - // No match. - return nullptr; -} - -/** - * Returns the source directory that corresponds to the given local directory - * name, or NULL if there is no match. - */ -CVSSourceDirectory *CVSSourceDirectory:: -find_dirname(const string &dirname) { - if (cmp_nocase(dirname, _dirname) == 0) { - return this; - } - - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - CVSSourceDirectory *result = (*ci)->find_dirname(dirname); - if (result != nullptr) { - return result; - } - } - - return nullptr; -} - -/** - * Recursively scans the contents of the source directory. Fullpath is the - * full path name to the directory; key_filename is the name of a file that - * must exist in each subdirectory for it to be considered part of the - * hierarchy. Returns true on success, false on failure. - */ -bool CVSSourceDirectory:: -scan(const Filename &directory, const string &key_filename) { - vector_string contents; - if (!directory.scan_directory(contents)) { - nout << "Unable to scan directory " << directory << "\n"; - return false; - } - - vector_string::const_iterator fi; - for (fi = contents.begin(); fi != contents.end(); ++fi) { - const string &basename = (*fi); - - // Is this possibly a subdirectory name? - Filename next_path(directory, basename); - Filename key(next_path, key_filename); - - if (key.exists()) { - CVSSourceDirectory *subdir = - new CVSSourceDirectory(_tree, this, basename); - _children.push_back(subdir); - - if (!subdir->scan(next_path, key_filename)) { - return false; - } - - } else { - // It's not a subdirectory; call it a regular file. - _tree->add_file(basename, this); - } - } - - return true; -} diff --git a/pandatool/src/cvscopy/cvsSourceDirectory.h b/pandatool/src/cvscopy/cvsSourceDirectory.h deleted file mode 100644 index eb452612e4..0000000000 --- a/pandatool/src/cvscopy/cvsSourceDirectory.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cvsSourceDirectory.h - * @author drose - * @date 2000-10-31 - */ - -#ifndef CVSSOURCEDIRECTORY_H -#define CVSSOURCEDIRECTORY_H - -#include "pandatoolbase.h" -#include "filename.h" - -#include "pvector.h" - -class CVSSourceTree; - -/** - * This represents one particular directory in the hierarchy of source - * directory files. We must scan the source directory to identify where the - * related files have previously been copied. - * - * The tree is maintained in a case-insensitive manner, even on a non-Windows - * system, since you might want to eventually check out the CVS tree onto a - * Windows system--and if you do, you'll be sad if there are case conflicts - * within the tree. So we make an effort to ensure this doesn't happen by - * treating two files with a different case as the same file. - */ -class CVSSourceDirectory { -public: - CVSSourceDirectory(CVSSourceTree *tree, CVSSourceDirectory *parent, - const std::string &dirname); - ~CVSSourceDirectory(); - - std::string get_dirname() const; - Filename get_fullpath() const; - Filename get_path() const; - Filename get_rel_to(const CVSSourceDirectory *other) const; - - int get_num_children() const; - CVSSourceDirectory *get_child(int n) const; - - CVSSourceDirectory *find_relpath(const std::string &relpath); - CVSSourceDirectory *find_dirname(const std::string &dirname); - -public: - bool scan(const Filename &directory, const std::string &key_filename); - -private: - CVSSourceTree *_tree; - CVSSourceDirectory *_parent; - std::string _dirname; - int _depth; - - typedef pvector Children; - Children _children; -}; - -#endif diff --git a/pandatool/src/cvscopy/cvsSourceTree.cxx b/pandatool/src/cvscopy/cvsSourceTree.cxx deleted file mode 100644 index 8511afac6a..0000000000 --- a/pandatool/src/cvscopy/cvsSourceTree.cxx +++ /dev/null @@ -1,546 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cvsSourceTree.cxx - * @author drose - * @date 2000-10-31 - */ - -#include "cvsSourceTree.h" -#include "cvsSourceDirectory.h" - -#include "filename.h" -#include "executionEnvironment.h" -#include "pnotify.h" -#include "string_utils.h" - -#include -#include -#include // for perror -#include - -#ifdef WIN32_VC -#include // for chdir -#endif - -using std::string; - -bool CVSSourceTree::_got_start_fullpath = false; -Filename CVSSourceTree::_start_fullpath; - -/** - * - */ -CVSSourceTree:: -CVSSourceTree() { - _root = nullptr; - _got_root_fullpath = false; -} - -/** - * - */ -CVSSourceTree:: -~CVSSourceTree() { - if (_root != nullptr) { - delete _root; - } -} - -/** - * Sets the root of the source directory. This must be called before scan(), - * and should not be called more than once. - */ -void CVSSourceTree:: -set_root(const Filename &root_path) { - nassertv(_path.empty()); - _path = root_path; -} - -/** - * Scans the complete source directory starting at the indicated pathname. It - * is an error to call this more than once. Returns true on success, false if - * there is an error. - */ -bool CVSSourceTree:: -scan(const Filename &key_filename) { - nassertr(_root == nullptr, false); - Filename root_fullpath = get_root_fullpath(); - _root = new CVSSourceDirectory(this, nullptr, root_fullpath.get_basename()); - return _root->scan(_path, key_filename); -} - -/** - * Returns the root directory of the hierarchy. - */ -CVSSourceDirectory *CVSSourceTree:: -get_root() const { - return _root; -} - -/** - * Returns the source directory that corresponds to the given path, or NULL if - * there is no such directory in the source tree. - */ -CVSSourceDirectory *CVSSourceTree:: -find_directory(const Filename &path) { - string root_fullpath = get_root_fullpath(); - string fullpath = get_actual_fullpath(path); - - // path is a subdirectory within the source hierarchy if and only if - // root_fullpath is an initial prefix of fullpath. - if (root_fullpath.length() > fullpath.length() || - cmp_nocase(fullpath.substr(0, root_fullpath.length()), root_fullpath) != 0) { - // Nope! - return nullptr; - } - - // The relative name is the part of fullpath not in root_fullpath. - Filename relpath = fullpath.substr(root_fullpath.length()); - - return _root->find_relpath(relpath); -} - -/** - * Returns the source directory that corresponds to the given relative path - * from the root, or NULL if there is no match. The relative path may or may - * not include the name of the root directory itself. - */ -CVSSourceDirectory *CVSSourceTree:: -find_relpath(const string &relpath) { - CVSSourceDirectory *result = _root->find_relpath(relpath); - if (result != nullptr) { - return result; - } - - // Check for the root dirname at the front of the path, and remove it if - // it's there. - size_t slash = relpath.find('/'); - Filename first = relpath.substr(0, slash); - Filename rest; - if (slash != string::npos) { - rest = relpath.substr(slash + 1); - } - - if (cmp_nocase(first, _root->get_dirname()) == 0) { - return _root->find_relpath(rest); - } - - return nullptr; -} - -/** - * Returns the source directory that corresponds to the given local directory - * name, or NULL if there is no match. - */ -CVSSourceDirectory *CVSSourceTree:: -find_dirname(const string &dirname) { - return _root->find_dirname(dirname); -} - -/** - * Determines where an externally referenced model file of the indicated name - * should go. It does this by looking for an existing model file of the same - * name; if a matching model is not found, or if multiple matching files are - * found, prompts the user for the directory, or uses suggested_dir. - */ -CVSSourceTree::FilePath CVSSourceTree:: -choose_directory(const string &basename, CVSSourceDirectory *suggested_dir, - bool force, bool interactive) { - static FilePaths empty_paths; - - Basenames::const_iterator bi; - bi = _basenames.find(downcase(basename)); - if (bi != _basenames.end()) { - // The filename already exists somewhere. - const FilePaths &paths = (*bi).second; - - return prompt_user(basename, suggested_dir, paths, - force, interactive); - } - - // Now we have to prompt the user for a suitable place to put it. - return prompt_user(basename, suggested_dir, empty_paths, - force, interactive); -} - -/** - * Returns the full path from the root to the top of the source hierarchy. - */ -Filename CVSSourceTree:: -get_root_fullpath() { - nassertr(!_path.empty(), Filename()); - if (!_got_root_fullpath) { - _root_fullpath = get_actual_fullpath(_path); - _got_root_fullpath = true; - } - return _root_fullpath; -} - -/** - * Returns the local directory name of the root of the tree. - */ -Filename CVSSourceTree:: -get_root_dirname() const { - nassertr(_root != nullptr, Filename()); - return _root->get_dirname(); -} - -/** - * Adds a new file to the set of known files. This is normally called from - * CVSSourceDirectory::scan() and should not be called directly by the user. - */ -void CVSSourceTree:: -add_file(const string &basename, CVSSourceDirectory *dir) { - FilePath file_path(dir, basename); - _basenames[downcase(basename)].push_back(file_path); -} - -/** - * Temporarily changes the current directory to the named path. Returns true - * on success, false on failure. Call restore_cwd() to restore to the - * original directory later. - */ -bool CVSSourceTree:: -temp_chdir(const Filename &path) { - // We have to call this first to guarantee that we have already determined - // our starting directory. - get_start_fullpath(); - - string os_path = path.to_os_specific(); - if (chdir(os_path.c_str()) < 0) { - return false; - } - return true; -} - -/** - * Restores the current directory after changing it from temp_chdir(). - */ -void CVSSourceTree:: -restore_cwd() { - Filename start_fullpath = get_start_fullpath(); - string os_path = start_fullpath.to_os_specific(); - - if (chdir(os_path.c_str()) < 0) { - // Hey! We can't get back to the directory we started from! - perror(os_path.c_str()); - nout << "Can't continue, aborting.\n"; - exit(1); - } -} - - -/** - * Prompts the user, if necessary, to choose a directory to import the given - * file into. - */ -CVSSourceTree::FilePath CVSSourceTree:: -prompt_user(const string &basename, CVSSourceDirectory *suggested_dir, - const CVSSourceTree::FilePaths &paths, - bool force, bool interactive) { - if (paths.size() == 1) { - // The file already exists in exactly one place. - if (!interactive) { - return paths[0]; - } - FilePath result = ask_existing(basename, paths[0]); - if (result.is_valid()) { - return result; - } - - } else if (paths.size() > 1) { - // The file already exists in multiple places. - if (force && !interactive) { - return paths[0]; - } - FilePath result = ask_existing(basename, paths, suggested_dir); - if (result.is_valid()) { - return result; - } - } - - // The file does not already exist, or the user declined to replace an - // existing file. - if (force && !interactive) { - return FilePath(suggested_dir, basename); - } - - // Is the file already in the suggested directory? If not, prompt the user - // to put it there. - bool found_dir = false; - FilePaths::const_iterator pi; - for (pi = paths.begin(); pi != paths.end(); ++pi) { - if ((*pi)._dir == suggested_dir) { - found_dir = true; - break; - } - } - - if (!found_dir) { - FilePath result = ask_new(basename, suggested_dir); - if (result.is_valid()) { - return result; - } - } - - // Ask the user where the damn thing should go. - return ask_any(basename, paths); -} - -/** - * Asks the user if he wants to replace an existing file. - */ -CVSSourceTree::FilePath CVSSourceTree:: -ask_existing(const string &basename, const CVSSourceTree::FilePath &path) { - while (true) { - nout << basename << " found in tree at " - << path.get_path() << ".\n"; - string result = prompt("Overwrite this file (y/n)? "); - nassertr(!result.empty(), FilePath()); - if (result.size() == 1) { - if (tolower(result[0]) == 'y') { - return path; - } else if (tolower(result[0]) == 'n') { - return FilePath(); - } - } - - nout << "*** Invalid response: " << result << "\n\n"; - } -} - -/** - * Asks the user which of several existing files he wants to replace. - */ -CVSSourceTree::FilePath CVSSourceTree:: -ask_existing(const string &basename, const CVSSourceTree::FilePaths &paths, - CVSSourceDirectory *suggested_dir) { - while (true) { - nout << basename << " found in tree at more than one place:\n"; - - bool any_suggested = false; - for (int i = 0; i < (int)paths.size(); i++) { - nout << " " << (i + 1) << ". " - << paths[i].get_path() << "\n"; - if (paths[i]._dir == suggested_dir) { - any_suggested = true; - } - } - - int next_option = paths.size() + 1; - int suggested_option = -1; - - if (!any_suggested) { - // If it wasn't already in the suggested directory, offer to put it - // there. - suggested_option = next_option; - next_option++; - nout << "\n" << suggested_option - << ". create " - << Filename(suggested_dir->get_path(), basename) - << "\n"; - } - - int other_option = next_option; - nout << other_option << ". Other\n"; - - string result = prompt("Choose an option: "); - nassertr(!result.empty(), FilePath()); - const char *nptr = result.c_str(); - char *endptr; - int option = strtol(nptr, &endptr, 10); - if (*endptr == '\0') { - if (option >= 1 && option <= (int)paths.size()) { - return paths[option - 1]; - - } else if (option == suggested_option) { - return FilePath(suggested_dir, basename); - - } else if (option == other_option) { - return FilePath(); - } - } - - nout << "*** Invalid response: " << result << "\n\n"; - } -} - -/** - * Asks the user if he wants to create a new file. - */ -CVSSourceTree::FilePath CVSSourceTree:: -ask_new(const string &basename, CVSSourceDirectory *dir) { - while (true) { - nout << basename << " will be created in " - << dir->get_path() << ".\n"; - string result = prompt("Create this file (y/n)? "); - nassertr(!result.empty(), FilePath()); - if (result.size() == 1) { - if (tolower(result[0]) == 'y') { - return FilePath(dir, basename); - } else if (tolower(result[0]) == 'n') { - return FilePath(); - } - } - - nout << "*** Invalid response: " << result << "\n\n"; - } -} - -/** - * Asks the user to type in the name of the directory in which to store the - * file. - */ -CVSSourceTree::FilePath CVSSourceTree:: -ask_any(const string &basename, - const CVSSourceTree::FilePaths &paths) { - while (true) { - string result = - prompt("Enter the name of the directory to copy " + basename + " to: "); - nassertr(!result.empty(), FilePath()); - - // The user might enter a fully-qualified path to the directory, or a - // relative path from the root (with or without the root's dirname), or - // the dirname of the particular directory. - CVSSourceDirectory *dir = find_directory(result); - if (dir == nullptr) { - dir = find_relpath(result); - } - if (dir == nullptr) { - dir = find_dirname(result); - } - - if (dir != nullptr) { - // If the file is already in this directory, we must preserve its - // existing case. - FilePaths::const_iterator pi; - for (pi = paths.begin(); pi != paths.end(); ++pi) { - if ((*pi)._dir == dir) { - return (*pi); - } - } - - // Otherwise, since we're creating a new file, keep the original case. - return FilePath(dir, basename); - } - - nout << "*** Not a valid directory name: " << result << "\n\n"; - } -} - -/** - * Issues a prompt to the user and waits for a typed response. Returns the - * response (which will not be empty). - */ -string CVSSourceTree:: -prompt(const string &message) { - nout << std::flush; - while (true) { - std::cerr << message << std::flush; - std::string response; - std::getline(std::cin, response); - - // Remove leading and trailing whitespace. - size_t p = 0; - while (p < response.length() && isspace(response[p])) { - p++; - } - - size_t q = response.length(); - while (q > p && isspace(response[q - 1])) { - q--; - } - - if (q > p) { - return response.substr(p, q - p); - } - } -} - -/** - * Determines the actual full path from the root to the named directory. - */ -Filename CVSSourceTree:: -get_actual_fullpath(const Filename &path) { - Filename canon = path; - canon.make_canonical(); - return canon; -} - - -/** - * Returns the full path from the root to the directory in which the user - * started the program. - */ -Filename CVSSourceTree:: -get_start_fullpath() { - if (!_got_start_fullpath) { - Filename cwd = ExecutionEnvironment::get_cwd(); - _start_fullpath = cwd.to_os_specific(); - } - return _start_fullpath; -} - - -/** - * Creates an invalid FilePath specification. - */ -CVSSourceTree::FilePath:: -FilePath() : - _dir(nullptr) -{ -} - -/** - * Creates a valid FilePath specification with the indicated directory and - * basename. - */ -CVSSourceTree::FilePath:: -FilePath(CVSSourceDirectory *dir, const string &basename) : - _dir(dir), - _basename(basename) -{ -} - -/** - * Returns true if this FilePath represents a valid file, or false if it - * represents an error return. - */ -bool CVSSourceTree::FilePath:: -is_valid() const { - return (_dir != nullptr); -} - -/** - * Returns the relative path to this file from the root of the source tree. - */ -Filename CVSSourceTree::FilePath:: -get_path() const { - nassertr(_dir != nullptr, Filename()); - return Filename(_dir->get_path(), _basename); -} - -/** - * Returns the full path to this file. - */ -Filename CVSSourceTree::FilePath:: -get_fullpath() const { - nassertr(_dir != nullptr, Filename()); - return Filename(_dir->get_fullpath(), _basename); -} - -/** - * Returns the relative path to this file as seen from the indicated source - * directory. - */ -Filename CVSSourceTree::FilePath:: -get_rel_from(const CVSSourceDirectory *other) const { - nassertr(_dir != nullptr, Filename()); - return Filename(other->get_rel_to(_dir), _basename); -} diff --git a/pandatool/src/cvscopy/cvsSourceTree.h b/pandatool/src/cvscopy/cvsSourceTree.h deleted file mode 100644 index 238431f78d..0000000000 --- a/pandatool/src/cvscopy/cvsSourceTree.h +++ /dev/null @@ -1,109 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cvsSourceTree.h - * @author drose - * @date 2000-10-31 - */ - -#ifndef CVSSOURCETREE_H -#define CVSSOURCETREE_H - -#include "pandatoolbase.h" - -#include "pvector.h" -#include "pmap.h" -#include "filename.h" - -class CVSSourceDirectory; - -/** - * This represents the root of the tree of source directory files. - * - * The tree is maintained in a case-insensitive manner, even on a non-Windows - * system, since you might want to eventually check out the CVS tree onto a - * Windows system--and if you do, you'll be sad if there are case conflicts - * within the tree. So we make an effort to ensure this doesn't happen by - * treating two files with a different case as the same file. - */ -class CVSSourceTree { -public: - CVSSourceTree(); - ~CVSSourceTree(); - - void set_root(const Filename &root_path); - bool scan(const Filename &key_filename); - - CVSSourceDirectory *get_root() const; - CVSSourceDirectory *find_directory(const Filename &path); - CVSSourceDirectory *find_relpath(const std::string &relpath); - CVSSourceDirectory *find_dirname(const std::string &dirname); - - // This nested class represents the selection of a particular directory in - // which to place a given file, given its basename. The basename of the - // file is returned as part of the answer, because it might have changed in - // case from the original basename (in order to match the case of an - // existing file in the selected directory). - class FilePath { - public: - FilePath(); - FilePath(CVSSourceDirectory *dir, const std::string &basename); - bool is_valid() const; - Filename get_path() const; - Filename get_fullpath() const; - Filename get_rel_from(const CVSSourceDirectory *other) const; - - CVSSourceDirectory *_dir; - std::string _basename; - }; - - FilePath choose_directory(const std::string &basename, - CVSSourceDirectory *suggested_dir, - bool force, bool interactive); - - Filename get_root_fullpath(); - Filename get_root_dirname() const; - - static bool temp_chdir(const Filename &path); - static void restore_cwd(); - -public: - void add_file(const std::string &basename, CVSSourceDirectory *dir); - -private: - typedef pvector FilePaths; - - FilePath - prompt_user(const std::string &basename, CVSSourceDirectory *suggested_dir, - const FilePaths &paths, bool force, bool interactive); - - FilePath ask_existing(const std::string &filename, const FilePath &path); - FilePath ask_existing(const std::string &filename, const FilePaths &paths, - CVSSourceDirectory *suggested_dir); - FilePath ask_new(const std::string &filename, CVSSourceDirectory *dir); - FilePath ask_any(const std::string &filename, const FilePaths &paths); - - std::string prompt(const std::string &message); - - static Filename get_actual_fullpath(const Filename &path); - static Filename get_start_fullpath(); - -private: - Filename _path; - CVSSourceDirectory *_root; - - typedef pmap Basenames; - Basenames _basenames; - - static bool _got_start_fullpath; - static Filename _start_fullpath; - bool _got_root_fullpath; - Filename _root_fullpath; -}; - -#endif diff --git a/pandatool/src/cvscopy/p3cvscopy_composite1.cxx b/pandatool/src/cvscopy/p3cvscopy_composite1.cxx deleted file mode 100644 index 3447005d49..0000000000 --- a/pandatool/src/cvscopy/p3cvscopy_composite1.cxx +++ /dev/null @@ -1,5 +0,0 @@ - -#include "cvsCopy.cxx" -#include "cvsSourceDirectory.cxx" -#include "cvsSourceTree.cxx" - diff --git a/pandatool/src/cvscopy/testCopy.cxx b/pandatool/src/cvscopy/testCopy.cxx deleted file mode 100644 index 78010c58bb..0000000000 --- a/pandatool/src/cvscopy/testCopy.cxx +++ /dev/null @@ -1,65 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file testCopy.cxx - * @author drose - * @date 2000-10-31 - */ - -#include "testCopy.h" -#include "cvsSourceDirectory.h" - -/** - * - */ -TestCopy:: -TestCopy() { - set_program_brief("copy files into a CVS source hierarchy"); - set_program_description - ("This program copies one or more files into a CVS source hierarchy. " - "Rather than copying the named files immediately into the current " - "directory, it first scans the entire source hierarchy, identifying all " - "the already-existing files. If the named file to copy matches the " - "name of an already-existing file in the current directory or elsewhere " - "in the hierarchy, that file is overwritten.\n\n" - - "This is primarily useful as a test program for libcvscopy."); -} - -/** - * - */ -void TestCopy:: -run() { - SourceFiles::iterator fi; - for (fi = _source_files.begin(); fi != _source_files.end(); ++fi) { - CVSSourceDirectory *dest = import(*fi, 0, _model_dir); - if (dest == nullptr) { - exit(1); - } - } -} - -/** - * Called by import() if the timestamps indicate that a file needs to be - * copied. This does the actual copy of a file from source to destination. - * If new_file is true, then dest does not already exist. - */ -bool TestCopy:: -copy_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *, void *, bool) { - return copy_binary_file(source, dest); -} - - -int main(int argc, char *argv[]) { - TestCopy prog; - prog.parse_command_line(argc, argv); - prog.run(); - return 0; -} diff --git a/pandatool/src/cvscopy/testCopy.h b/pandatool/src/cvscopy/testCopy.h deleted file mode 100644 index 3e1b770fee..0000000000 --- a/pandatool/src/cvscopy/testCopy.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file testCopy.h - * @author drose - * @date 2000-10-31 - */ - -#ifndef TESTCOPY_H -#define TESTCOPY_H - -#include "pandatoolbase.h" - -#include "cvsCopy.h" - -/** - * A program to copy ordinary files into the cvs tree. Mainly to test - * CVSCopy. - */ -class TestCopy : public CVSCopy { -public: - TestCopy(); - - void run(); - -protected: - virtual bool copy_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir, void *extra_data, - bool new_file); -}; - -#endif diff --git a/pandatool/src/fltprogs/fltCopy.cxx b/pandatool/src/fltprogs/fltCopy.cxx deleted file mode 100644 index 6ecb3b7833..0000000000 --- a/pandatool/src/fltprogs/fltCopy.cxx +++ /dev/null @@ -1,237 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file fltCopy.cxx - * @author drose - * @date 2000-11-01 - */ - -#include "fltCopy.h" - -#include "cvsSourceDirectory.h" -#include "fltHeader.h" -#include "fltFace.h" -#include "fltExternalReference.h" -#include "fltError.h" -#include "dcast.h" - -/** - * - */ -FltCopy:: -FltCopy() { - set_program_brief("copy MultiGen .flt files into a CVS source hierarchy"); - set_program_description - ("fltcopy copies one or more MultiGen .flt files into a " - "CVS source hierarchy. " - "Rather than copying the named files immediately into the current " - "directory, it first scans the entire source hierarchy, identifying all " - "the already-existing files. If the named file to copy matches the " - "name of an already-existing file in the current directory or elsewhere " - "in the hierarchy, that file is overwritten. Other .flt files, as " - "well as texture files, that are externally referenced by the " - "named .flt file(s) are similarly copied."); - - clear_runlines(); - add_runline("[opts] file.flt [file.flt ... ]"); - - add_path_replace_options(); -} - -/** - * - */ -void FltCopy:: -run() { - SourceFiles::iterator fi; - for (fi = _source_files.begin(); fi != _source_files.end(); ++fi) { - ExtraData ed; - ed._type = FT_flt; - - CVSSourceTree::FilePath dest = import(*fi, &ed, _model_dir); - if (!dest.is_valid()) { - exit(1); - } - } -} - -/** - * Called by import() if verify_file() indicates that a file needs to be - * copied. This does the actual copy of a file from source to destination. - * If new_file is true, then dest does not already exist. - */ -bool FltCopy:: -copy_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir, void *extra_data, bool new_file) { - ExtraData *ed = (ExtraData *)extra_data; - switch (ed->_type) { - case FT_flt: - return copy_flt_file(source, dest, dir); - - case FT_texture: - return copy_texture(source, dest, dir, ed->_texture, new_file); - } - - nout << "Internal error: invalid type " << (int)ed->_type << "\n"; - return false; -} - -/** - * - */ -bool FltCopy:: -copy_flt_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir) { - PT(FltHeader) header = new FltHeader(_path_replace); - - // We don't want to automatically generate .attr files--we'd rather write - // them out explicitly. - header->set_auto_attr_update(FltHeader::AU_none); - - FltError result = header->read_flt(source); - if (result != FE_ok) { - nout << "Cannot read " << source << ": " << result << "\n"; - return false; - } - - header->check_version(); - - // Now scan the flt file for nested references. - Refs refs; - Textures textures; - scan_flt(header, refs, textures); - - Refs::const_iterator ri; - for (ri = refs.begin(); ri != refs.end(); ++ri) { - FltExternalReference *ref = (*ri); - Filename ref_filename = ref->get_ref_filename(); - - if (!ref_filename.exists()) { - nout << "*** Warning: external reference " << ref_filename - << " does not exist.\n"; - } else { - ExtraData ed; - ed._type = FT_flt; - - CVSSourceTree::FilePath ref_path = - import(ref_filename, &ed, _model_dir); - if (!ref_path.is_valid()) { - return false; - } - - // Update the reference to point to the new flt filename, relative to - // the base flt file. - ref->set_ref_filename(ref_path.get_rel_from(dir)); - } - } - - // Remove all the textures from the palette, and then add back only those we - // found in use. This way we don't copy a file that references bogus - // textures. - header->clear_textures(); - - Textures::const_iterator ti; - for (ti = textures.begin(); ti != textures.end(); ++ti) { - FltTexture *tex = (*ti); - Filename texture_filename = tex->get_texture_filename(); - - if (!texture_filename.exists()) { - nout << "*** Warning: texture " << texture_filename - << " does not exist.\n"; - } else { - ExtraData ed; - ed._type = FT_texture; - ed._texture = tex; - - CVSSourceTree::FilePath texture_path = - import(texture_filename, &ed, _map_dir); - if (!texture_path.is_valid()) { - return false; - } - - // Update the texture reference to point to the new texture filename, - // relative to the flt file. - tex->set_texture_filename(texture_path.get_rel_from(dir)); - header->add_texture(tex); - } - } - - // Finally, write the resulting file out. - result = header->write_flt(dest); - if (result != FE_ok) { - nout << "Cannot write " << dest << "\n"; - return false; - } - - return true; -} - -/** - * - */ -bool FltCopy:: -copy_texture(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir, FltTexture *tex, bool new_file) { - if (!copy_binary_file(source, dest)) { - return false; - } - - // Also write out the .attr file. - Filename attr_filename = dest.get_fullpath() + ".attr"; - if (!attr_filename.exists()) { - new_file = true; - } - - tex->write_attr_data(attr_filename); - - if (new_file) { - cvs_add(attr_filename); - } - - return true; -} - -/** - * Recursively walks through the flt file hierarchy, looking for texture - * references and external flt file references. - */ -void FltCopy:: -scan_flt(FltRecord *record, FltCopy::Refs &refs, FltCopy::Textures &textures) { - if (record->is_of_type(FltFace::get_class_type())) { - FltFace *face; - DCAST_INTO_V(face, record); - if (face->has_texture()) { - textures.insert(face->get_texture()); - } - - } else if (record->is_of_type(FltExternalReference::get_class_type())) { - FltExternalReference *ref; - DCAST_INTO_V(ref, record); - - refs.insert(ref); - } - - int i; - int num_subfaces = record->get_num_subfaces(); - for (i = 0; i < num_subfaces; i++) { - scan_flt(record->get_subface(i), refs, textures); - } - - int num_children = record->get_num_children(); - for (i = 0; i < num_children; i++) { - scan_flt(record->get_child(i), refs, textures); - } -} - - -int main(int argc, char *argv[]) { - FltCopy prog; - prog.parse_command_line(argc, argv); - prog.run(); - return 0; -} diff --git a/pandatool/src/fltprogs/fltCopy.h b/pandatool/src/fltprogs/fltCopy.h deleted file mode 100644 index 2370fec605..0000000000 --- a/pandatool/src/fltprogs/fltCopy.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file fltCopy.h - * @author drose - * @date 2000-11-01 - */ - -#ifndef FLTCOPY_H -#define FLTCOPY_H - -#include "pandatoolbase.h" - -#include "cvsCopy.h" - -#include "dSearchPath.h" -#include "pointerTo.h" - -#include "pset.h" - -class FltRecord; -class FltTexture; -class FltExternalReference; - -/** - * A program to copy Multigen .flt files into the cvs tree. It copies the - * base file plus all externally referenced files as well as all textures. - */ -class FltCopy : public CVSCopy { -public: - FltCopy(); - - void run(); - -protected: - virtual bool copy_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir, void *extra_data, - bool new_file); - -private: - enum FileType { - FT_flt, - FT_texture - }; - - class ExtraData { - public: - FileType _type; - FltTexture *_texture; - }; - - bool copy_flt_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir); - bool copy_texture(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir, FltTexture *tex, - bool new_file); - - - typedef pset< PT(FltExternalReference) > Refs; - typedef pset< PT(FltTexture) > Textures; - - void scan_flt(FltRecord *record, Refs &refs, Textures &textures); -}; - -#endif diff --git a/pandatool/src/mayaprogs/mayaCopy.cxx b/pandatool/src/mayaprogs/mayaCopy.cxx deleted file mode 100644 index d10ed8e0aa..0000000000 --- a/pandatool/src/mayaprogs/mayaCopy.cxx +++ /dev/null @@ -1,457 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaCopy.cxx - * @author drose - * @date 2002-05-10 - * Modified 19Mar10 by ETC PandaSE team (see - * header comment for mayaToEgg.cxx for more details) - */ - -#include "mayaCopy.h" -#include "config_maya.h" -#include "cvsSourceDirectory.h" -#include "dcast.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - -#include "mayaShader.h" - -using std::endl; -using std::string; - -/** - * - */ -MayaCopy:: -MayaCopy() { - set_program_brief("copy Maya .mb files into a CVS source hierarchy"); - set_program_description - ("mayacopy copies one or more Maya .mb files into a " - "CVS source hierarchy. " - "Rather than copying the named files immediately into the current " - "directory, it first scans the entire source hierarchy, identifying all " - "the already-existing files. If the named file to copy matches the " - "name of an already-existing file in the current directory or elsewhere " - "in the hierarchy, that file is overwritten. Other .mb files, as " - "well as texture files, that are externally referenced by the " - "named .mb file(s) are similarly copied."); - - clear_runlines(); - add_runline("[opts] file.mb [file.mb ... ]"); - - add_option - ("keepver", "", 0, - "Don't attempt to strip the Maya version number from the tail of the " - "source filename before it is copied into the tree.", - &CVSCopy::dispatch_none, &_keep_ver); - - /* - add_option - ("rp", "replace_prefix", 80, - "use these prefixes when replacing reference with the recently copied file from the " - "source filename before it is copied into the tree.", - &CVSCopy::dispatch_vector_string, NULL, &_replace_prefix); - */ - - add_option - ("omittex", "", 0, - "Character animation files do not need to copy the texures. " - "This option omits the textures of the models to be re-mayacopied", - &CVSCopy::dispatch_none, &_omit_tex); - - add_option - ("omitref", "", 0, - "Character animation files do not need to copy internal file references. " - "This option omits the references of the models to be re-mayacopied", - &CVSCopy::dispatch_none, &_omit_ref); - - add_option - ("ma", "", 0, - "Write a .ma file instead of a .mb file (regardless of input type)", - &CVSCopy::dispatch_none, &_maya_ascii); - - add_path_replace_options(); -} - -/** - * - */ -void MayaCopy:: -run() { - _maya = MayaApi::open_api(_program_name); - if (!_maya->is_valid()) { - nout << "Unable to initialize Maya.\n"; - exit(1); - } - - SourceFiles::iterator fi; - for (fi = _source_files.begin(); fi != _source_files.end(); ++fi) { - _curr_idx = 0; - ExtraData ed; - ed._type = FT_maya; - - CVSSourceTree::FilePath path = import(*fi, &ed, _model_dir); - if (!path.is_valid()) { - nout << "\nUnable to copy, aborting!\n\n"; - exit(1); - } - } -} - -/** - * Called by import() if verify_file() indicates that a file needs to be - * copied. This does the actual copy of a file from source to destination. - * If new_file is true, then dest does not already exist. - */ -bool MayaCopy:: -copy_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir, void *extra_data, bool new_file) { - ExtraData *ed = (ExtraData *)extra_data; - switch (ed->_type) { - case FT_maya: - return copy_maya_file(source, dest, dir); - - case FT_texture: - if (_omit_tex) { - return true; - } - return copy_texture(source, dest, dir); - } - - nout << "Internal error: invalid type " << (int)ed->_type << "\n"; - return false; -} - -/** - * Given a source filename (including the basename only, without a dirname), - * return the appropriate corresponding filename within the source directory. - * This may be used by derived classes to, for instance, strip a version - * number from the filename. - */ -string MayaCopy:: -filter_filename(const string &source) { - if (_keep_ver) { - return source; - } - - size_t dot = source.rfind('.'); - size_t underscore = source.rfind("_v", dot); - if ((underscore != string::npos) && !isdigit(source.at(underscore+2))) - underscore = string::npos; - - string extension = source.substr(dot); - if (extension == ".ma" || extension == ".mb") { - // If we are reading a Maya file (as opposed to a texture image), then we - // always write ".mb" files out (unless -ma was specified on the command - // line). - if (_maya_ascii) { - extension = ".ma"; - } else { - extension = ".mb"; - } - } - - if (underscore == string::npos) { - // No version number appears to be present. - return source.substr(0, dot) + extension; - } else { - return source.substr(0, underscore) + extension; - } -} - -/** - * - */ -bool MayaCopy:: -copy_maya_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir) { - if (!_maya->read(source)) { - maya_cat.error() - << "Unable to read " << source << "\n"; - return false; - } - - // Get the set of externally referenced Maya files. - MStringArray refs; - MStatus status = MFileIO::getReferences(refs); - if (status != MStatus::kSuccess) { - status.perror("MItDag constructor"); - return false; - } - - // Finally, copy in any referenced Maya files. - unsigned int num_refs = refs.length(); - - unsigned int ref_index; - maya_cat.info() << "num_refs = " << num_refs << endl; - for (ref_index = 0; ref_index < num_refs; ref_index++) { - maya_cat.info() << "curr_idx " << _curr_idx << endl; - string lookup = refs[ref_index].asChar(); - string blah = "file -q -referenceNode \"" + lookup + "\";"; - maya_cat.info() << blah << endl; - MString result; - status = MGlobal::executeCommand(MString(blah.c_str()), result); - maya_cat.info() << "result = " << result.asChar() << endl; - - // for multiple reference of the same model. maya throws in a {#} at the - // end, ignore that - size_t dup = lookup.find('{'); - if (dup != string::npos){ - lookup.erase(dup); - } - - // to check out this specific reference is actually loaded or not somehow - // this flag order of MEL script must be observed to guarantee proper - // working - string refNode = result.asChar(); - string refCheckCmd = "file -rfn " + refNode + " -q -dr;"; - int deferredRef; - status = MGlobal::executeCommand(MString(refCheckCmd.c_str()), deferredRef); - maya_cat.info() << "deferredRef = " << deferredRef << endl; - if (deferredRef == 1) { // means this reference is deferred, unloaded - continue; - } - - Filename filename = - _path_replace->convert_path(Filename::from_os_specific(lookup)); - - CVSSourceTree::FilePath path = - _tree.choose_directory(filename.get_basename(), dir, _force, _interactive); - Filename new_filename = path.get_rel_from(dir); - - if (maya_cat.is_spam()) { - maya_cat.spam() << "cvs dir " << dir->get_fullpath().to_os_generic() << endl; - maya_cat.spam() << "cvs path " << path.get_fullpath().to_os_generic() << endl; - } - MString result2; - - if (maya_cat.is_debug()) { - string cmdStr = "pwd"; - MString result3; - status = MGlobal::executeCommand(MString(cmdStr.c_str()), result3); - maya_cat.debug() << "result = " << result3.asChar() << "\n"; - } - _exec_string.push_back("file -loadReference \"" + string(result.asChar()) + "\" -type \"mayaBinary\" -options \"v=0\" \"" + new_filename.to_os_generic() + "\";"); - if (!_omit_ref) { - maya_cat.info() << "executing command: " << _exec_string[_curr_idx] << "\n"; - status = MGlobal::executeCommand(MString(_exec_string[_curr_idx].c_str())); - if (status != MStatus::kSuccess) { - status.perror("loadReference failed"); - } - } - _curr_idx++; - } - - if (!_omit_tex) { - // Get all the shaders so we can determine the set of textures. - _shaders.clear(); - collect_shaders(); - int num_shaders = _shaders.get_num_shaders(); - for (int i = 0; i < num_shaders; i++) { - MayaShader *shader = _shaders.get_shader(i); - for (size_t j = 0; j < shader->_all_maps.size(); j++) { - if (!extract_texture(*shader->_all_maps[j], dir)) { - return false; - } - } - } - } - - // Now write out the Maya file. - if (!_maya->write(dest)) { - maya_cat.error() - << "Cannot write " << dest << "\n"; - return false; - } - - for (ref_index = 0; ref_index < num_refs; ref_index++) { - if (1) { // we may want an option later to pull in all the referenced files - continue; - } - - string lookup = refs[ref_index].asChar(); - // for multiple reference of the same model. maya throws in a {#} at the - // end, ignore that - size_t dup = lookup.find('{'); - if (dup != string::npos){ - lookup.erase(dup); - } - - Filename filename = - _path_replace->convert_path(Filename::from_os_specific(lookup)); - - maya_cat.info() - << "External ref: " << filename << "\n"; - - // Now import the file - ExtraData ed; - ed._type = FT_maya; - - CVSSourceTree::FilePath path = import(filename, &ed, _model_dir); - if (!path.is_valid()) { - exit(1); - } - } - - return true; -} - -/** - * Gets the texture out of the indicated color channel and copies it in, - * updating the channel with the new texture filename. Returns true on - * success, false on failure. - */ -bool MayaCopy:: -extract_texture(MayaShaderColorDef &color_def, CVSSourceDirectory *dir) { - Filename texture_filename = - _path_replace->convert_path(color_def._texture_filename); - if (!texture_filename.exists()) { - nout << "*** Error: texture " << texture_filename - << " does not exist.\n"; - return false; - } else if (!texture_filename.is_regular_file()) { - nout << "*** Error: texture " << texture_filename - << " is not a regular file.\n"; - return false; - } else { - ExtraData ed; - ed._type = FT_texture; - - CVSSourceTree::FilePath texture_path = - import(texture_filename, &ed, _map_dir); - - if (!texture_path.is_valid()) { - return false; - } - - // Update the texture reference to point to the new texture filename, - // relative to the maya file. - Filename new_filename = texture_path.get_rel_from(dir); - color_def.reset_maya_texture(new_filename); - } - - return true; -} - -/** - * - */ -bool MayaCopy:: -copy_texture(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir) { - if (!copy_binary_file(source, dest)) { - return false; - } - - return true; -} - -/** - * Recursively walks through the maya scene graph hierarchy, looking for - * shaders. - */ -bool MayaCopy:: -collect_shaders() { - MStatus status; - - MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status); - if (status != MStatus::kSuccess) { - status.perror("MItDag constructor"); - return false; - } - - // This while loop walks through the entire Maya hierarchy, one node at a - // time. Maya's MItDag object automatically performs a depth-first - // traversal of its scene graph. - bool all_ok = true; - while (!dag_iterator.isDone()) { - MDagPath dag_path; - status = dag_iterator.getPath(dag_path); - if (status != MStatus::kSuccess) { - status.perror("MItDag::getPath"); - } else { - if (!collect_shader_for_node(dag_path)) { - all_ok = false; - } - } - - dag_iterator.next(); - } - - if (!all_ok) { - nout << "Errors encountered in traversal.\n"; - return false; - } - - return true; -} - -/** - * Gets the relevant shader on the current node, if it has one. - */ -bool MayaCopy:: -collect_shader_for_node(const MDagPath &dag_path) { - MStatus status; - MFnDagNode dag_node(dag_path, &status); - if (status != MStatus::kSuccess) { - status.perror("MFnDagNode constructor"); - return false; - } - - if (dag_path.hasFn(MFn::kNurbsSurface)) { - MFnNurbsSurface surface(dag_path, &status); - if (status) { - _shaders.find_shader_for_node(surface.object(), false); - } - - } else if (dag_path.hasFn(MFn::kMesh)) { - MFnMesh mesh(dag_path, &status); - if (status) { - // Meshes may have multiple different shaders. - MObjectArray shaders; - MIntArray poly_shader_indices; - - status = mesh.getConnectedShaders(dag_path.instanceNumber(), - shaders, poly_shader_indices); - if (status) { - unsigned int num_shaders = shaders.length(); - for (unsigned int shader_index = 0; - shader_index < num_shaders; - shader_index++) { - MObject engine = shaders[shader_index]; - _shaders.find_shader_for_shading_engine(engine, false); - } - } - } - - } else { - // Ignoring other kinds of node. - } - - return true; -} - - -int main(int argc, char *argv[]) { - MayaCopy prog; - prog.parse_command_line(argc, argv); - prog.run(); - return 0; -} diff --git a/pandatool/src/mayaprogs/mayaCopy.h b/pandatool/src/mayaprogs/mayaCopy.h deleted file mode 100644 index 38f0aef9de..0000000000 --- a/pandatool/src/mayaprogs/mayaCopy.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaCopy.h - * @author drose - * @date 2002-05-10 - */ - -#ifndef MAYACOPY_H -#define MAYACOPY_H - -#include "pandatoolbase.h" -#include "cvsCopy.h" -#include "mayaApi.h" -#include "dSearchPath.h" -#include "pointerTo.h" - -#include "pset.h" - -#include "pre_maya_include.h" -#include -#include "post_maya_include.h" - -#include "mayaShaders.h" - -class MayaShader; -class MayaShaderColorDef; - -/** - * A program to copy Maya .mb files into the cvs tree. - */ -class MayaCopy : public CVSCopy { -public: - MayaCopy(); - - void run(); - -protected: - virtual bool copy_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir, void *extra_data, - bool new_file); - - virtual std::string filter_filename(const std::string &source); - -private: - enum FileType { - FT_maya, - FT_texture - }; - - class ExtraData { - public: - FileType _type; - MayaShader *_shader; - }; - - bool copy_maya_file(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir); - bool extract_texture(MayaShaderColorDef &color_def, CVSSourceDirectory *dir); - bool copy_texture(const Filename &source, const Filename &dest, - CVSSourceDirectory *dir); - - bool collect_shaders(); - bool collect_shader_for_node(const MDagPath &dag_path); - - bool _keep_ver; - bool _omit_tex; - bool _omit_ref; - int _curr_idx; - bool _maya_ascii; - /* - vector_string _replace_prefix; - */ - - vector_string _exec_string; - - PT(MayaApi) _maya; - MayaShaders _shaders; -}; - -#endif From ec08fff3a788a2efa33cafdba77cf011a79999f3 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 13 Jan 2019 00:20:56 +0100 Subject: [PATCH 031/144] travis: enable Discord notification --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2c4efe8a65..c3991fbeb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,3 +54,8 @@ notifications: on_failure: always use_notice: true skip_join: false + webhooks: + urls: + - https://www.panda3d.org/webhooks/travis-ci.php + on_success: change + on_failure: always From 095d6ac818e88dc2a7a53bb7f68fe9f49d5eefe2 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 13 Jan 2019 13:14:58 +0100 Subject: [PATCH 032/144] readme: fix link to development builds Closes #533 [skip ci] --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 99c7c39a5d..a5cda4ee03 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Installing Panda3D ================== The latest Panda3D SDK can be downloaded from -(this page)[https://www.panda3d.org/download/sdk-1-10-0/]. +[this page](https://www.panda3d.org/download/sdk-1-10-0/). If you are familiar with installing Python packages, you can use the following comand: @@ -40,7 +40,7 @@ pip install --pre --extra-index-url https://archive.panda3d.org/ panda3d If this command fails, please make sure your version of pip is up-to-date. If you prefer to install the full SDK with all tools, the latest development -builds can be obtained from (this page)[https://www.panda3d.org/download/]. +builds can be obtained from [this page](https://www.panda3d.org/download.php?version=devel&sdk). These are automatically kept up-to-date with the latest GitHub version of Panda. From d51db6e39e0c50aa2ce2f02321b32e5f22c36fdc Mon Sep 17 00:00:00 2001 From: Donny Lawrence Date: Sun, 13 Jan 2019 11:46:57 -0500 Subject: [PATCH 033/144] Fix an instance where a macOS window will stick around when trying to have it destroyed. This commit also removes an extraneous call to [_window setReleasedWhenClosed], which is already set in cocoaPandaWindow's init method. --- panda/src/cocoadisplay/cocoaGraphicsWindow.mm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm index c3f23d4013..0a140109c7 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm @@ -711,8 +711,11 @@ close_window() { } if (_window != nil) { - [_window setReleasedWhenClosed: YES]; [_window close]; + + // Process events once more so any pending NSEvents are cleared. Not doing + // this causes the window to stick around after calling [_window close]. + process_events(); _window = nil; } From 5a9a87d2c101a940c898a8246bd6ac349ab7b444 Mon Sep 17 00:00:00 2001 From: Younguk Kim Date: Sun, 13 Jan 2019 22:04:27 +0900 Subject: [PATCH 034/144] makepanda: fix link error of assimp tool Closes #535 --- makepanda/makepanda.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index dc0bded1f8..6e56cfccf3 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -5825,7 +5825,7 @@ if not PkgSkip("PANDATOOL") and not PkgSkip("ASSIMP"): TargetAdd('p3assimp_composite1.obj', opts=OPTS, input='p3assimp_composite1.cxx') TargetAdd('libp3assimp.dll', input='p3assimp_composite1.obj') TargetAdd('libp3assimp.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libp3assimp.dll', opts=OPTS+['ZLIB']) + TargetAdd('libp3assimp.dll', opts=OPTS+['ZLIB', 'ADVAPI']) # # DIRECTORY: pandatool/src/daeprogs/ From 955081f81f060f20befd86c8aefbbea64148f75e Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Sun, 13 Jan 2019 13:23:20 -0700 Subject: [PATCH 035/144] movies: Fix missing includes in {opus,vorbis}AudioCursor.cxx --- panda/src/movies/opusAudioCursor.cxx | 4 ++++ panda/src/movies/vorbisAudioCursor.cxx | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/panda/src/movies/opusAudioCursor.cxx b/panda/src/movies/opusAudioCursor.cxx index 2b1591e971..8554215088 100644 --- a/panda/src/movies/opusAudioCursor.cxx +++ b/panda/src/movies/opusAudioCursor.cxx @@ -12,6 +12,10 @@ */ #include "opusAudioCursor.h" + +#include "config_movies.h" + +#include "opusAudio.h" #include "virtualFileSystem.h" #ifdef HAVE_OPUS diff --git a/panda/src/movies/vorbisAudioCursor.cxx b/panda/src/movies/vorbisAudioCursor.cxx index d4478c9f07..d3210ae46e 100644 --- a/panda/src/movies/vorbisAudioCursor.cxx +++ b/panda/src/movies/vorbisAudioCursor.cxx @@ -12,6 +12,10 @@ */ #include "vorbisAudioCursor.h" + +#include "config_movies.h" + +#include "vorbisAudio.h" #include "virtualFileSystem.h" #ifdef HAVE_VORBIS From 2c513ba1c43811b328544eec0c722fa76d3d91c8 Mon Sep 17 00:00:00 2001 From: Donny Lawrence Date: Sun, 13 Jan 2019 19:07:43 -0500 Subject: [PATCH 036/144] Move handle_close_event() call to windowShouldClose, which only triggers when the close button is pressed by the user. --- panda/src/cocoadisplay/cocoaPandaWindowDelegate.h | 1 - panda/src/cocoadisplay/cocoaPandaWindowDelegate.mm | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/panda/src/cocoadisplay/cocoaPandaWindowDelegate.h b/panda/src/cocoadisplay/cocoaPandaWindowDelegate.h index 1a80ef056e..93d5b7b35b 100644 --- a/panda/src/cocoadisplay/cocoaPandaWindowDelegate.h +++ b/panda/src/cocoadisplay/cocoaPandaWindowDelegate.h @@ -34,7 +34,6 @@ class CocoaGraphicsWindow; - (void)windowDidBecomeKey:(NSNotification *)notification; - (void)windowDidResignKey:(NSNotification *)notification; - (BOOL)windowShouldClose:(id)sender; -- (void)windowWillClose:(NSNotification *)notification; // TODO: handle fullscreen on Lion. diff --git a/panda/src/cocoadisplay/cocoaPandaWindowDelegate.mm b/panda/src/cocoadisplay/cocoaPandaWindowDelegate.mm index 6b93410538..7e39748bd1 100644 --- a/panda/src/cocoadisplay/cocoaPandaWindowDelegate.mm +++ b/panda/src/cocoadisplay/cocoaPandaWindowDelegate.mm @@ -50,11 +50,11 @@ } - (BOOL) windowShouldClose:(id)sender { - return _graphicsWindow->handle_close_request(); -} - -- (void) windowWillClose:(NSNotification *)notification { - _graphicsWindow->handle_close_event(); + bool should_close = _graphicsWindow->handle_close_request(); + if (should_close) { + _graphicsWindow->handle_close_event(); + } + return should_close; } @end From 1389ada3845bc6de46091d1db7579ca798b5cb80 Mon Sep 17 00:00:00 2001 From: LD Date: Fri, 18 Jan 2019 13:19:35 +0100 Subject: [PATCH 037/144] setuptools: os.makedirs does not support 'exist_ok' parameter in Python2 Closes #540 --- direct/src/dist/commands.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/direct/src/dist/commands.py b/direct/src/dist/commands.py index abf0e9f777..948891d19d 100644 --- a/direct/src/dist/commands.py +++ b/direct/src/dist/commands.py @@ -1347,7 +1347,8 @@ class bdist_apps(setuptools.Command): platforms = build_cmd.platforms build_base = os.path.abspath(build_cmd.build_base) - os.makedirs(self.dist_dir, exist_ok=True) + if not os.path.exists(self.dist_dir): + os.makedirs(self.dist_dir) os.chdir(self.dist_dir) for platform in platforms: From e4f0a9ce32dc84662d82a1751b4ed12ffde7f474 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 19 Jan 2019 22:59:51 +0100 Subject: [PATCH 038/144] pgraph: allow getting NodePath from CullTraverserData in Python --- panda/src/pgraph/cullTraverserData.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/panda/src/pgraph/cullTraverserData.h b/panda/src/pgraph/cullTraverserData.h index e275dcfd93..eca5f142dc 100644 --- a/panda/src/pgraph/cullTraverserData.h +++ b/panda/src/pgraph/cullTraverserData.h @@ -67,6 +67,8 @@ PUBLISHED: void apply_transform_and_state(CullTraverser *trav); void apply_transform(const TransformState *node_transform); + MAKE_PROPERTY(node_path, get_node_path); + private: // We store a chain leading all the way to the root, so that we can compose // a NodePath. We may be able to eliminate this requirement in the future. From 85ca6f66f25c9cbc7077aa698c31b0cad15981bb Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 19 Jan 2019 23:02:30 +0100 Subject: [PATCH 039/144] makepackage: add some missing imports --- makepanda/makepackage.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py index 31a45a2bb9..85e96e3491 100755 --- a/makepanda/makepackage.py +++ b/makepanda/makepackage.py @@ -5,6 +5,8 @@ from installpanda import * import sys import os import shutil +import glob +import re INSTALLER_DEB_FILE = """ From 73076c71159481215e71946b00764576db8a03db Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 19 Jan 2019 23:04:19 +0100 Subject: [PATCH 040/144] android: add missing include for open() definition --- panda/src/android/android_main.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/panda/src/android/android_main.cxx b/panda/src/android/android_main.cxx index 2f7d7e3dcc..13895d99f6 100644 --- a/panda/src/android/android_main.cxx +++ b/panda/src/android/android_main.cxx @@ -24,6 +24,7 @@ #include "config_display.h" // #define OPENGLES_1 #include "config_androiddisplay.h" +#include #include #include From 7d09451b2da4908359fc7b7f0697e4aa88c00006 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 19 Jan 2019 23:08:14 +0100 Subject: [PATCH 041/144] display: remove unused iterator variable --- panda/src/display/graphicsEngine.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index ae1052ba1d..80973ae071 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -593,7 +593,6 @@ remove_all_windows() { // appeared to be happening, and this worked around it. Windows old_windows; old_windows.swap(_windows); - Windows::iterator wi; for (GraphicsOutput *win : old_windows) { nassertv(win != nullptr); do_remove_window(win, current_thread); From 6eca44464e28309a067ce4e694970ab2e6682993 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 19 Jan 2019 23:10:46 +0100 Subject: [PATCH 042/144] load_dso: prevent load_dso_error() from returning old error This happens if load_dso fails due to being unable to find the file, but not setting the dlerror flag and therefore causing a misleading error message to be shown. --- dtool/src/dtoolutil/load_dso.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtool/src/dtoolutil/load_dso.cxx b/dtool/src/dtoolutil/load_dso.cxx index 79d821b5fa..0c7ae24ebe 100644 --- a/dtool/src/dtoolutil/load_dso.cxx +++ b/dtool/src/dtoolutil/load_dso.cxx @@ -132,6 +132,9 @@ void * load_dso(const DSearchPath &path, const Filename &filename) { Filename abspath = resolve_dso(path, filename); if (!abspath.is_regular_file()) { + // Make sure the error flag is cleared, to prevent a subsequent call to + // load_dso_error() from returning a previously stored error. + dlerror(); return nullptr; } string os_specific = abspath.to_os_specific(); From ba4036e290af32aa5c357abfef6632c08d520fff Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 19 Jan 2019 23:12:46 +0100 Subject: [PATCH 043/144] prc: clear error flag if loading deploy-ng blobinfo fails --- dtool/src/prc/configPageManager.cxx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dtool/src/prc/configPageManager.cxx b/dtool/src/prc/configPageManager.cxx index 72e00f0189..b26eb17c69 100644 --- a/dtool/src/prc/configPageManager.cxx +++ b/dtool/src/prc/configPageManager.cxx @@ -129,7 +129,12 @@ reload_implicit_pages() { #else const BlobInfo *blobinfo = (const BlobInfo *)dlsym(dlopen(NULL, RTLD_NOW), "blobinfo"); #endif - if (blobinfo != nullptr && (blobinfo->version == 0 || blobinfo->num_pointers < 10)) { + if (blobinfo == nullptr) { +#ifndef _MSC_VER + // Clear the error flag. + dlerror(); +#endif + } else if (blobinfo->version == 0 || blobinfo->num_pointers < 10) { blobinfo = nullptr; } From 7968022c239363590b673d187cbbadabd7d02426 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 20 Jan 2019 00:30:34 +0100 Subject: [PATCH 044/144] Fix some warnings comparing char against EOF This is not possible on platforms where char is unsigned. In cases where fail() is checked, it is also unnecessary. --- panda/src/downloader/documentSpec.cxx | 4 ++-- panda/src/downloader/httpDate.cxx | 2 +- panda/src/pnmimagetypes/pnmFileTypePNM.cxx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/panda/src/downloader/documentSpec.cxx b/panda/src/downloader/documentSpec.cxx index 34bfe3808d..a27ebe0338 100644 --- a/panda/src/downloader/documentSpec.cxx +++ b/panda/src/downloader/documentSpec.cxx @@ -66,7 +66,7 @@ input(std::istream &in) { // Scan the tag, up to but not including the closing paren. std::string tag; in >> ch; - while (!in.fail() && ch != EOF && ch != ')') { + while (!in.fail() && ch != ')') { tag += ch; // We want to include embedded whitespace, so we use get(). ch = in.get(); @@ -81,7 +81,7 @@ input(std::istream &in) { // Scan the date, up to but not including the closing bracket. if (ch != ']') { std::string date; - while (!in.fail() && ch != EOF && ch != ']') { + while (!in.fail() && ch != ']') { date += ch; ch = in.get(); } diff --git a/panda/src/downloader/httpDate.cxx b/panda/src/downloader/httpDate.cxx index e49769257f..e17c6c06d6 100644 --- a/panda/src/downloader/httpDate.cxx +++ b/panda/src/downloader/httpDate.cxx @@ -279,7 +279,7 @@ input(std::istream &in) { string date; ch = in.get(); - while (!in.fail() && ch != EOF && ch != '"') { + while (!in.fail() && ch != '"') { date += ch; ch = in.get(); } diff --git a/panda/src/pnmimagetypes/pnmFileTypePNM.cxx b/panda/src/pnmimagetypes/pnmFileTypePNM.cxx index cdc1e62f93..02411c0933 100644 --- a/panda/src/pnmimagetypes/pnmFileTypePNM.cxx +++ b/panda/src/pnmimagetypes/pnmFileTypePNM.cxx @@ -193,7 +193,7 @@ pm_getuint(istream * const ifP) { 'unsigned int'), issue an error message to stderr and abort the program. -----------------------------------------------------------------------------*/ - char ch; + int ch; unsigned int i; // skip whitespace From c0b973b78998fa67fde912dda40dcdc2b7fca5d4 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 19 Jan 2019 23:15:21 +0100 Subject: [PATCH 045/144] makepanda: support cross-compiling for Android again --- makepanda/makepackage.py | 15 +++++++-- makepanda/makepanda.py | 5 ++- makepanda/makepandacore.py | 69 ++++++++++++++++++++++++++++++++------ 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py index 85e96e3491..c11651283a 100755 --- a/makepanda/makepackage.py +++ b/makepanda/makepackage.py @@ -867,6 +867,11 @@ def MakeInstallerAndroid(version, **kwargs): line = line.strip() if not line: continue + + if ' ' in line: + line = line.split(' ', 1)[0] + + # Change .so.1.2 suffix to .so, as needed for loading in .apk if '.so.' in line: dep = line.rpartition('.so.')[0] + '.so' oscmd("patchelf --replace-needed %s %s %s" % (line, dep, target), True) @@ -960,7 +965,7 @@ def MakeInstallerAndroid(version, **kwargs): aapt_cmd += " -F %s" % (apk_unaligned) aapt_cmd += " -M apkroot/AndroidManifest.xml" aapt_cmd += " -A apkroot/assets -S apkroot/res" - aapt_cmd += " -I $PREFIX/share/aapt/android.jar" + aapt_cmd += " -I %s" % (SDK["ANDROID_JAR"]) oscmd(aapt_cmd) # And add all the libraries to it. @@ -974,7 +979,13 @@ def MakeInstallerAndroid(version, **kwargs): oscmd("zipalign -v -p 4 %s %s" % (apk_unaligned, apk_unsigned)) # Finally, sign it using a debug key. This is generated if it doesn't exist. - oscmd("apksigner debug.ks %s panda3d.apk" % (apk_unsigned)) + if GetHost() == 'android': + # Termux version of apksigner automatically generates a debug key. + oscmd("apksigner debug.ks %s panda3d.apk" % (apk_unsigned)) + else: + if not os.path.isfile('debug.ks'): + oscmd("keytool -genkey -noprompt -dname 'CN=Panda3D,O=Panda3D,C=US' -keystore debug.ks -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 1000") + oscmd("apksigner sign --ks debug.ks --ks-pass pass:android --min-sdk-version %s --out panda3d.apk %s" % (SDK["ANDROID_API"], apk_unsigned)) # Clean up. oscmd("rm -rf apkroot") diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 6e56cfccf3..792bf5ebfc 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -2043,7 +2043,10 @@ def CompileRsrc(target, src, opts): def CompileJava(target, src, opts): """Compiles a .java file into a .class file.""" - cmd = "ecj " + if GetHost() == 'android': + cmd = "ecj " + else: + cmd = "javac -bootclasspath " + BracketNameWithQuotes(SDK["ANDROID_JAR"]) + " " optlevel = GetOptimizeOption(opts) if optlevel >= 4: diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 8790538395..6babeb7fd8 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -2463,22 +2463,40 @@ def SdkLocateAndroid(): SDK["ANDROID_TRIPLE"] = ANDROID_TRIPLE if GetHost() == 'android': + # Assume we're compiling from termux. + prefix = os.environ.get("PREFIX", "/data/data/com.termux/files/usr") + SDK["ANDROID_JAR"] = prefix + "/share/aapt/android.jar" return - # Determine the NDK installation directory. - if 'NDK_ROOT' not in os.environ: - exit('NDK_ROOT must be set when compiling for Android!') + sdk_root = os.environ.get('ANDROID_HOME') + if not sdk_root or not os.path.isdir(sdk_root): + sdk_root = os.environ.get('ANDROID_SDK_ROOT') + if not sdk_root: + exit('ANDROID_SDK_ROOT must be set when compiling for Android!') + elif not os.path.isdir(sdk_root): + exit('Cannot find %s. Please install Android SDK and set ANDROID_SDK_ROOT or ANDROID_HOME.' % (sdk_root)) - ndk_root = os.environ["NDK_ROOT"] - if not os.path.isdir(ndk_root): - exit("Cannot find %s. Please install Android NDK and set NDK_ROOT." % (ndk_root)) + # Determine the NDK installation directory. + if os.environ.get('NDK_ROOT') or os.environ.get('ANDROID_NDK_ROOT'): + # We have an explicit setting from an environment variable. + ndk_root = os.environ.get('ANDROID_NDK_ROOT') + if not ndk_root or not os.path.isdir(ndk_root): + ndk_root = os.environ.get('NDK_ROOT') + if not ndk_root or not os.path.isdir(ndk_root): + exit("Cannot find %s. Please install Android NDK and set ANDROID_NDK_ROOT." % (ndk_root)) + else: + # Often, it's installed in the ndk-bundle subdirectory of the SDK. + ndk_root = os.path.join(sdk_root, 'ndk-bundle') + + if not os.path.isdir(os.path.join(ndk_root, 'toolchains')): + exit('Cannot find the Android NDK. Install it via the SDK manager or set the ANDROID_NDK_ROOT variable if you have installed it in a different location.') SDK["ANDROID_NDK"] = ndk_root # Determine the toolchain location. prebuilt_dir = os.path.join(ndk_root, 'toolchains', 'llvm', 'prebuilt') if not os.path.isdir(prebuilt_dir): - exit('Not found: %s' % (prebuilt_dir)) + exit('Not found: %s (is the Android NDK installed?)' % (prebuilt_dir)) host_tag = GetHost() + '-x86' if host_64: @@ -2527,7 +2545,24 @@ def SdkLocateAndroid(): # STL that ships with Android. support = os.path.join(ndk_root, 'sources', 'android', 'support', 'include') IncDirectory("ALWAYS", support.replace('\\', '/')) - LibName("ALWAYS", "-landroid_support") + if api < 21: + LibName("ALWAYS", "-landroid_support") + + # Determine the location of android.jar. + SDK["ANDROID_JAR"] = os.path.join(sdk_root, 'platforms', 'android-%s' % (api), 'android.jar') + + # Which build tools versions do we have? Pick the latest. + versions = [] + for version in os.listdir(os.path.join(sdk_root, "build-tools")): + match = re.match('([0-9]+)\\.([0-9]+)\\.([0-9]+)', version) + if match: + version_tuple = int(match.group(1)), int(match.group(2)), int(match.group(3)) + versions.append(version_tuple) + + versions.sort() + if versions: + version = versions[-1] + SDK["ANDROID_BUILD_TOOLS"] = os.path.join(sdk_root, "build-tools", "{0}.{1}.{2}".format(*version)) ######################################################################## ## @@ -2793,6 +2828,9 @@ def SetupBuildEnvironment(compiler): if GetTarget() == 'android' and GetHost() != 'android': AddToPathEnv("PATH", os.path.join(SDK["ANDROID_TOOLCHAIN"], "bin")) + if "ANDROID_BUILD_TOOLS" in SDK: + AddToPathEnv("PATH", SDK["ANDROID_BUILD_TOOLS"]) + if compiler == "MSVC": # Add the visual studio tools to PATH et al. SetupVisualStudioEnviron() @@ -2845,7 +2883,12 @@ def SetupBuildEnvironment(compiler): SYS_LIB_DIRS += [SDK.get("SYSROOT", "") + "/usr/lib"] # Now extract the preprocessor's include directories. - cmd = GetCXX() + sysroot_flag + " -x c++ -v -E /dev/null" + cmd = GetCXX() + " -x c++ -v -E " + os.devnull + if "ANDROID_NDK" in SDK: + cmd += " --sysroot=%s/sysroot" % (SDK["ANDROID_NDK"].replace('\\', '/')) + else: + cmd += sysroot_flag + null = open(os.devnull, 'w') handle = subprocess.Popen(cmd, stdout=null, stderr=subprocess.PIPE, shell=True) scanning = False @@ -2858,8 +2901,12 @@ def SetupBuildEnvironment(compiler): scanning = True continue - if not line.startswith(' /'): - continue + if sys.platform == "win32": + if not line.startswith(' '): + continue + else: + if not line.startswith(' /'): + continue line = line.strip() if line.endswith(" (framework directory)"): From eef2a931634c8c0f5c4295a9cf0d3efa6c4a586d Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 20 Jan 2019 15:59:08 +0100 Subject: [PATCH 046/144] makepanda: allow building for Android from Windows machine --- makepanda/makepackage.py | 37 ++++++++++++--------- makepanda/makepandacore.py | 68 +++++++++++++++++++++++++++++++++----- 2 files changed, 81 insertions(+), 24 deletions(-) diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py index c11651283a..9b34192e94 100755 --- a/makepanda/makepackage.py +++ b/makepanda/makepackage.py @@ -7,6 +7,7 @@ import os import shutil import glob import re +import subprocess INSTALLER_DEB_FILE = """ @@ -837,7 +838,8 @@ def MakeInstallerAndroid(version, **kwargs): # off any suffix (eg. libfile.so.1.0), as Android does not support them. source_dir = os.path.join(outputdir, "lib") target_dir = os.path.join("apkroot", "lib", SDK["ANDROID_ABI"]) - oscmd("mkdir -p %s" % (target_dir)) + if not os.path.exists(target_dir): + os.makedirs(target_dir, mode=0o755) # Determine the library directories we should look in. libpath = [source_dir] @@ -859,24 +861,26 @@ def MakeInstallerAndroid(version, **kwargs): # Already processed. return - oscmd("cp %s %s" % (source, target)) + shutil.copy(source, target) # Walk through the library dependencies. - oscmd("ldd %s | grep .so > %s/tmp/otool-libs.txt" % (target, outputdir), True) - for line in open(outputdir + "/tmp/otool-libs.txt", "r"): - line = line.strip() - if not line: + handle = subprocess.Popen(['readelf', '--dynamic', target], stdout=subprocess.PIPE) + for line in handle.communicate()[0].splitlines(): + # The line will look something like: + # 0x0000000000000001 (NEEDED) Shared library: [libpanda.so] + line = line.decode('utf-8', 'replace').strip() + if not line or '(NEEDED)' not in line or '[' not in line or ']' not in line: continue - if ' ' in line: - line = line.split(' ', 1)[0] + # Extract the part between square brackets. + idx = line.index('[') + dep = line[idx + 1 : line.index(']', idx)] # Change .so.1.2 suffix to .so, as needed for loading in .apk - if '.so.' in line: - dep = line.rpartition('.so.')[0] + '.so' - oscmd("patchelf --replace-needed %s %s %s" % (line, dep, target), True) - else: - dep = line + if '.so.' in dep: + orig_dep = dep + dep = dep.rpartition('.so.')[0] + '.so' + oscmd("patchelf --replace-needed %s %s %s" % (orig_dep, dep, target), True) # Find it on the LD_LIBRARY_PATH. for dir in libpath: @@ -969,11 +973,12 @@ def MakeInstallerAndroid(version, **kwargs): oscmd(aapt_cmd) # And add all the libraries to it. - oscmd("cd apkroot && aapt add ../%s classes.dex" % (apk_unaligned)) + oscmd("aapt add %s classes.dex" % (os.path.join('..', apk_unaligned)), cwd="apkroot") for path, dirs, files in os.walk('apkroot/lib'): if files: rel = os.path.relpath(path, 'apkroot') - oscmd("cd apkroot && aapt add ../%s %s/*" % (apk_unaligned, rel)) + rel_files = [os.path.join(rel, file).replace('\\', '/') for file in files] + oscmd("aapt add %s %s" % (os.path.join('..', apk_unaligned), ' '.join(rel_files)), cwd="apkroot") # Now align the .apk, which is necessary for Android to load it. oscmd("zipalign -v -p 4 %s %s" % (apk_unaligned, apk_unsigned)) @@ -984,7 +989,7 @@ def MakeInstallerAndroid(version, **kwargs): oscmd("apksigner debug.ks %s panda3d.apk" % (apk_unsigned)) else: if not os.path.isfile('debug.ks'): - oscmd("keytool -genkey -noprompt -dname 'CN=Panda3D,O=Panda3D,C=US' -keystore debug.ks -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 1000") + oscmd("keytool -genkey -noprompt -dname CN=Panda3D,O=Panda3D,C=US -keystore debug.ks -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 1000") oscmd("apksigner sign --ks debug.ks --ks-pass pass:android --min-sdk-version %s --out panda3d.apk %s" % (SDK["ANDROID_API"], apk_unsigned)) # Clean up. diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 6babeb7fd8..144d26f11a 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -564,11 +564,12 @@ def LocateBinary(binary): p = os.environ["PATH"] pathList = p.split(os.pathsep) + suffixes = [''] if GetHost() == 'windows': - if not binary.endswith('.exe'): + if not binary.lower().endswith('.exe') and not binary.lower().endswith('.bat'): # Append .exe if necessary - binary += '.exe' + suffixes = ['.exe', '.bat'] # On Windows the current directory is always implicitly # searched before anything else on PATH. @@ -576,8 +577,9 @@ def LocateBinary(binary): for path in pathList: binpath = os.path.join(os.path.expanduser(path), binary) - if os.access(binpath, os.X_OK): - return os.path.abspath(os.path.realpath(binpath)) + for suffix in suffixes: + if os.access(binpath + suffix, os.X_OK): + return os.path.abspath(os.path.realpath(binpath + suffix)) return None ######################################################################## @@ -586,20 +588,31 @@ def LocateBinary(binary): ## ######################################################################## -def oscmd(cmd, ignoreError = False): +def oscmd(cmd, ignoreError = False, cwd=None): if VERBOSE: print(GetColor("blue") + cmd.split(" ", 1)[0] + " " + GetColor("magenta") + cmd.split(" ", 1)[1] + GetColor()) sys.stdout.flush() if sys.platform == "win32": - exe = cmd.split()[0] + if cmd[0] == '"': + exe = cmd[1 : cmd.index('"', 1)] + else: + exe = cmd.split()[0] exe_path = LocateBinary(exe) if exe_path is None: exit("Cannot find "+exe+" on search path") + + if cwd is not None: + pwd = os.getcwd() + os.chdir(cwd) + res = os.spawnl(os.P_WAIT, exe_path, cmd) + + if cwd is not None: + os.chdir(pwd) else: cmd = cmd.replace(';', '\\;') - res = subprocess.call(cmd, shell=True) + res = subprocess.call(cmd, cwd=cwd, shell=True) sig = res & 0x7F if (GetVerbose() and res != 0): print(ColorText("red", "Process exited with exit status %d and signal code %d" % ((res & 0xFF00) >> 8, sig))) @@ -2468,9 +2481,15 @@ def SdkLocateAndroid(): SDK["ANDROID_JAR"] = prefix + "/share/aapt/android.jar" return + # Find the location of the Android SDK. sdk_root = os.environ.get('ANDROID_HOME') if not sdk_root or not os.path.isdir(sdk_root): sdk_root = os.environ.get('ANDROID_SDK_ROOT') + + # Try the default installation location on Windows. + if not sdk_root and GetHost() == 'windows': + sdk_root = os.path.expanduser(os.path.join('~', 'AppData', 'Local', 'Android', 'Sdk')) + if not sdk_root: exit('ANDROID_SDK_ROOT must be set when compiling for Android!') elif not os.path.isdir(sdk_root): @@ -2550,6 +2569,8 @@ def SdkLocateAndroid(): # Determine the location of android.jar. SDK["ANDROID_JAR"] = os.path.join(sdk_root, 'platforms', 'android-%s' % (api), 'android.jar') + if not os.path.isfile(SDK["ANDROID_JAR"]): + exit("Cannot find %s. Install platform API level %s via the SDK manager or change the targeted API level with --target=android-#" % (SDK["ANDROID_JAR"], api)) # Which build tools versions do we have? Pick the latest. versions = [] @@ -2564,6 +2585,24 @@ def SdkLocateAndroid(): version = versions[-1] SDK["ANDROID_BUILD_TOOLS"] = os.path.join(sdk_root, "build-tools", "{0}.{1}.{2}".format(*version)) + # And find the location of the Java compiler. + if GetHost() == "windows": + jdk_home = os.environ.get("JDK_HOME") or os.environ.get("JAVA_HOME") + if not jdk_home: + # Try to use the Java shipped with Android Studio. + studio_path = GetRegistryKey("SOFTWARE\\Android Studio", "Path", override64=False) + if studio_path and os.path.isdir(studio_path): + jdk_home = os.path.join(studio_path, "jre") + + if not jdk_home or not os.path.isdir(jdk_home): + exit("Cannot find JDK. Please set JDK_HOME or JAVA_HOME.") + + javac = os.path.join(jdk_home, "bin", "javac.exe") + if not os.path.isfile(javac): + exit("Cannot find %s. Install the JDK and set JDK_HOME or JAVA_HOME." % (javac)) + + SDK["JDK"] = jdk_home + ######################################################################## ## ## SDK Auto-Disables @@ -2831,6 +2870,10 @@ def SetupBuildEnvironment(compiler): if "ANDROID_BUILD_TOOLS" in SDK: AddToPathEnv("PATH", SDK["ANDROID_BUILD_TOOLS"]) + if "JDK" in SDK: + AddToPathEnv("PATH", os.path.join(SDK["JDK"], "bin")) + os.environ["JAVA_HOME"] = SDK["JDK"] + if compiler == "MSVC": # Add the visual studio tools to PATH et al. SetupVisualStudioEnviron() @@ -2882,10 +2925,19 @@ def SetupBuildEnvironment(compiler): Warn("%s failed" % (cmd)) SYS_LIB_DIRS += [SDK.get("SYSROOT", "") + "/usr/lib"] + # The Android toolchain on Windows doesn't actually add this one. + if target == 'android' and GetHost() == 'windows': + libdir = SDK.get("SYSROOT", "") + "/usr/lib" + if GetTargetArch() == 'x86_64': + libdir += '64' + SYS_LIB_DIRS += [libdir] + # Now extract the preprocessor's include directories. cmd = GetCXX() + " -x c++ -v -E " + os.devnull if "ANDROID_NDK" in SDK: - cmd += " --sysroot=%s/sysroot" % (SDK["ANDROID_NDK"].replace('\\', '/')) + ndk_dir = SDK["ANDROID_NDK"].replace('\\', '/') + cmd += ' -isystem %s/sysroot/usr/include' % (ndk_dir) + cmd += ' -isystem %s/sysroot/usr/include/%s' % (ndk_dir, SDK["ANDROID_TRIPLE"]) else: cmd += sysroot_flag From 66655aae856f96437184e058a52b1b4a9e1b24a2 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 21 Jan 2019 15:31:54 +0100 Subject: [PATCH 047/144] device: fix incorrect features when printing InputDevice --- panda/src/device/inputDevice.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/panda/src/device/inputDevice.cxx b/panda/src/device/inputDevice.cxx index 130854834e..cce2f975b4 100644 --- a/panda/src/device/inputDevice.cxx +++ b/panda/src/device/inputDevice.cxx @@ -404,19 +404,19 @@ output(std::ostream &out) const { << (_axes.size() != 1 ? 'e' : 'i') << 's'; } - if (_features & (unsigned int)Feature::pointer) { + if (_features & (1 << (unsigned int)Feature::pointer)) { out << ", pointer"; } - if (_features & (unsigned int)Feature::keyboard) { + if (_features & (1 << (unsigned int)Feature::keyboard)) { out << ", keyboard"; } - if (_features & (unsigned int)Feature::tracker) { + if (_features & (1 << (unsigned int)Feature::tracker)) { out << ", tracker"; } - if (_features & (unsigned int)Feature::vibration) { + if (_features & (1 << (unsigned int)Feature::vibration)) { out << ", vibration"; } - if (_features & (unsigned int)Feature::battery) { + if (_features & (1 << (unsigned int)Feature::battery)) { out << ", battery"; if (_battery_data.level > 0 && _battery_data.max_level > 0) { From 9d12a4c43716d3ac0c1e53ced1e0fd847cbafd81 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 23 Jan 2019 22:24:02 +0100 Subject: [PATCH 048/144] general: improvements to doxygen API reference: * In C++ reference, only pick up classes defined in .h file * Add a few excludes to C++ reference that aren't public API * On class index pages, reduce number of columns * Add @since for some methods/classes that are new in 1.10.0 * Fix/improve a few docstrings here and there --- direct/src/directscripts/Doxyfile.cxx | 18 ++++++++++--- direct/src/directscripts/Doxyfile.python | 2 +- panda/src/device/evdevInputDevice.h | 2 ++ panda/src/device/inputDevice.h | 2 ++ panda/src/device/inputDeviceManager.h | 2 ++ panda/src/device/linuxJoystickDevice.h | 2 ++ panda/src/device/winRawInputDevice.h | 2 ++ panda/src/device/xInputDevice.h | 2 ++ panda/src/egg/eggMaterial.I | 32 ++++++++++++----------- panda/src/event/asyncFuture.h | 2 ++ panda/src/express/weakPointerTo.I | 9 ++++++- panda/src/express/weakPointerToBase.I | 2 +- panda/src/express/weakReferenceList.I | 6 +++++ panda/src/express/weakReferenceList.cxx | 6 +++++ panda/src/gobj/geom.I | 2 ++ panda/src/gobj/geom.cxx | 2 ++ panda/src/gobj/geomLinesAdjacency.h | 2 ++ panda/src/gobj/geomLinestripsAdjacency.h | 4 ++- panda/src/gobj/geomPrimitive.cxx | 2 ++ panda/src/gobj/geomTrianglesAdjacency.h | 2 ++ panda/src/gobj/geomTristripsAdjacency.h | 4 ++- panda/src/gobj/shaderBuffer.h | 2 ++ panda/src/gobj/texture.I | 4 +++ panda/src/movies/flacAudio.h | 2 ++ panda/src/movies/flacAudioCursor.h | 6 +++-- panda/src/movies/opusAudio.h | 2 ++ panda/src/movies/opusAudioCursor.h | 3 +++ panda/src/pgraph/light.I | 4 +++ panda/src/pgraph/light.cxx | 2 ++ panda/src/pgraph/logicOpAttrib.h | 2 ++ panda/src/pgraphnodes/rectangleLight.h | 2 ++ panda/src/pgraphnodes/shaderGenerator.cxx | 4 +++ panda/src/pgraphnodes/sphereLight.h | 2 ++ panda/src/text/textProperties.I | 8 +++++- 34 files changed, 123 insertions(+), 27 deletions(-) diff --git a/direct/src/directscripts/Doxyfile.cxx b/direct/src/directscripts/Doxyfile.cxx index 6c81025960..db71c81b3b 100644 --- a/direct/src/directscripts/Doxyfile.cxx +++ b/direct/src/directscripts/Doxyfile.cxx @@ -432,7 +432,7 @@ EXTRACT_STATIC = NO # for Java sources. # The default value is: YES. -EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local methods, # which are defined in the implementation section but not in the interface are @@ -802,6 +802,11 @@ EXCLUDE = dtool/src/parser-inc \ panda/src/iphone \ panda/src/tinydisplay \ panda/src/movies/dr_flac.h \ + panda/src/windisplay/winDetectDx.h \ + panda/src/wgldisplay/wglext.h \ + panda/src/glxdisplay/panda_glxext.h \ + pandatool/src/gtk-stats \ + dtool/src/dtoolbase/fakestringstream.h \ dtool/src/dtoolbase/pdtoa.cxx \ dtool/src/dtoolutil/panda_getopt_long.h \ dtool/src/dtoolutil/panda_getopt_impl.h \ @@ -840,7 +845,10 @@ EXCLUDE_PATTERNS = */Opt*-*/* \ # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = InterrogateFunctionWrapper::Parameter \ + CollisionFloorMesh::TriangleIndices \ + tagTOUCHINPUT \ + WINDOW_METRICS # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include @@ -1018,7 +1026,7 @@ ALPHABETICAL_INDEX = YES # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -COLS_IN_ALPHA_INDEX = 5 +COLS_IN_ALPHA_INDEX = 3 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag @@ -1972,6 +1980,7 @@ INCLUDE_FILE_PATTERNS = PREDEFINED = TVOLATILE= \ INLINE=inline \ + ALWAYS_INLINE=inline \ PUBLISHED=public \ protected=private \ INLINE_LINMATH=inline \ @@ -1986,7 +1995,8 @@ PREDEFINED = TVOLATILE= \ MAKE_SEQ(x)= \ MAKE_SEQ_PROPERTY(x)= \ MAKE_MAP_PROPERTY(x)= \ - MAKE_MAP_KEYS_SEQ(x)= + MAKE_MAP_KEYS_SEQ(x)= \ + RETURNS_ALIGNED(x)= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/direct/src/directscripts/Doxyfile.python b/direct/src/directscripts/Doxyfile.python index 2119f7b321..170c3917c1 100644 --- a/direct/src/directscripts/Doxyfile.python +++ b/direct/src/directscripts/Doxyfile.python @@ -805,7 +805,7 @@ ALPHABETICAL_INDEX = YES # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) -COLS_IN_ALPHA_INDEX = 5 +COLS_IN_ALPHA_INDEX = 2 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. diff --git a/panda/src/device/evdevInputDevice.h b/panda/src/device/evdevInputDevice.h index ffc3503ff0..ce9e152cdc 100644 --- a/panda/src/device/evdevInputDevice.h +++ b/panda/src/device/evdevInputDevice.h @@ -24,6 +24,8 @@ class LinuxInputDeviceManager; * This is a type of device that uses the Linux /dev/input/event# API to read * data from a raw mouse or other input device. Unlike the joystick API, the * evdev API supports sending force feedback (ie. rumble) events. + * + * @since 1.10.0 */ class EXPCL_PANDA_DEVICE EvdevInputDevice : public InputDevice { public: diff --git a/panda/src/device/inputDevice.h b/panda/src/device/inputDevice.h index 3e4e37313e..f3f500e378 100644 --- a/panda/src/device/inputDevice.h +++ b/panda/src/device/inputDevice.h @@ -47,6 +47,8 @@ * There is the DeviceType enumeration, however, which will (if known) contain * identification of the general category of devices this fits in, such as * keyboard, mouse, gamepad, or flight stick. + * + * @since 1.10.0 */ class EXPCL_PANDA_DEVICE InputDevice : public TypedReferenceCount { PUBLISHED: diff --git a/panda/src/device/inputDeviceManager.h b/panda/src/device/inputDeviceManager.h index 7fd69b804e..66381c79e0 100644 --- a/panda/src/device/inputDeviceManager.h +++ b/panda/src/device/inputDeviceManager.h @@ -27,6 +27,8 @@ class WinRawInputDevice; /** * This class keeps track of all the devices on a system, and sends out events * when a device has been hot-plugged. + * + * @since 1.10.0 */ class EXPCL_PANDA_DEVICE InputDeviceManager { protected: diff --git a/panda/src/device/linuxJoystickDevice.h b/panda/src/device/linuxJoystickDevice.h index 61d05cd3e8..cf56e27b58 100644 --- a/panda/src/device/linuxJoystickDevice.h +++ b/panda/src/device/linuxJoystickDevice.h @@ -23,6 +23,8 @@ class LinuxInputDeviceManager; /** * This is a type of device that uses the Linux /dev/input/js# API to read * data from a game controller. + * + * @since 1.10.0 */ class EXPCL_PANDA_DEVICE LinuxJoystickDevice : public InputDevice { PUBLISHED: diff --git a/panda/src/device/winRawInputDevice.h b/panda/src/device/winRawInputDevice.h index ce4fe9a19c..bea8066b85 100644 --- a/panda/src/device/winRawInputDevice.h +++ b/panda/src/device/winRawInputDevice.h @@ -25,6 +25,8 @@ class WinInputDeviceManager; /** * This implementation of InputDevice uses the Win32 raw input API and the HID * parser library to support a wide range of devices. + * + * @since 1.10.0 */ class EXPCL_PANDA_DEVICE WinRawInputDevice final : public InputDevice { public: diff --git a/panda/src/device/xInputDevice.h b/panda/src/device/xInputDevice.h index 0bf3900ec4..2088c19182 100644 --- a/panda/src/device/xInputDevice.h +++ b/panda/src/device/xInputDevice.h @@ -31,6 +31,8 @@ typedef struct tagRID_DEVICE_INFO RID_DEVICE_INFO; /** * This implementation of InputDevice uses Microsoft's XInput library to * interface with an Xbox 360 game controller. + * + * @since 1.10.0 */ class EXPCL_PANDA_DEVICE XInputDevice final : public InputDevice { public: diff --git a/panda/src/egg/eggMaterial.I b/panda/src/egg/eggMaterial.I index f12a50c00d..7c49c2bd98 100644 --- a/panda/src/egg/eggMaterial.I +++ b/panda/src/egg/eggMaterial.I @@ -12,7 +12,7 @@ */ /** - * + * @since 1.10.0 */ INLINE void EggMaterial:: set_base(const LColor &base) { @@ -21,7 +21,7 @@ set_base(const LColor &base) { } /** - * + * @since 1.10.0 */ INLINE void EggMaterial:: clear_base() { @@ -29,7 +29,7 @@ clear_base() { } /** - * + * @since 1.10.0 */ INLINE bool EggMaterial:: has_base() const { @@ -39,6 +39,8 @@ has_base() const { /** * It is legal to call this even if has_base() returns false. If so, it * simply returns the default base color. + * + * @since 1.10.0 */ INLINE LColor EggMaterial:: get_base() const { @@ -239,7 +241,7 @@ get_shininess() const { } /** - * + * @since 1.10.0 */ INLINE void EggMaterial:: set_roughness(double roughness) { @@ -248,7 +250,7 @@ set_roughness(double roughness) { } /** - * + * @since 1.10.0 */ INLINE void EggMaterial:: clear_roughness() { @@ -256,7 +258,7 @@ clear_roughness() { } /** - * + * @since 1.10.0 */ INLINE bool EggMaterial:: has_roughness() const { @@ -264,7 +266,7 @@ has_roughness() const { } /** - * + * @since 1.10.0 */ INLINE double EggMaterial:: get_roughness() const { @@ -276,7 +278,7 @@ get_roughness() const { } /** - * + * @since 1.10.0 */ INLINE void EggMaterial:: set_metallic(double metallic) { @@ -285,7 +287,7 @@ set_metallic(double metallic) { } /** - * + * @since 1.10.0 */ INLINE void EggMaterial:: clear_metallic() { @@ -293,7 +295,7 @@ clear_metallic() { } /** - * + * @since 1.10.0 */ INLINE bool EggMaterial:: has_metallic() const { @@ -301,7 +303,7 @@ has_metallic() const { } /** - * + * @since 1.10.0 */ INLINE double EggMaterial:: get_metallic() const { @@ -313,7 +315,7 @@ get_metallic() const { } /** - * + * @since 1.10.0 */ INLINE void EggMaterial:: set_ior(double ior) { @@ -322,7 +324,7 @@ set_ior(double ior) { } /** - * + * @since 1.10.0 */ INLINE void EggMaterial:: clear_ior() { @@ -330,7 +332,7 @@ clear_ior() { } /** - * + * @since 1.10.0 */ INLINE bool EggMaterial:: has_ior() const { @@ -338,7 +340,7 @@ has_ior() const { } /** - * + * @since 1.10.0 */ INLINE double EggMaterial:: get_ior() const { diff --git a/panda/src/event/asyncFuture.h b/panda/src/event/asyncFuture.h index 27cab7b585..c12bccb7d0 100644 --- a/panda/src/event/asyncFuture.h +++ b/panda/src/event/asyncFuture.h @@ -55,6 +55,8 @@ class ConditionVarFull; * coroutine, which only suspends the current task and not the entire thread. * * This API aims to mirror and be compatible with Python's Future class. + * + * @since 1.10.0 */ class EXPCL_PANDA_EVENT AsyncFuture : public TypedReferenceCount { PUBLISHED: diff --git a/panda/src/express/weakPointerTo.I b/panda/src/express/weakPointerTo.I index 8d60057c31..316fe8ca71 100644 --- a/panda/src/express/weakPointerTo.I +++ b/panda/src/express/weakPointerTo.I @@ -118,9 +118,11 @@ operator T * () const { /** * A thread-safe way to access the underlying pointer; will silently return * null if the underlying pointer was deleted or null. - * Note that this may return null even if was_deleted() still returns true, + * Note that this may return null even if was_deleted() still returns false, * which can occur if the object has reached reference count 0 and is about to * be destroyed. + * + * @since 1.10.0 */ template INLINE PointerTo WeakPointerTo:: @@ -397,6 +399,11 @@ operator const T * () const { /** * A thread-safe way to access the underlying pointer; will silently return * null if the underlying pointer was deleted or null. + * Note that this may return null even if was_deleted() still returns false, + * which can occur if the object has reached reference count 0 and is about to + * be destroyed. + * + * @since 1.10.0 */ template INLINE ConstPointerTo WeakConstPointerTo:: diff --git a/panda/src/express/weakPointerToBase.I b/panda/src/express/weakPointerToBase.I index 5673114764..3b27047da1 100644 --- a/panda/src/express/weakPointerToBase.I +++ b/panda/src/express/weakPointerToBase.I @@ -290,7 +290,7 @@ update_type(To *ptr) { * A thread-safe way to access the underlying pointer; will only write to the * given pointer if the underlying pointer has not yet been deleted and is not * null. Note that it may leave the pointer unassigned even if was_deleted() - * still returns true, which can occur if the object has reached reference + * still returns false, which can occur if the object has reached reference * count 0 and is about to be destroyed. */ template diff --git a/panda/src/express/weakReferenceList.I b/panda/src/express/weakReferenceList.I index 0e4efc8c52..eb6e7b9976 100644 --- a/panda/src/express/weakReferenceList.I +++ b/panda/src/express/weakReferenceList.I @@ -13,6 +13,8 @@ /** * Increases the number of weak references. + * + * @since 1.10.0 */ INLINE void WeakReferenceList:: ref() const { @@ -23,6 +25,8 @@ ref() const { * Decreases the number of weak references. Returns true if, after this, * there are still any weak or strong references remaining, or false if this * structure should be deleted right away. + * + * @since 1.10.0 */ INLINE bool WeakReferenceList:: unref() const { @@ -32,6 +36,8 @@ unref() const { /** * Returns true if the object represented has been deleted, ie. there are only * weak references left pointing to the object. + * + * @since 1.10.0 */ INLINE bool WeakReferenceList:: was_deleted() const { diff --git a/panda/src/express/weakReferenceList.cxx b/panda/src/express/weakReferenceList.cxx index 0534556d7a..ac1363c85a 100644 --- a/panda/src/express/weakReferenceList.cxx +++ b/panda/src/express/weakReferenceList.cxx @@ -37,6 +37,8 @@ WeakReferenceList:: * * The data pointer can be an arbitrary pointer and is passed as only argument * to the callback. + * + * @since 1.10.0 */ void WeakReferenceList:: add_callback(WeakPointerCallback *callback, void *data) { @@ -61,6 +63,8 @@ add_callback(WeakPointerCallback *callback, void *data) { * weak reference-counting pointer), this removes the indicated PointerToVoid * structure from the list of such structures that are maintaining a weak * pointer to this object. + * + * @since 1.10.0 */ void WeakReferenceList:: remove_callback(WeakPointerCallback *callback) { @@ -73,6 +77,8 @@ remove_callback(WeakPointerCallback *callback) { /** * Called only by the ReferenceCount pointer to indicate that it has been * deleted. + * + * @since 1.10.0 */ void WeakReferenceList:: mark_deleted() { diff --git a/panda/src/gobj/geom.I b/panda/src/gobj/geom.I index 94469ec77c..3fa32ade36 100644 --- a/panda/src/gobj/geom.I +++ b/panda/src/gobj/geom.I @@ -215,6 +215,8 @@ make_patches() const { /** * Returns a new Geom with each primitive converted into a corresponding * version with adjacency information. + * + * @since 1.10.0 */ INLINE PT(Geom) Geom:: make_adjacency() const { diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 3b6dee026a..4fc2b8ceb2 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -892,6 +892,8 @@ make_patches_in_place() { * * Don't call this in a downstream thread unless you don't mind it blowing * away other changes you might have recently made in an upstream thread. + * + * @since 1.10.0 */ void Geom:: make_adjacency_in_place() { diff --git a/panda/src/gobj/geomLinesAdjacency.h b/panda/src/gobj/geomLinesAdjacency.h index 884875cb39..7202d324e6 100644 --- a/panda/src/gobj/geomLinesAdjacency.h +++ b/panda/src/gobj/geomLinesAdjacency.h @@ -20,6 +20,8 @@ /** * Defines a series of disconnected line segments with adjacency information, * for use with geometry shaders. + * + * @since 1.10.0 */ class EXPCL_PANDA_GOBJ GeomLinesAdjacency : public GeomPrimitive { PUBLISHED: diff --git a/panda/src/gobj/geomLinestripsAdjacency.h b/panda/src/gobj/geomLinestripsAdjacency.h index baf3d19255..16753c302a 100644 --- a/panda/src/gobj/geomLinestripsAdjacency.h +++ b/panda/src/gobj/geomLinestripsAdjacency.h @@ -18,7 +18,9 @@ #include "geomPrimitive.h" /** - * Defines a series of line strips. + * Defines a series of line strips with adjacency information. + * + * @since 1.10.0 */ class EXPCL_PANDA_GOBJ GeomLinestripsAdjacency : public GeomPrimitive { PUBLISHED: diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index 6fa66329ba..afa406e921 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -1038,6 +1038,8 @@ make_patches() const { /** * Adds adjacency information to this primitive. May return null if this type * of geometry does not support adjacency information. + * + * @since 1.10.0 */ CPT(GeomPrimitive) GeomPrimitive:: make_adjacency() const { diff --git a/panda/src/gobj/geomTrianglesAdjacency.h b/panda/src/gobj/geomTrianglesAdjacency.h index 6ebdbdc6eb..90f3811b06 100644 --- a/panda/src/gobj/geomTrianglesAdjacency.h +++ b/panda/src/gobj/geomTrianglesAdjacency.h @@ -19,6 +19,8 @@ /** * Defines a series of disconnected triangles, with adjacency information. + * + * @since 1.10.0 */ class EXPCL_PANDA_GOBJ GeomTrianglesAdjacency : public GeomPrimitive { PUBLISHED: diff --git a/panda/src/gobj/geomTristripsAdjacency.h b/panda/src/gobj/geomTristripsAdjacency.h index 7811079401..896233c6ee 100644 --- a/panda/src/gobj/geomTristripsAdjacency.h +++ b/panda/src/gobj/geomTristripsAdjacency.h @@ -18,7 +18,9 @@ #include "geomPrimitive.h" /** - * Defines a series of triangle strips. + * Defines a series of triangle strips with adjacency information. + * + * @since 1.10.0 */ class EXPCL_PANDA_GOBJ GeomTristripsAdjacency : public GeomPrimitive { PUBLISHED: diff --git a/panda/src/gobj/shaderBuffer.h b/panda/src/gobj/shaderBuffer.h index 0cc0660433..d523e13256 100644 --- a/panda/src/gobj/shaderBuffer.h +++ b/panda/src/gobj/shaderBuffer.h @@ -27,6 +27,8 @@ class PreparedGraphicsObjects; /** * This is a generic buffer object that lives in graphics memory. + * + * @since 1.10.0 */ class EXPCL_PANDA_GOBJ ShaderBuffer : public TypedWritableReferenceCount, public Namable, public GeomEnums { private: diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index 7d859dbda8..ce3aa6cffe 100644 --- a/panda/src/gobj/texture.I +++ b/panda/src/gobj/texture.I @@ -175,6 +175,8 @@ setup_cube_map(int size, ComponentType component_type, Format format) { * is not the same as the z_size. Follow up with read() or load() to fill the * texture properties and image data, or use set_clear_color to let the * texture be cleared to a solid color. + * + * @since 1.10.0 */ INLINE void Texture:: setup_cube_map_array(int num_cube_maps) { @@ -189,6 +191,8 @@ setup_cube_map_array(int num_cube_maps) { * * The num_cube_maps given here is multiplied by six to become the z_size of * the image. + * + * @since 1.10.0 */ INLINE void Texture:: setup_cube_map_array(int size, int num_cube_maps, ComponentType component_type, Format format) { diff --git a/panda/src/movies/flacAudio.h b/panda/src/movies/flacAudio.h index 4fb9818930..5309e95eae 100644 --- a/panda/src/movies/flacAudio.h +++ b/panda/src/movies/flacAudio.h @@ -21,6 +21,8 @@ class FlacAudioCursor; /** * Reads FLAC audio files. Ogg-encapsulated FLAC files are not supported. + * + * @since 1.10.0 */ class EXPCL_PANDA_MOVIES FlacAudio : public MovieAudio { PUBLISHED: diff --git a/panda/src/movies/flacAudioCursor.h b/panda/src/movies/flacAudioCursor.h index 1de46bad01..995be42e1e 100644 --- a/panda/src/movies/flacAudioCursor.h +++ b/panda/src/movies/flacAudioCursor.h @@ -25,8 +25,10 @@ extern "C" { class FlacAudio; /** - * Interfaces with the libvorbisfile library to implement decoding of Ogg - * Vorbis audio files. + * Implements decoding of FLAC audio files. + * + * @see FlacAudio + * @since 1.10.0 */ class EXPCL_PANDA_MOVIES FlacAudioCursor : public MovieAudioCursor { PUBLISHED: diff --git a/panda/src/movies/opusAudio.h b/panda/src/movies/opusAudio.h index 813a4dbd58..3de8fb8535 100644 --- a/panda/src/movies/opusAudio.h +++ b/panda/src/movies/opusAudio.h @@ -24,6 +24,8 @@ class OpusAudioCursor; /** * Interfaces with the libopusfile library to implement decoding of Opus * audio files. + * + * @since 1.10.0 */ class EXPCL_PANDA_MOVIES OpusAudio : public MovieAudio { PUBLISHED: diff --git a/panda/src/movies/opusAudioCursor.h b/panda/src/movies/opusAudioCursor.h index 1a3dfa035b..b3996c73bb 100644 --- a/panda/src/movies/opusAudioCursor.h +++ b/panda/src/movies/opusAudioCursor.h @@ -28,6 +28,9 @@ class OpusAudio; /** * Interfaces with the libopusfile library to implement decoding of Opus * audio files. + * + * @see OpusAudio + * @since 1.10.0 */ class EXPCL_PANDA_MOVIES OpusAudioCursor : public MovieAudioCursor { PUBLISHED: diff --git a/panda/src/pgraph/light.I b/panda/src/pgraph/light.I index 4b84c409aa..6dd0428836 100644 --- a/panda/src/pgraph/light.I +++ b/panda/src/pgraph/light.I @@ -78,6 +78,8 @@ set_color(const LColor &color) { /** * Returns true if the color was specified as a temperature in kelvins, and * get_color_temperature is defined. + * + * @since 1.10.0 */ INLINE bool Light:: has_color_temperature() const { @@ -87,6 +89,8 @@ has_color_temperature() const { /** * Returns the basic color temperature of the light, assuming * has_color_temperature() returns true. + * + * @since 1.10.0 */ INLINE PN_stdfloat Light:: get_color_temperature() const { diff --git a/panda/src/pgraph/light.cxx b/panda/src/pgraph/light.cxx index 82b53f5757..8631cb5b0b 100644 --- a/panda/src/pgraph/light.cxx +++ b/panda/src/pgraph/light.cxx @@ -70,6 +70,8 @@ is_ambient_light() const { * * The default value is 6500 K, corresponding to a perfectly white light * assuming a D65 white point. + * + * @since 1.10.0 */ void Light:: set_color_temperature(PN_stdfloat temperature) { diff --git a/panda/src/pgraph/logicOpAttrib.h b/panda/src/pgraph/logicOpAttrib.h index f5bd2ce5d9..7d6b0f5b6e 100644 --- a/panda/src/pgraph/logicOpAttrib.h +++ b/panda/src/pgraph/logicOpAttrib.h @@ -24,6 +24,8 @@ class FactoryParams; * If enabled, specifies that a custom logical operation be performed instead * of any color blending. Setting it to a value other than M_none will cause * color blending to be disabled and the given logic operation to be performed. + * + * @since 1.10.0 */ class EXPCL_PANDA_PGRAPH LogicOpAttrib : public RenderAttrib { PUBLISHED: diff --git a/panda/src/pgraphnodes/rectangleLight.h b/panda/src/pgraphnodes/rectangleLight.h index 9fafe875d6..770f7f7d0d 100644 --- a/panda/src/pgraphnodes/rectangleLight.h +++ b/panda/src/pgraphnodes/rectangleLight.h @@ -22,6 +22,8 @@ /** * This is a type of area light that is an axis aligned rectangle, pointing * along the Y axis in the positive direction. + * + * @since 1.10.0 */ class EXPCL_PANDA_PGRAPHNODES RectangleLight : public LightLensNode { PUBLISHED: diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index 16a7483478..d00022984f 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -573,6 +573,8 @@ analyze_renderstate(ShaderKey &key, const RenderState *rs) { * Call this if certain state has changed in such a way as to require a rerun * of the shader generator. This should be rare because in most cases, the * shader generator will automatically regenerate shaders as necessary. + * + * @since 1.10.0 */ void ShaderGenerator:: rehash_generated_shaders() { @@ -614,6 +616,8 @@ rehash_generated_shaders() { /** * Removes all previously generated shaders, requiring all shaders to be * regenerated. Does not clear cache of compiled shaders. + * + * @since 1.10.0 */ void ShaderGenerator:: clear_generated_shaders() { diff --git a/panda/src/pgraphnodes/sphereLight.h b/panda/src/pgraphnodes/sphereLight.h index d4b1fb1c32..3717764b77 100644 --- a/panda/src/pgraphnodes/sphereLight.h +++ b/panda/src/pgraphnodes/sphereLight.h @@ -22,6 +22,8 @@ /** * A sphere light is like a point light, except that it represents a sphere * with a radius, rather than being an infinitely thin point in space. + * + * @since 1.10.0 */ class EXPCL_PANDA_PGRAPHNODES SphereLight : public PointLight { PUBLISHED: diff --git a/panda/src/text/textProperties.I b/panda/src/text/textProperties.I index 09bfc78dad..d56c354d46 100644 --- a/panda/src/text/textProperties.I +++ b/panda/src/text/textProperties.I @@ -801,6 +801,8 @@ get_text_scale() const { /** * Specifies the text direction. If none is specified, it will be guessed * based on the contents of the string. + * + * @since 1.10.0 */ INLINE void TextProperties:: set_direction(Direction direction) { @@ -811,6 +813,8 @@ set_direction(Direction direction) { /** * Clears the text direction setting. If no text direction is specified, it * will be guessed based on the contents of the string. + * + * @since 1.10.0 */ INLINE void TextProperties:: clear_direction() { @@ -819,7 +823,7 @@ clear_direction() { } /** - * + * @since 1.10.0 */ INLINE bool TextProperties:: has_direction() const { @@ -828,6 +832,8 @@ has_direction() const { /** * Returns the direction of the text as specified by set_direction(). + * + * @since 1.10.0 */ INLINE TextProperties::Direction TextProperties:: get_direction() const { From 3cc9e49469e58ba9812066940af2ca316e6d0134 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 23 Jan 2019 22:55:38 +0100 Subject: [PATCH 049/144] installpanda: fix issues installing includes to existing dir --- makepanda/installpanda.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/makepanda/installpanda.py b/makepanda/installpanda.py index 7f9b79cd60..0b82fa11bd 100644 --- a/makepanda/installpanda.py +++ b/makepanda/installpanda.py @@ -157,6 +157,7 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built", libdir=GetLibDir( # Create the directory structure that we will be putting our files in. oscmd("mkdir -m 0755 -p "+destdir+prefix+"/bin") oscmd("mkdir -m 0755 -p "+destdir+prefix+"/include") + oscmd("mkdir -m 0755 -p "+destdir+prefix+"/include/panda3d") oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/panda3d") oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/mime-info") oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/mime/packages") @@ -184,7 +185,7 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built", libdir=GetLibDir( WriteFile(destdir+"/etc/Config.prc", Configrc) oscmd("cp "+outputdir+"/etc/Confauto.prc "+destdir+"/etc/Confauto.prc") - oscmd("cp -R "+outputdir+"/include "+destdir+prefix+"/include/panda3d") + oscmd("cp -R "+outputdir+"/include/* "+destdir+prefix+"/include/panda3d/") oscmd("cp -R "+outputdir+"/pandac "+destdir+prefix+"/share/panda3d/") oscmd("cp -R "+outputdir+"/models "+destdir+prefix+"/share/panda3d/") if os.path.isdir("samples"): oscmd("cp -R samples "+destdir+prefix+"/share/panda3d/") @@ -237,8 +238,8 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built", libdir=GetLibDir( DeleteEmptyDirs(destdir+prefix+"/include/panda3d") # Change permissions on include directory. - os.chmod(destdir + prefix + "/include", 0o755) - for root, dirs, files in os.walk(destdir + prefix + "/include"): + os.chmod(destdir + prefix + "/include/panda3d", 0o755) + for root, dirs, files in os.walk(destdir + prefix + "/include/panda3d"): for basename in dirs: os.chmod(os.path.join(root, basename), 0o755) for basename in files: From 0b087ecf92b5f59a8e32a5968a44c4dd3997d049 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 23 Jan 2019 23:18:51 +0100 Subject: [PATCH 050/144] installpanda: create intermediate directories with mode 0755 too Fixes #541 --- makepanda/installpanda.py | 32 ++++++++++++++++++-------------- makepanda/makepandacore.py | 16 +++++++++++++--- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/makepanda/installpanda.py b/makepanda/installpanda.py index 0b82fa11bd..ef8ddeab7e 100644 --- a/makepanda/installpanda.py +++ b/makepanda/installpanda.py @@ -155,25 +155,29 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built", libdir=GetLibDir( libdir = prefix + "/" + libdir # Create the directory structure that we will be putting our files in. - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/bin") - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/include") - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/include/panda3d") - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/panda3d") - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/mime-info") - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/mime/packages") - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/application-registry") - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/applications") - oscmd("mkdir -m 0755 -p "+destdir+libdir+"/panda3d") + # Don't use os.makedirs or mkdir -p; neither properly set permissions for + # created intermediate directories. + MakeDirectory(destdir+prefix+"/bin", mode=0o755, recursive=True) + MakeDirectory(destdir+prefix+"/include", mode=0o755) + MakeDirectory(destdir+prefix+"/include/panda3d", mode=0o755) + MakeDirectory(destdir+prefix+"/share", mode=0o755) + MakeDirectory(destdir+prefix+"/share/panda3d", mode=0o755) + MakeDirectory(destdir+prefix+"/share/mime-info", mode=0o755) + MakeDirectory(destdir+prefix+"/share/mime", mode=0o755) + MakeDirectory(destdir+prefix+"/share/mime/packages", mode=0o755) + MakeDirectory(destdir+prefix+"/share/application-registry", mode=0o755) + MakeDirectory(destdir+prefix+"/share/applications", mode=0o755) + MakeDirectory(destdir+libdir+"/panda3d", mode=0o755, recursive=True) for python_version in python_versions: - oscmd("mkdir -m 0755 -p "+destdir+python_version["purelib"]) - oscmd("mkdir -m 0755 -p "+destdir+python_version["platlib"]+"/panda3d") + MakeDirectory(destdir+python_version["purelib"], mode=0o755, recursive=True) + MakeDirectory(destdir+python_version["platlib"]+"/panda3d", mode=0o755, recursive=True) if (sys.platform.startswith("freebsd")): - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/etc") - oscmd("mkdir -m 0755 -p "+destdir+"/usr/local/libdata/ldconfig") + MakeDirectory(destdir+prefix+"/etc", mode=0o755) + MakeDirectory(destdir+"/usr/local/libdata/ldconfig", mode=0o755, recursive=True) else: - oscmd("mkdir -m 0755 -p "+destdir+"/etc/ld.so.conf.d") + MakeDirectory(destdir+"/etc/ld.so.conf.d", mode=0o755, recursive=True) # Write the Config.prc file. Configrc = ReadFile(outputdir+"/etc/Config.prc") diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 144d26f11a..74ce108adf 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -1104,9 +1104,19 @@ def GetOptimizeOption(opts): ## ######################################################################## -def MakeDirectory(path): - if os.path.isdir(path): return 0 - os.mkdir(path) +def MakeDirectory(path, mode=None, recursive=False): + if os.path.isdir(path): + return + + if recursive: + parent = os.path.dirname(path) + if parent and not os.path.isdir(parent): + MakeDirectory(parent, mode=mode, recursive=True) + + if mode is not None: + os.mkdir(path, mode) + else: + os.mkdir(path) def ReadFile(wfile): try: From 403e56817a03123e8a7f3c64868d73a962cb52f9 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 26 Jan 2019 19:22:44 +0100 Subject: [PATCH 051/144] dtoolbase: fix x86 compilation error on Android --- dtool/src/dtoolbase/atomicAdjustI386Impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtool/src/dtoolbase/atomicAdjustI386Impl.h b/dtool/src/dtoolbase/atomicAdjustI386Impl.h index bcd1a62c61..4daa335b2a 100644 --- a/dtool/src/dtoolbase/atomicAdjustI386Impl.h +++ b/dtool/src/dtoolbase/atomicAdjustI386Impl.h @@ -17,7 +17,7 @@ #include "dtoolbase.h" #include "selectThreadImpl.h" -#if (defined(__i386__) || defined(_M_IX86)) && !defined(__APPLE__) +#if (defined(__i386__) || defined(_M_IX86)) && !defined(__APPLE__) && !defined(__ANDROID__) #include "numeric_types.h" From 376cef51c494fa2e4514d757b88eec9f069445cd Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 26 Jan 2019 19:26:56 +0100 Subject: [PATCH 052/144] interrogate: fix Python 3 crash with optional std::wstring args This would cause PyMem_Free to be called on an uninitialized pointer if a default argument was not specified. Fixes #542 --- dtool/src/interrogate/interfaceMakerPythonNative.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index ca2ed7eb8d..5f351dbbc1 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -4701,7 +4701,7 @@ write_function_instance(ostream &out, FunctionRemap *remap, if (is_optional) { extra_convert - << "wchar_t *" << param_name << "_str;\n" + << "wchar_t *" << param_name << "_str = nullptr;\n" << "if (" << param_name << " != nullptr) {\n" << "#if PY_VERSION_HEX >= 0x03030000\n" << " " << param_name << "_str = PyUnicode_AsWideCharString(" << param_name << ", nullptr);\n" @@ -4748,7 +4748,7 @@ write_function_instance(ostream &out, FunctionRemap *remap, if (is_optional) { extra_convert << "Py_ssize_t " << param_name << "_len;\n" - << "wchar_t *" << param_name << "_str;\n" + << "wchar_t *" << param_name << "_str = nullptr;\n" << "std::wstring " << param_name << "_wstr;\n" << "if (" << param_name << " != nullptr) {\n" << "#if PY_VERSION_HEX >= 0x03030000\n" From dc8f01df8a4a0fc50fbc6eb27f5886b76ae0f55a Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 30 Jan 2019 23:51:50 +0100 Subject: [PATCH 053/144] ShaderGenerator: pack eye-space normal to save one varying Only when normal mapping is enabled. --- panda/src/pgraphnodes/shaderGenerator.cxx | 53 ++++++++++++++++------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index d00022984f..c66a325124 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -749,6 +749,11 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { bool need_world_normal = false; bool need_eye_position = key._lighting; bool need_eye_normal = !key._lights.empty() || ((key._outputs & AuxBitplaneAttrib::ABO_aux_normal) != 0); + bool need_tangents = ((key._texture_flags & ShaderKey::TF_map_normal) != 0); + + // If we have binormal/tangent and eye position, we can pack eye normal in + // the w channels of the others. + bool pack_eye_normal = need_eye_normal && need_tangents && need_eye_position; bool have_specular = false; if (key._lighting) { @@ -829,7 +834,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { map_index_gloss = i; } } - if (key._texture_flags & ShaderKey::TF_map_normal) { + if (need_tangents) { tangent_freg = alloc_freg(); binormal_freg = alloc_freg(); text << "\t out float4 l_tangent : " << tangent_freg << ",\n"; @@ -854,13 +859,15 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t uniform float4x4 trans_model_to_view,\n"; eye_position_freg = alloc_freg(); text << "\t out float4 l_eye_position : " << eye_position_freg << ",\n"; - } else if (key._texture_flags & ShaderKey::TF_map_normal) { + } else if (need_tangents) { text << "\t uniform float4x4 trans_model_to_view,\n"; } if (need_eye_normal) { - eye_normal_freg = alloc_freg(); text << "\t uniform float4x4 tpose_view_to_model,\n"; - text << "\t out float3 l_eye_normal : " << eye_normal_freg << ",\n"; + if (!pack_eye_normal) { + eye_normal_freg = alloc_freg(); + text << "\t out float3 l_eye_normal : " << eye_normal_freg << ",\n"; + } } if ((key._texture_flags & ShaderKey::TF_map_height) != 0 || need_world_normal || need_eye_normal) { text << "\t in float3 vtx_normal : " << normal_vreg << ",\n"; @@ -946,9 +953,6 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { if (need_eye_position) { text << "\t l_eye_position = mul(trans_model_to_view, vtx_position);\n"; } - if (need_eye_normal) { - text << "\t l_eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n"; - } pmap::const_iterator it; for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) { // Pass through all texcoord inputs as-is. @@ -958,7 +962,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { if (need_color && key._color_type == ColorAttrib::T_vertex) { text << "\t l_color = vtx_color;\n"; } - if (key._texture_flags & ShaderKey::TF_map_normal) { + if (need_tangents) { text << "\t l_tangent.xyz = normalize(mul((float3x3)trans_model_to_view, vtx_" << tangent_input << ".xyz));\n"; text << "\t l_tangent.w = 0;\n"; text << "\t l_binormal.xyz = normalize(mul((float3x3)trans_model_to_view, -vtx_" << binormal_input << ".xyz));\n"; @@ -976,6 +980,17 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t l_eyevec.z = dot(vtx_normal, eyedir);\n"; text << "\t l_eyevec = normalize(l_eyevec);\n"; } + if (need_eye_normal) { + if (pack_eye_normal) { + // We can pack the normal into the w channels of these unused varyings. + text << "\t float3 eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n"; + text << "\t l_tangent.w = eye_normal.x;\n"; + text << "\t l_binormal.w = eye_normal.y;\n"; + text << "\t l_eye_position.w = eye_normal.z;\n"; + } else { + text << "\t l_eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n"; + } + } text << "}\n\n"; // Fragment shader @@ -995,7 +1010,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { if (need_eye_position) { text << "\t in float4 l_eye_position : " << eye_position_freg << ",\n"; } - if (need_eye_normal) { + if (need_eye_normal && !pack_eye_normal) { text << "\t in float3 l_eye_normal : " << eye_normal_freg << ",\n"; } for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) { @@ -1020,9 +1035,9 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t uniform float4 texcolor_" << i << ",\n"; } } - if (key._texture_flags & ShaderKey::TF_map_normal) { - text << "\t in float3 l_tangent : " << tangent_freg << ",\n"; - text << "\t in float3 l_binormal : " << binormal_freg << ",\n"; + if (need_tangents) { + text << "\t in float4 l_tangent : " << tangent_freg << ",\n"; + text << "\t in float4 l_binormal : " << binormal_freg << ",\n"; } for (size_t i = 0; i < key._lights.size(); ++i) { text << "\t uniform float4x4 attr_light" << i << ",\n"; @@ -1078,6 +1093,12 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t discard;\n"; text << "\t }\n"; } + + // Reconstruct a packed normal vector. + if (need_eye_normal && pack_eye_normal) { + text << "\t float3 l_eye_normal = float3(l_tangent.w, l_binormal.w, l_eye_position.w);\n"; + } + text << "\t float4 result;\n"; if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) { text << "\t o_aux = float4(0, 0, 0, 0);\n"; @@ -1102,7 +1123,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t float4 texcoord" << i << " = l_world_normal;\n"; break; case TexGenAttrib::M_eye_position: - text << "\t float4 texcoord" << i << " = l_eye_position;\n"; + text << "\t float4 texcoord" << i << " = float4(l_eye_position.xyz, 1.0f);\n"; break; case TexGenAttrib::M_eye_normal: text << "\t float4 texcoord" << i << " = float4(l_eye_normal, 1.0f);\n"; @@ -1199,7 +1220,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t // Correct the surface normal for interpolation effects\n"; text << "\t l_eye_normal = normalize(l_eye_normal);\n"; } - if (key._texture_flags & ShaderKey::TF_map_normal) { + if (need_tangents) { text << "\t // Translate tangent-space normal in map to view-space.\n"; // Use Reoriented Normal Mapping to blend additional normal maps. @@ -1218,8 +1239,8 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } } text << "\t l_eye_normal *= tsnormal.z;\n"; - text << "\t l_eye_normal += normalize(l_tangent) * tsnormal.x;\n"; - text << "\t l_eye_normal += normalize(l_binormal) * tsnormal.y;\n"; + text << "\t l_eye_normal += normalize(l_tangent.xyz) * tsnormal.x;\n"; + text << "\t l_eye_normal += normalize(l_binormal.xyz) * tsnormal.y;\n"; text << "\t l_eye_normal = normalize(l_eye_normal);\n"; } if (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) { From 0e447b7429117d6a0ee173cee9736f2271896ed5 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 30 Jan 2019 23:54:22 +0100 Subject: [PATCH 054/144] ShaderGenerator: do shadow map calcs in fshader if out of varyings If too many shadow-casting lights are active, too many TEXCOORD varyings will be used and a shader compilation error will be displayed. Instead, Panda will now just do the calculation in the fragment shader if not enough varyings are available. It's slower, but better than crashing. --- panda/src/pgraphnodes/shaderGenerator.cxx | 45 +++++++++++++++++------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index c66a325124..77575371dd 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -876,20 +876,26 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t uniform float4 mspos_view,\n"; text << "\t out float3 l_eyevec,\n"; } - for (size_t i = 0; i < key._lights.size(); ++i) { - const ShaderKey::LightInfo &light = key._lights[i]; - if (light._flags & ShaderKey::LF_has_shadows) { - lightcoord_fregs.push_back(alloc_freg()); - text << "\t uniform float4x4 mat_shadow_" << i << ",\n"; - text << "\t out float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; - } else { - lightcoord_fregs.push_back(nullptr); - } - } if (key._fog_mode != 0) { hpos_freg = alloc_freg(); text << "\t out float4 l_hpos : " << hpos_freg << ",\n"; } + for (size_t i = 0; i < key._lights.size(); ++i) { + const ShaderKey::LightInfo &light = key._lights[i]; + if (light._flags & ShaderKey::LF_has_shadows) { + if (_ftregs_used >= 8) { + // We ran out of TEXCOORD registers. That means we have to do this + // calculation in the fragment shader, which is slower. + lightcoord_fregs.push_back(nullptr); + } else { + lightcoord_fregs.push_back(alloc_freg()); + text << "\t uniform float4x4 mat_shadow_" << i << ",\n"; + text << "\t out float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; + } + } else { + lightcoord_fregs.push_back(nullptr); + } + } if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware && key._anim_spec.get_num_transforms() > 0) { int num_transforms; @@ -970,7 +976,9 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } for (size_t i = 0; i < key._lights.size(); ++i) { if (key._lights[i]._flags & ShaderKey::LF_has_shadows) { - text << "\t l_lightcoord" << i << " = mul(mat_shadow_" << i << ", l_eye_position);\n"; + if (lightcoord_fregs[i] != nullptr) { + text << "\t l_lightcoord" << i << " = mul(mat_shadow_" << i << ", l_eye_position);\n"; + } } } if (key._texture_flags & ShaderKey::TF_map_height) { @@ -1051,7 +1059,11 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } else { text << "\t uniform sampler2D shadow_" << i << ",\n"; } - text << "\t in float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; + if (lightcoord_fregs[i] != nullptr) { + text << "\t in float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; + } else { + text << "\t uniform float4x4 mat_shadow_" << i << ",\n"; + } } if (light._flags & ShaderKey::LF_has_specular_color) { text << "\t uniform float4 attr_lspec" << i << ",\n"; @@ -1272,6 +1284,15 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } for (size_t i = 0; i < key._lights.size(); ++i) { const ShaderKey::LightInfo &light = key._lights[i]; + + if (light._flags & ShaderKey::LF_has_shadows) { + if (lightcoord_fregs[i] == nullptr) { + // We have to do this one in the fragment shader if we ran out of + // varyings. + text << "\t float4 l_lightcoord" << i << " = mul(mat_shadow_" << i << ", float4(l_eye_position.xyz, 1.0f));\n"; + } + } + if (light._type.is_derived_from(DirectionalLight::get_class_type())) { text << "\t // Directional Light " << i << "\n"; text << "\t lcolor = attr_light" << i << "[0];\n"; From 1d9334f578491230418501c1bd645062dd4efdda Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 30 Jan 2019 23:59:34 +0100 Subject: [PATCH 055/144] parser-inc: add atomic_int, etc. typedefs --- dtool/src/parser-inc/atomic | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/dtool/src/parser-inc/atomic b/dtool/src/parser-inc/atomic index a7e174937b..8167308f33 100644 --- a/dtool/src/parser-inc/atomic +++ b/dtool/src/parser-inc/atomic @@ -16,4 +16,50 @@ namespace std { template struct atomic; struct atomic_flag; + + using atomic_bool = atomic; + using atomic_char = atomic; + using atomic_schar = atomic; + using atomic_uchar = atomic; + using atomic_short = atomic; + using atomic_ushort = atomic; + using atomic_int = atomic; + using atomic_uint = atomic; + using atomic_long = atomic; + using atomic_ulong = atomic; + using atomic_llong = atomic; + using atomic_ullong = atomic; + using atomic_char16_t = atomic; + using atomic_char32_t = atomic; + using atomic_wchar_t = atomic; + using atomic_int8_t = atomic; + using atomic_uint8_t = atomic; + using atomic_int16_t = atomic; + using atomic_uint16_t = atomic; + using atomic_int32_t = atomic; + using atomic_uint32_t = atomic; + using atomic_int64_t = atomic; + using atomic_uint64_t = atomic; + using atomic_int_least8_t = atomic; + using atomic_uint_least8_t = atomic; + using atomic_int_least16_t = atomic; + using atomic_uint_least16_t = atomic; + using atomic_int_least32_t = atomic; + using atomic_uint_least32_t = atomic; + using atomic_int_least64_t = atomic; + using atomic_uint_least64_t = atomic; + using atomic_int_fast8_t = atomic; + using atomic_uint_fast8_t = atomic; + using atomic_int_fast16_t = atomic; + using atomic_uint_fast16_t = atomic; + using atomic_int_fast32_t = atomic; + using atomic_uint_fast32_t = atomic; + using atomic_int_fast64_t = atomic; + using atomic_uint_fast64_t = atomic; + using atomic_intptr_t = atomic; + using atomic_uintptr_t = atomic; + using atomic_size_t = atomic; + using atomic_ptrdiff_t = atomic; + using atomic_intmax_t = atomic; + using atomic_uintmax_t = atomic; } From 0ba1235d350a3136bdfd8691907cf024fd581bc8 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 31 Jan 2019 00:05:23 +0100 Subject: [PATCH 056/144] ShaderGenerator: print out generated shader in spam output mode --- panda/src/pgraphnodes/shaderGenerator.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index 77575371dd..7198024648 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -1684,6 +1684,11 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } text << "}\n"; + if (pgraphnodes_cat.is_spam()) { + pgraphnodes_cat.spam() << "Generated shader:\n" + << text.str() << "\n"; + } + // Insert the shader into the shader attrib. PT(Shader) shader = Shader::make(text.str(), Shader::SL_Cg); nassertr(shader != nullptr, nullptr); From 2627c433d60837a03c0453d81c9371e99a2227a7 Mon Sep 17 00:00:00 2001 From: John Cote Date: Wed, 30 Jan 2019 14:03:35 -0500 Subject: [PATCH 057/144] particles: Import SpriteAnim in Particles.py Fixes #544 Closes #545 --- direct/src/particles/Particles.py | 1 + 1 file changed, 1 insertion(+) diff --git a/direct/src/particles/Particles.py b/direct/src/particles/Particles.py index 6ed19af896..d05700c3b1 100644 --- a/direct/src/particles/Particles.py +++ b/direct/src/particles/Particles.py @@ -22,6 +22,7 @@ from panda3d.physics import RingEmitter from panda3d.physics import SphereSurfaceEmitter from panda3d.physics import SphereVolumeEmitter from panda3d.physics import TangentRingEmitter +from panda3d.physics import SpriteAnim from . import SpriteParticleRendererExt From 3a6f7fcde1f89c975ac558aa07e987f11bde0c07 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 31 Jan 2019 00:11:21 +0100 Subject: [PATCH 058/144] dtoolbase: docstring clarification for record_python_type [skip ci] --- dtool/src/dtoolbase/typeRegistry.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtool/src/dtoolbase/typeRegistry.cxx b/dtool/src/dtoolbase/typeRegistry.cxx index 360dfcd9e4..16f551ec33 100644 --- a/dtool/src/dtoolbase/typeRegistry.cxx +++ b/dtool/src/dtoolbase/typeRegistry.cxx @@ -210,7 +210,7 @@ record_alternate_name(TypeHandle type, const string &name) { #ifdef HAVE_PYTHON /** * Records the given Python type pointer in the type registry for the benefit - * of interrogate. + * of interrogate, which expects this to contain a Dtool_PyTypedObject. */ void TypeRegistry:: record_python_type(TypeHandle type, PyObject *python_type) { From 22cac1cdf937047dabb26498d845449a70437e80 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 31 Jan 2019 18:23:29 +0100 Subject: [PATCH 059/144] device: fix stack corruption crashes on 32-bit Windows --- panda/src/device/winInputDeviceManager.cxx | 4 ++-- panda/src/device/winInputDeviceManager.h | 2 +- panda/src/device/winRawInputDevice.cxx | 10 +++++----- panda/src/device/xInputDevice.cxx | 12 ++++++------ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/panda/src/device/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index 95f73549dd..40820f40cc 100644 --- a/panda/src/device/winInputDeviceManager.cxx +++ b/panda/src/device/winInputDeviceManager.cxx @@ -289,8 +289,8 @@ on_input_device_arrival(HANDLE handle) { // Some devices insert quite some trailing space here. wchar_t *wbuffer = (wchar_t *)buffer; - size_t wlen = wcslen(wbuffer); - while (iswspace(wbuffer[wlen - 1])) { + size_t wlen = wcsnlen_s(wbuffer, sizeof(buffer) / sizeof(wchar_t)); + while (wlen > 0 && iswspace(wbuffer[wlen - 1])) { wbuffer[--wlen] = 0; } TextEncoder encoder; diff --git a/panda/src/device/winInputDeviceManager.h b/panda/src/device/winInputDeviceManager.h index 6c3fefd8c1..4bf178b376 100644 --- a/panda/src/device/winInputDeviceManager.h +++ b/panda/src/device/winInputDeviceManager.h @@ -54,7 +54,7 @@ private: static LRESULT WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); - typedef CONFIGRET (*pCM_Get_DevNode_Property)(DEVINST, const DEVPROPKEY *, DEVPROPTYPE *, PBYTE, PULONG, ULONG); + typedef CONFIGRET (WINAPI *pCM_Get_DevNode_Property)(DEVINST, const DEVPROPKEY *, DEVPROPTYPE *, PBYTE, PULONG, ULONG); pCM_Get_DevNode_Property _CM_Get_DevNode_PropertyW; friend class InputDeviceManager; diff --git a/panda/src/device/winRawInputDevice.cxx b/panda/src/device/winRawInputDevice.cxx index 9c49d83122..dd4ecdb973 100644 --- a/panda/src/device/winRawInputDevice.cxx +++ b/panda/src/device/winRawInputDevice.cxx @@ -159,11 +159,11 @@ typedef struct _HIDP_DATA { } HIDP_DATA, *PHIDP_DATA; typedef LONG NTSTATUS; -typedef NTSTATUS (*pHidP_GetCaps)(PHIDP_PREPARSED_DATA, PHIDP_CAPS); -typedef NTSTATUS (*pHidP_GetButtonCaps)(HIDP_REPORT_TYPE, PHIDP_BUTTON_CAPS, PUSHORT, PHIDP_PREPARSED_DATA); -typedef NTSTATUS (*pHidP_GetValueCaps)(HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PUSHORT, PHIDP_PREPARSED_DATA); -typedef NTSTATUS (*pHidP_GetData)(HIDP_REPORT_TYPE, PHIDP_DATA, PULONG, PHIDP_PREPARSED_DATA, PCHAR, ULONG); -typedef ULONG (*pHidP_MaxDataListLength)(HIDP_REPORT_TYPE, PHIDP_PREPARSED_DATA); +typedef NTSTATUS (__stdcall *pHidP_GetCaps)(PHIDP_PREPARSED_DATA, PHIDP_CAPS); +typedef NTSTATUS (__stdcall *pHidP_GetButtonCaps)(HIDP_REPORT_TYPE, PHIDP_BUTTON_CAPS, PUSHORT, PHIDP_PREPARSED_DATA); +typedef NTSTATUS (__stdcall *pHidP_GetValueCaps)(HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PUSHORT, PHIDP_PREPARSED_DATA); +typedef NTSTATUS (__stdcall *pHidP_GetData)(HIDP_REPORT_TYPE, PHIDP_DATA, PULONG, PHIDP_PREPARSED_DATA, PCHAR, ULONG); +typedef ULONG (__stdcall *pHidP_MaxDataListLength)(HIDP_REPORT_TYPE, PHIDP_PREPARSED_DATA); static pHidP_GetCaps _HidP_GetCaps = nullptr; static pHidP_GetButtonCaps _HidP_GetButtonCaps = nullptr; diff --git a/panda/src/device/xInputDevice.cxx b/panda/src/device/xInputDevice.cxx index 9e8035fb0e..b86a5cd90b 100644 --- a/panda/src/device/xInputDevice.cxx +++ b/panda/src/device/xInputDevice.cxx @@ -99,12 +99,12 @@ typedef struct _XINPUT_CAPABILITIES_EX { WORD Unknown2; } XINPUT_CAPABILITIES_EX; -typedef DWORD (*pXInputGetState)(DWORD, XINPUT_STATE *); -typedef DWORD (*pXInputSetState)(DWORD, XINPUT_VIBRATION *); -typedef DWORD (*pXInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES *); -typedef DWORD (*pXInputGetCapabilitiesEx)(DWORD, DWORD, DWORD, XINPUT_CAPABILITIES_EX *); -typedef DWORD (*pXInputGetBatteryInformation)(DWORD, BYTE, XINPUT_BATTERY_INFORMATION *); -typedef DWORD (*pXInputGetBaseBusInformation)(DWORD, XINPUT_BUSINFO *); +typedef DWORD (WINAPI *pXInputGetState)(DWORD, XINPUT_STATE *); +typedef DWORD (WINAPI *pXInputSetState)(DWORD, XINPUT_VIBRATION *); +typedef DWORD (WINAPI *pXInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES *); +typedef DWORD (WINAPI *pXInputGetCapabilitiesEx)(DWORD, DWORD, DWORD, XINPUT_CAPABILITIES_EX *); +typedef DWORD (WINAPI *pXInputGetBatteryInformation)(DWORD, BYTE, XINPUT_BATTERY_INFORMATION *); +typedef DWORD (WINAPI *pXInputGetBaseBusInformation)(DWORD, XINPUT_BUSINFO *); static pXInputGetState get_state = nullptr; static pXInputSetState set_state = nullptr; From 16d5c27a57aa34fa07b764d2ab5323b5611ebbfa Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Feb 2019 23:37:47 +0100 Subject: [PATCH 060/144] collide: remove unused legacy_to_3d method --- panda/src/collide/collisionBox.h | 1 - panda/src/collide/collisionPolygon.cxx | 31 -------------------------- panda/src/collide/collisionPolygon.h | 1 - 3 files changed, 33 deletions(-) diff --git a/panda/src/collide/collisionBox.h b/panda/src/collide/collisionBox.h index db9d2c2aa9..3baa77d152 100644 --- a/panda/src/collide/collisionBox.h +++ b/panda/src/collide/collisionBox.h @@ -139,7 +139,6 @@ public: INLINE void calc_to_3d_mat(LMatrix4 &to_3d_mat, int plane) const; INLINE void rederive_to_3d_mat(LMatrix4 &to_3d_mat, int plane) const; INLINE static LPoint3 to_3d(const LVecBase2 &point2d, const LMatrix4 &to_3d_mat); - LPoint3 legacy_to_3d(const LVecBase2 &point2d, int axis) const; bool clip_polygon(Points &new_points, const Points &source_points, const LPlane &plane,int plane_no) const; bool apply_clip_plane(Points &new_points, const ClipPlaneAttrib *cpa, diff --git a/panda/src/collide/collisionPolygon.cxx b/panda/src/collide/collisionPolygon.cxx index 24c8230d2f..59914c25e1 100644 --- a/panda/src/collide/collisionPolygon.cxx +++ b/panda/src/collide/collisionPolygon.cxx @@ -1335,37 +1335,6 @@ setup_points(const LPoint3 *begin, const LPoint3 *end) { compute_vectors(_points); } -/** - * Converts the indicated point to 3-d space according to the way - * CollisionPolygons used to be stored in bam files prior to 4.9. - */ -LPoint3 CollisionPolygon:: -legacy_to_3d(const LVecBase2 &point2d, int axis) const { - nassertr(!point2d.is_nan(), LPoint3(0.0f, 0.0f, 0.0f)); - - LVector3 normal = get_normal(); - PN_stdfloat D = get_plane()[3]; - - nassertr(!normal.is_nan(), LPoint3(0.0f, 0.0f, 0.0f)); - nassertr(!cnan(D), LPoint3(0.0f, 0.0f, 0.0f)); - - switch (axis) { - case 0: // AT_x: - return LPoint3(-(normal[1]*point2d[0] + normal[2]*point2d[1] + D)/normal[0], point2d[0], point2d[1]); - - case 1: // AT_y: - return LPoint3(point2d[0], - -(normal[0]*point2d[0] + normal[2]*point2d[1] + D)/normal[1], point2d[1]); - - case 2: // AT_z: - return LPoint3(point2d[0], point2d[1], - -(normal[0]*point2d[0] + normal[1]*point2d[1] + D)/normal[2]); - } - - nassertr(false, LPoint3(0.0f, 0.0f, 0.0f)); - return LPoint3(0.0f, 0.0f, 0.0f); -} - /** * Clips the source_points of the polygon by the indicated clipping plane, and * modifies new_points to reflect the new set of clipped points (but does not diff --git a/panda/src/collide/collisionPolygon.h b/panda/src/collide/collisionPolygon.h index f7fa771bfa..81dd37fdc7 100644 --- a/panda/src/collide/collisionPolygon.h +++ b/panda/src/collide/collisionPolygon.h @@ -131,7 +131,6 @@ private: INLINE void calc_to_3d_mat(LMatrix4 &to_3d_mat) const; INLINE void rederive_to_3d_mat(LMatrix4 &to_3d_mat) const; INLINE static LPoint3 to_3d(const LVecBase2 &point2d, const LMatrix4 &to_3d_mat); - LPoint3 legacy_to_3d(const LVecBase2 &point2d, int axis) const; bool clip_polygon(Points &new_points, const Points &source_points, const LPlane &plane) const; From e96736846826a5bbd6b5d4f0e90e814e617cf697 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Feb 2019 23:41:03 +0100 Subject: [PATCH 061/144] collide: add capsule-into-polygon test Need to find a better solution for the interior point calculation when the capsule is hitting a polygon edge with the cylindrical part. The current approach pushes the capsule back too much. --- panda/src/collide/collisionCapsule.h | 1 + panda/src/collide/collisionPolygon.cxx | 136 +++++++++++++++++++++++++ panda/src/collide/collisionPolygon.h | 2 + 3 files changed, 139 insertions(+) diff --git a/panda/src/collide/collisionCapsule.h b/panda/src/collide/collisionCapsule.h index b6d375ff44..994a12d011 100644 --- a/panda/src/collide/collisionCapsule.h +++ b/panda/src/collide/collisionCapsule.h @@ -154,6 +154,7 @@ private: static TypeHandle _type_handle; friend class CollisionBox; + friend class CollisionPolygon; }; #include "collisionCapsule.I" diff --git a/panda/src/collide/collisionPolygon.cxx b/panda/src/collide/collisionPolygon.cxx index 59914c25e1..0c467c1d4c 100644 --- a/panda/src/collide/collisionPolygon.cxx +++ b/panda/src/collide/collisionPolygon.cxx @@ -842,6 +842,142 @@ test_intersection_from_parabola(const CollisionEntry &entry) const { return new_entry; } +/** + * This is part of the double-dispatch implementation of test_intersection(). + * It is called when the "from" object is a capsule. + */ +PT(CollisionEntry) CollisionPolygon:: +test_intersection_from_capsule(const CollisionEntry &entry) const { + if (_points.size() < 3) { + return nullptr; + } + + const CollisionCapsule *capsule; + DCAST_INTO_R(capsule, entry.get_from(), nullptr); + + const LMatrix4 &wrt_mat = entry.get_wrt_mat(); + LMatrix4 plane_mat = wrt_mat * _to_2d_mat; + + LPoint3 from_a = capsule->get_point_a() * plane_mat; + LPoint3 from_b = capsule->get_point_b() * plane_mat; + + LVector3 from_radius_v = + LVector3(capsule->get_radius(), 0.0f, 0.0f) * wrt_mat; + PN_stdfloat from_radius_sq = from_radius_v.length_squared(); + + // Check if the capsule is colliding with the plane at all. + // Are the points on the same side of the plane? + if ((from_a[1] > 0) == (from_b[1] > 0)) { + // Yes, so calculate the distance of the closest point. + PN_stdfloat dist = min(cabs(from_a[1]), cabs(from_b[1])); + if (dist * dist > from_radius_sq) { + return nullptr; + } + } + + // Order from_a and from_b so that from_a has the deepest point. + bool swapped = (from_a[1] < from_b[1]); + if (swapped) { + std::swap(from_a, from_b); + } + + LPoint3 surface_point, interior_point; + + // Is the projection of from_a onto the plane inside the polygon? + LPoint2 from_a_proj(from_a[0], from_a[2]); + if (point_is_inside(from_a_proj, _points)) { + // Yes, and we already checked the vertical separation earlier on, so we + // know that the capsule is touching the polygon near from_a. + LPoint3 deepest = (swapped ? capsule->get_point_b() : capsule->get_point_a()) * wrt_mat; + PN_stdfloat from_radius = csqrt(from_radius_sq); + surface_point = get_plane().project(deepest); + interior_point = deepest - get_normal() * from_radius; + } + else { + LVector3 from_direction = from_b - from_a; + + // Find the point in the capsule's inner segment with the closest distance + // to the polygon's edges. We effectively test a sphere around that point. + PN_stdfloat min_dist_sq = make_inf((PN_stdfloat)0); + LPoint3 poly_point; + LPoint3 line_point; + + LPoint2 last_point = _points.back()._p; + for (const PointDef &pd : _points) { + LVector2 dir = last_point - pd._p; + last_point = pd._p; + + double t1, t2; + CollisionCapsule::calc_closest_segment_points(t1, t2, + LPoint3(pd._p[0], 0, pd._p[1]), LVector3(dir[0], 0, dir[1]), + from_a, from_direction); + + LPoint3 point1(pd._p[0] + dir[0] * t1, 0, pd._p[1] + dir[1] * t1); + LPoint3 point2 = from_a + from_direction * t2; + PN_stdfloat dist_sq = (point2 - point1).length_squared(); + if (dist_sq < min_dist_sq) { + min_dist_sq = dist_sq; + poly_point = point1; + line_point = point2; + } + } + + // Project the closest point on the segment onto the polygon. Is this point + // inside the polygon? + LPoint2 line_point_proj(line_point[0], line_point[2]); + if (point_is_inside(line_point_proj, _points)) { + // Yes, and we already checked the vertical separation earlier on, so we + // know that the capsule is touching the polygon here. + LMatrix4 to_3d_mat; + rederive_to_3d_mat(to_3d_mat); + + surface_point = to_3d(line_point_proj, to_3d_mat); + + LPoint3 interior; + if (IS_NEARLY_EQUAL(from_a[1], from_b[1])) { + // It's parallel to the polygon; we can use any point on the segment we + // want, so we might as well use the point we determined to be closest. + interior = line_point; + } else { + // Use the deepest point. FIXME: we need something better. This + // pushes the capsule out way too much. + interior = from_a; + } + interior[1] += csqrt(from_radius_sq); + interior_point = interior * to_3d_mat; + } + else if (min_dist_sq < from_radius_sq) { + // No, but it is colliding with an edge. + LMatrix4 to_3d_mat; + rederive_to_3d_mat(to_3d_mat); + + surface_point = poly_point * to_3d_mat; + + // Make sure we calculate an interior point that lies below the polygon. + LVector3 dir = line_point * to_3d_mat - surface_point; + dir.normalize(); + interior_point = surface_point - dir * (csqrt(from_radius_sq) - csqrt(min_dist_sq)); + } + else { + // It is outside the polygon altogether. + return nullptr; + } + } + + if (collide_cat.is_debug()) { + collide_cat.debug() + << "intersection detected from " << entry.get_from_node_path() + << " into " << entry.get_into_node_path() << "\n"; + } + PT(CollisionEntry) new_entry = new CollisionEntry(entry); + LVector3 normal = (has_effective_normal() && capsule->get_respect_effective_normal()) ? get_effective_normal() : get_normal(); + new_entry->set_surface_normal(normal); + new_entry->set_surface_point(surface_point); + new_entry->set_interior_point(interior_point); + + return new_entry; +} + /** * This is part of the double-dispatch implementation of test_intersection(). * It is called when the "from" object is a box. diff --git a/panda/src/collide/collisionPolygon.h b/panda/src/collide/collisionPolygon.h index 81dd37fdc7..145f35c8a6 100644 --- a/panda/src/collide/collisionPolygon.h +++ b/panda/src/collide/collisionPolygon.h @@ -93,6 +93,8 @@ protected: virtual PT(CollisionEntry) test_intersection_from_parabola(const CollisionEntry &entry) const; virtual PT(CollisionEntry) + test_intersection_from_capsule(const CollisionEntry &entry) const; + virtual PT(CollisionEntry) test_intersection_from_box(const CollisionEntry &entry) const; virtual void fill_viz_geom(); From 2afd604c9d1433ba9e704a0a00fb97814cd12f9d Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Feb 2019 23:50:53 +0100 Subject: [PATCH 062/144] collide: implement capsule-into-invsphere and box-into-invsphere tests --- panda/src/collide/collisionInvSphere.cxx | 113 +++++++++++++++++++++++ panda/src/collide/collisionInvSphere.h | 4 + 2 files changed, 117 insertions(+) diff --git a/panda/src/collide/collisionInvSphere.cxx b/panda/src/collide/collisionInvSphere.cxx index 8a75135e55..1428078d09 100644 --- a/panda/src/collide/collisionInvSphere.cxx +++ b/panda/src/collide/collisionInvSphere.cxx @@ -288,6 +288,119 @@ test_intersection_from_segment(const CollisionEntry &entry) const { return new_entry; } +/** + * + */ +PT(CollisionEntry) CollisionInvSphere:: +test_intersection_from_capsule(const CollisionEntry &entry) const { + const CollisionCapsule *capsule; + DCAST_INTO_R(capsule, entry.get_from(), nullptr); + + const LMatrix4 &wrt_mat = entry.get_wrt_mat(); + + LPoint3 from_a = capsule->get_point_a() * wrt_mat; + LPoint3 from_b = capsule->get_point_b() * wrt_mat; + + LVector3 from_radius_v = + LVector3(capsule->get_radius(), 0.0f, 0.0f) * wrt_mat; + PN_stdfloat from_radius = from_radius_v.length(); + + LPoint3 center = get_center(); + PN_stdfloat radius = get_radius(); + + // Check which one of the points lies furthest inside the sphere. + PN_stdfloat dist_a = (from_a - center).length(); + PN_stdfloat dist_b = (from_b - center).length(); + if (dist_b > dist_a) { + // Store the furthest point into from_a/dist_a. + dist_a = dist_b; + from_a = from_b; + } + + // from_a now contains the furthest point. Is it inside? + if (dist_a < radius - from_radius) { + return nullptr; + } + + if (collide_cat.is_debug()) { + collide_cat.debug() + << "intersection detected from " << entry.get_from_node_path() + << " into " << entry.get_into_node_path() << "\n"; + } + PT(CollisionEntry) new_entry = new CollisionEntry(entry); + + LVector3 normal = center - from_a; + normal.normalize(); + new_entry->set_surface_point(get_center() - normal * radius); + new_entry->set_interior_point(from_a - normal * from_radius); + + if (has_effective_normal() && capsule->get_respect_effective_normal()) { + new_entry->set_surface_normal(get_effective_normal()); + } else { + new_entry->set_surface_normal(normal); + } + + return new_entry; +} + +/** + * Double dispatch point for box as a FROM object + */ +PT(CollisionEntry) CollisionInvSphere:: +test_intersection_from_box(const CollisionEntry &entry) const { + const CollisionBox *box; + DCAST_INTO_R(box, entry.get_from(), nullptr); + + const LMatrix4 &wrt_mat = entry.get_wrt_mat(); + + LPoint3 center = get_center(); + PN_stdfloat radius_sq = get_radius(); + radius_sq *= radius_sq; + + // Just figure out which box point is furthest from the center. If it + // exceeds the radius, the furthest point wins. + + PN_stdfloat max_dist_sq = -1.0; + LPoint3 deepest_vertex; + + for (int i = 0; i < 8; ++i) { + LPoint3 point = wrt_mat.xform_point(box->get_point(i)); + + PN_stdfloat dist_sq = (point - center).length_squared(); + if (dist_sq > max_dist_sq) { + deepest_vertex = point; + max_dist_sq = dist_sq; + } + } + + if (max_dist_sq < radius_sq) { + // The point furthest away from the center is still inside the sphere. + // Therefore, no collision. + return nullptr; + } + + if (collide_cat.is_debug()) { + collide_cat.debug() + << "intersection detected from " << entry.get_from_node_path() + << " into " << entry.get_into_node_path() << "\n"; + } + + PT(CollisionEntry) new_entry = new CollisionEntry(entry); + + // The interior point is just the deepest cube vertex. + new_entry->set_interior_point(deepest_vertex); + + // Now extrapolate the surface point and normal from that. + LVector3 normal = center - deepest_vertex; + normal.normalize(); + new_entry->set_surface_point(center - normal * get_radius()); + new_entry->set_surface_normal( + (has_effective_normal() && box->get_respect_effective_normal()) + ? get_effective_normal() : normal); + + return new_entry; +} + /** * Fills the _viz_geom GeomNode up with Geoms suitable for rendering this * solid. diff --git a/panda/src/collide/collisionInvSphere.h b/panda/src/collide/collisionInvSphere.h index fe8b43b10d..b716f412d6 100644 --- a/panda/src/collide/collisionInvSphere.h +++ b/panda/src/collide/collisionInvSphere.h @@ -55,6 +55,10 @@ protected: test_intersection_from_ray(const CollisionEntry &entry) const; virtual PT(CollisionEntry) test_intersection_from_segment(const CollisionEntry &entry) const; + virtual PT(CollisionEntry) + test_intersection_from_capsule(const CollisionEntry &entry) const; + virtual PT(CollisionEntry) + test_intersection_from_box(const CollisionEntry &entry) const; virtual void fill_viz_geom(); From 63d2992d5ed36be5a5273a96237814e953e36b04 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 5 Feb 2019 00:30:54 +0100 Subject: [PATCH 063/144] egg: add ability to read with four components This is not intended to be used just yet in 1.10, but already added in preparation for changes on master to support #546. I'm just allowing Panda to parse the syntax ahead of time to reduce potential .egg incompatiblities. --- panda/src/egg/eggVertexUV.I | 37 +++++++++++++++ panda/src/egg/eggVertexUV.cxx | 5 +- panda/src/egg/eggVertexUV.h | 7 +++ panda/src/egg/parser.yxx | 8 ++++ tests/egg/test_egg_vertex_uv.py | 84 +++++++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 tests/egg/test_egg_vertex_uv.py diff --git a/panda/src/egg/eggVertexUV.I b/panda/src/egg/eggVertexUV.I index 05f6f8609f..eef97e52e3 100644 --- a/panda/src/egg/eggVertexUV.I +++ b/panda/src/egg/eggVertexUV.I @@ -97,6 +97,14 @@ has_tangent() const { return (_flags & F_has_tangent) != 0; } +/** + * + */ +INLINE bool EggVertexUV:: +has_tangent4() const { + return (_flags & F_has_tangent4) != 0; +} + /** * */ @@ -106,6 +114,19 @@ get_tangent() const { return _tangent; } +/** + * + */ +INLINE LVecBase4d EggVertexUV:: +get_tangent4() const { + LVecBase4d tangent4(_tangent, 1.0); + nassertr_always(has_tangent(), tangent4); + if (_flags & F_flip_computed_binormal) { + tangent4[3] = -1.0; + } + return tangent4; +} + /** * */ @@ -113,6 +134,22 @@ INLINE void EggVertexUV:: set_tangent(const LNormald &tangent) { _tangent = tangent; _flags |= F_has_tangent; + _flags &= ~(F_has_tangent4 | F_flip_computed_binormal); +} + +/** + * Sets the tangent vector, along with a fourth parameter that is multiplied + * with the result of cross(normal, tangent) when computing the binormal. + */ +INLINE void EggVertexUV:: +set_tangent4(const LVecBase4d &tangent) { + _tangent = tangent.get_xyz(); + _flags |= F_has_tangent4 | F_has_tangent; + if (tangent[3] < 0.0) { + _flags |= F_flip_computed_binormal; + } else { + _flags &= ~F_flip_computed_binormal; + } } /** diff --git a/panda/src/egg/eggVertexUV.cxx b/panda/src/egg/eggVertexUV.cxx index 49a3c39ace..bcc0c1055e 100644 --- a/panda/src/egg/eggVertexUV.cxx +++ b/panda/src/egg/eggVertexUV.cxx @@ -145,7 +145,10 @@ write(std::ostream &out, int indent_level) const { } else { indent(out, indent_level+2) << get_uv() << "\n"; } - if (has_tangent()) { + if (has_tangent4()) { + indent(out, indent_level + 2) + << " { " << get_tangent4() << " }\n"; + } else if (has_tangent()) { indent(out, indent_level + 2) << " { " << get_tangent() << " }\n"; } diff --git a/panda/src/egg/eggVertexUV.h b/panda/src/egg/eggVertexUV.h index 2ab0447639..e729f28101 100644 --- a/panda/src/egg/eggVertexUV.h +++ b/panda/src/egg/eggVertexUV.h @@ -45,8 +45,11 @@ PUBLISHED: INLINE void set_uvw(const LTexCoord3d &texCoord); INLINE bool has_tangent() const; + INLINE bool has_tangent4() const; INLINE const LNormald &get_tangent() const; + INLINE LVecBase4d get_tangent4() const; INLINE void set_tangent(const LNormald &tangent); + INLINE void set_tangent4(const LVecBase4d &tangent); INLINE void clear_tangent(); INLINE bool has_binormal() const; @@ -69,6 +72,10 @@ private: F_has_tangent = 0x001, F_has_binormal = 0x002, F_has_w = 0x004, + F_has_tangent4 = 0x008, + + // Only defined temporarily as we can't add a float to this class in 1.10. + F_flip_computed_binormal = 0x010, }; int _flags; diff --git a/panda/src/egg/parser.yxx b/panda/src/egg/parser.yxx index 1ffaa3a078..6125ead479 100644 --- a/panda/src/egg/parser.yxx +++ b/panda/src/egg/parser.yxx @@ -1103,6 +1103,14 @@ vertex_uv_body: } else { DCAST(EggVertexUV, egg_stack.back())->set_tangent(LNormald($4, $5, $6)); } +} + | vertex_uv_body TANGENT '{' real real real real '}' +{ + if (DCAST(EggVertexUV, egg_stack.back())->has_tangent()) { + eggyywarning("Ignoring repeated tangent"); + } else { + DCAST(EggVertexUV, egg_stack.back())->set_tangent4(LVecBase4d($4, $5, $6, $7)); + } } | vertex_uv_body BINORMAL '{' real real real '}' { diff --git a/tests/egg/test_egg_vertex_uv.py b/tests/egg/test_egg_vertex_uv.py new file mode 100644 index 0000000000..e2f1deeebf --- /dev/null +++ b/tests/egg/test_egg_vertex_uv.py @@ -0,0 +1,84 @@ +import pytest +from panda3d import core + +# Skip these tests if we can't import egg. +egg = pytest.importorskip("panda3d.egg") + + +def read_egg_vertex(string): + """Reads an EggVertex from a string.""" + data = " pool { 1 { %s } }" % (string) + stream = core.StringStream(data.encode('utf-8')) + data = egg.EggData() + assert data.read(stream) + pool, = data.get_children() + return pool.get_vertex(1) + + +def test_egg_vertex_uv_empty(): + vertex = read_egg_vertex(""" + 0 0 0 + { + 0 0 + } + """) + + obj = vertex.get_uv_obj("") + assert not obj.has_tangent() + assert not obj.has_tangent4() + + assert '' not in str(obj) + + +def test_egg_vertex_tangent(): + vertex = read_egg_vertex(""" + 0 0 0 + { + 0 0 + { 2 3 4 } + } + """) + + obj = vertex.get_uv_obj("") + assert obj.has_tangent() + assert not obj.has_tangent4() + assert obj.get_tangent() == (2, 3, 4) + assert obj.get_tangent4() == (2, 3, 4, 1) + + assert '{ 2 3 4 }' in str(obj) + + +def test_egg_vertex_tangent4_pos(): + vertex = read_egg_vertex(""" + 0 0 0 + { + 0 0 + { 2 3 4 1 } + } + """) + + obj = vertex.get_uv_obj("") + assert obj.has_tangent() + assert obj.has_tangent4() + assert obj.get_tangent() == (2, 3, 4) + assert obj.get_tangent4() == (2, 3, 4, 1) + + assert '{ 2 3 4 1 }' in str(obj) + + +def test_egg_vertex_tangent4_neg(): + vertex = read_egg_vertex(""" + 0 0 0 + { + 0 0 + { 2 3 4 -1 } + } + """) + + obj = vertex.get_uv_obj("") + assert obj.has_tangent() + assert obj.has_tangent4() + assert obj.get_tangent() == (2, 3, 4) + assert obj.get_tangent4() == (2, 3, 4, -1) + + assert '{ 2 3 4 -1 }' in str(obj) From aadc62a96c18d9911428da041e611f8c3b01a444 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 6 Feb 2019 21:51:06 +0100 Subject: [PATCH 064/144] device: fix inability to detect devices with pipelining enabled This is because the message window is being created in the main thread, but there is nothing processing messages in the main thread. --- panda/src/device/winInputDeviceManager.cxx | 13 +++++++++++++ panda/src/device/winInputDeviceManager.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/panda/src/device/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index 40820f40cc..515dc376d8 100644 --- a/panda/src/device/winInputDeviceManager.cxx +++ b/panda/src/device/winInputDeviceManager.cxx @@ -391,6 +391,19 @@ on_input_device_removal(HANDLE handle) { } } +/** + * Polls the system to see if there are any new devices. In some + * implementations this is a no-op. + */ +void WinInputDeviceManager:: +update() { + MSG msg; + while (PeekMessage(&msg, _message_hwnd, WM_INPUT_DEVICE_CHANGE, WM_INPUT, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + /** * Implementation of the message loop. */ diff --git a/panda/src/device/winInputDeviceManager.h b/panda/src/device/winInputDeviceManager.h index 4bf178b376..e99a01f761 100644 --- a/panda/src/device/winInputDeviceManager.h +++ b/panda/src/device/winInputDeviceManager.h @@ -52,6 +52,8 @@ private: pmap _raw_devices; pmap _raw_devices_by_path; + virtual void update() override; + static LRESULT WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); typedef CONFIGRET (WINAPI *pCM_Get_DevNode_Property)(DEVINST, const DEVPROPKEY *, DEVPROPTYPE *, PBYTE, PULONG, ULONG); From 1b4035f29a0aae7e7f7c488cc19afbed8f5682b2 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 6 Feb 2019 21:56:47 +0100 Subject: [PATCH 065/144] device: move HID API definitions to separate header file --- panda/src/device/phidsdi.h | 166 +++++++++++++++++++++++++ panda/src/device/winRawInputDevice.cxx | 146 +--------------------- 2 files changed, 167 insertions(+), 145 deletions(-) create mode 100644 panda/src/device/phidsdi.h diff --git a/panda/src/device/phidsdi.h b/panda/src/device/phidsdi.h new file mode 100644 index 0000000000..647b3ed322 --- /dev/null +++ b/panda/src/device/phidsdi.h @@ -0,0 +1,166 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file phidsdi.h + * @author rdb + * @date 2019-02-05 + */ + +#ifndef PHIDSDI_H +#define PHIDSDI_H + +#if defined(_WIN32) && !defined(CPPPARSER) + +// Copy definitions from hidusage.h, until we can drop support for the 7.1 SDK +typedef USHORT USAGE, *PUSAGE; + +#define HID_USAGE_PAGE_UNDEFINED ((USAGE) 0x00) +#define HID_USAGE_PAGE_GENERIC ((USAGE) 0x01) +#define HID_USAGE_PAGE_SIMULATION ((USAGE) 0x02) +#define HID_USAGE_PAGE_VR ((USAGE) 0x03) +#define HID_USAGE_PAGE_SPORT ((USAGE) 0x04) +#define HID_USAGE_PAGE_GAME ((USAGE) 0x05) +#define HID_USAGE_PAGE_KEYBOARD ((USAGE) 0x07) +#define HID_USAGE_PAGE_LED ((USAGE) 0x08) +#define HID_USAGE_PAGE_BUTTON ((USAGE) 0x09) + +#define HID_USAGE_GENERIC_POINTER ((USAGE) 0x01) +#define HID_USAGE_GENERIC_MOUSE ((USAGE) 0x02) +#define HID_USAGE_GENERIC_JOYSTICK ((USAGE) 0x04) +#define HID_USAGE_GENERIC_GAMEPAD ((USAGE) 0x05) +#define HID_USAGE_GENERIC_KEYBOARD ((USAGE) 0x06) +#define HID_USAGE_GENERIC_KEYPAD ((USAGE) 0x07) +#define HID_USAGE_GENERIC_SYSTEM_CTL ((USAGE) 0x80) + +#define HID_USAGE_GENERIC_X ((USAGE) 0x30) +#define HID_USAGE_GENERIC_Y ((USAGE) 0x31) +#define HID_USAGE_GENERIC_Z ((USAGE) 0x32) +#define HID_USAGE_GENERIC_RX ((USAGE) 0x33) +#define HID_USAGE_GENERIC_RY ((USAGE) 0x34) +#define HID_USAGE_GENERIC_RZ ((USAGE) 0x35) +#define HID_USAGE_GENERIC_SLIDER ((USAGE) 0x36) +#define HID_USAGE_GENERIC_DIAL ((USAGE) 0x37) +#define HID_USAGE_GENERIC_WHEEL ((USAGE) 0x38) +#define HID_USAGE_GENERIC_HATSWITCH ((USAGE) 0x39) + +// Copy definitions from hidpi.h, until we can drop support for the 7.1 SDK +#define HIDP_STATUS_SUCCESS ((NTSTATUS)(0x11 << 16)) + +typedef enum _HIDP_REPORT_TYPE { + HidP_Input, + HidP_Output, + HidP_Feature +} HIDP_REPORT_TYPE; + +typedef struct _HIDP_BUTTON_CAPS { + USAGE UsagePage; + UCHAR ReportID; + BOOLEAN IsAlias; + USHORT BitField; + USHORT LinkCollection; + USAGE LinkUsage; + USAGE LinkUsagePage; + BOOLEAN IsRange; + BOOLEAN IsStringRange; + BOOLEAN IsDesignatorRange; + BOOLEAN IsAbsolute; + ULONG Reserved[10]; + union { + struct { + USAGE UsageMin, UsageMax; + USHORT StringMin, StringMax; + USHORT DesignatorMin, DesignatorMax; + USHORT DataIndexMin, DataIndexMax; + } Range; + struct { + USAGE Usage, Reserved1; + USHORT StringIndex, Reserved2; + USHORT DesignatorIndex, Reserved3; + USHORT DataIndex, Reserved4; + } NotRange; + }; +} HIDP_BUTTON_CAPS, *PHIDP_BUTTON_CAPS; + +typedef struct _HIDP_VALUE_CAPS { + USAGE UsagePage; + UCHAR ReportID; + BOOLEAN IsAlias; + USHORT BitField; + USHORT LinkCollection; + USAGE LinkUsage; + USAGE LinkUsagePage; + BOOLEAN IsRange; + BOOLEAN IsStringRange; + BOOLEAN IsDesignatorRange; + BOOLEAN IsAbsolute; + BOOLEAN HasNull; + UCHAR Reserved; + USHORT BitSize; + USHORT ReportCount; + USHORT Reserved2[5]; + ULONG UnitsExp; + ULONG Units; + LONG LogicalMin, LogicalMax; + LONG PhysicalMin, PhysicalMax; + union { + struct { + USAGE UsageMin, UsageMax; + USHORT StringMin, StringMax; + USHORT DesignatorMin, DesignatorMax; + USHORT DataIndexMin, DataIndexMax; + } Range; + struct { + USAGE Usage, Reserved1; + USHORT StringIndex, Reserved2; + USHORT DesignatorIndex, Reserved3; + USHORT DataIndex, Reserved4; + } NotRange; + }; +} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS; + +typedef PUCHAR PHIDP_REPORT_DESCRIPTOR; +typedef struct _HIDP_PREPARSED_DATA *PHIDP_PREPARSED_DATA; + +typedef struct _HIDP_CAPS { + USAGE Usage; + USAGE UsagePage; + USHORT InputReportByteLength; + USHORT OutputReportByteLength; + USHORT FeatureReportByteLength; + USHORT Reserved[17]; + USHORT NumberLinkCollectionNodes; + USHORT NumberInputButtonCaps; + USHORT NumberInputValueCaps; + USHORT NumberInputDataIndices; + USHORT NumberOutputButtonCaps; + USHORT NumberOutputValueCaps; + USHORT NumberOutputDataIndices; + USHORT NumberFeatureButtonCaps; + USHORT NumberFeatureValueCaps; + USHORT NumberFeatureDataIndices; +} HIDP_CAPS, *PHIDP_CAPS; + +typedef struct _HIDP_DATA { + USHORT DataIndex; + USHORT Reserved; + union { + ULONG RawValue; + BOOLEAN On; + }; +} HIDP_DATA, *PHIDP_DATA; + +typedef LONG NTSTATUS; +typedef NTSTATUS (__stdcall *pHidP_GetCaps)(PHIDP_PREPARSED_DATA, PHIDP_CAPS); +typedef NTSTATUS (__stdcall *pHidP_GetButtonCaps)(HIDP_REPORT_TYPE, PHIDP_BUTTON_CAPS, PUSHORT, PHIDP_PREPARSED_DATA); +typedef NTSTATUS (__stdcall *pHidP_GetValueCaps)(HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PUSHORT, PHIDP_PREPARSED_DATA); +typedef NTSTATUS (__stdcall *pHidP_GetData)(HIDP_REPORT_TYPE, PHIDP_DATA, PULONG, PHIDP_PREPARSED_DATA, PCHAR, ULONG); +typedef ULONG (__stdcall *pHidP_MaxDataListLength)(HIDP_REPORT_TYPE, PHIDP_PREPARSED_DATA); + +#endif + +#endif diff --git a/panda/src/device/winRawInputDevice.cxx b/panda/src/device/winRawInputDevice.cxx index dd4ecdb973..262ee515ff 100644 --- a/panda/src/device/winRawInputDevice.cxx +++ b/panda/src/device/winRawInputDevice.cxx @@ -19,151 +19,7 @@ #include #include - -// Copy definitions from hidusage.h, until we can drop support for the 7.1 SDK -typedef USHORT USAGE, *PUSAGE; - -#define HID_USAGE_PAGE_UNDEFINED ((USAGE) 0x00) -#define HID_USAGE_PAGE_GENERIC ((USAGE) 0x01) -#define HID_USAGE_PAGE_SIMULATION ((USAGE) 0x02) -#define HID_USAGE_PAGE_VR ((USAGE) 0x03) -#define HID_USAGE_PAGE_SPORT ((USAGE) 0x04) -#define HID_USAGE_PAGE_GAME ((USAGE) 0x05) -#define HID_USAGE_PAGE_KEYBOARD ((USAGE) 0x07) -#define HID_USAGE_PAGE_LED ((USAGE) 0x08) -#define HID_USAGE_PAGE_BUTTON ((USAGE) 0x09) - -#define HID_USAGE_GENERIC_POINTER ((USAGE) 0x01) -#define HID_USAGE_GENERIC_MOUSE ((USAGE) 0x02) -#define HID_USAGE_GENERIC_JOYSTICK ((USAGE) 0x04) -#define HID_USAGE_GENERIC_GAMEPAD ((USAGE) 0x05) -#define HID_USAGE_GENERIC_KEYBOARD ((USAGE) 0x06) -#define HID_USAGE_GENERIC_KEYPAD ((USAGE) 0x07) -#define HID_USAGE_GENERIC_SYSTEM_CTL ((USAGE) 0x80) - -#define HID_USAGE_GENERIC_X ((USAGE) 0x30) -#define HID_USAGE_GENERIC_Y ((USAGE) 0x31) -#define HID_USAGE_GENERIC_Z ((USAGE) 0x32) -#define HID_USAGE_GENERIC_RX ((USAGE) 0x33) -#define HID_USAGE_GENERIC_RY ((USAGE) 0x34) -#define HID_USAGE_GENERIC_RZ ((USAGE) 0x35) -#define HID_USAGE_GENERIC_SLIDER ((USAGE) 0x36) -#define HID_USAGE_GENERIC_DIAL ((USAGE) 0x37) -#define HID_USAGE_GENERIC_WHEEL ((USAGE) 0x38) -#define HID_USAGE_GENERIC_HATSWITCH ((USAGE) 0x39) - -// Copy definitions from hidpi.h, until we can drop support for the 7.1 SDK -#define HIDP_STATUS_SUCCESS ((NTSTATUS)(0x11 << 16)) - -typedef enum _HIDP_REPORT_TYPE { - HidP_Input, - HidP_Output, - HidP_Feature -} HIDP_REPORT_TYPE; - -typedef struct _HIDP_BUTTON_CAPS { - USAGE UsagePage; - UCHAR ReportID; - BOOLEAN IsAlias; - USHORT BitField; - USHORT LinkCollection; - USAGE LinkUsage; - USAGE LinkUsagePage; - BOOLEAN IsRange; - BOOLEAN IsStringRange; - BOOLEAN IsDesignatorRange; - BOOLEAN IsAbsolute; - ULONG Reserved[10]; - union { - struct { - USAGE UsageMin, UsageMax; - USHORT StringMin, StringMax; - USHORT DesignatorMin, DesignatorMax; - USHORT DataIndexMin, DataIndexMax; - } Range; - struct { - USAGE Usage, Reserved1; - USHORT StringIndex, Reserved2; - USHORT DesignatorIndex, Reserved3; - USHORT DataIndex, Reserved4; - } NotRange; - }; -} HIDP_BUTTON_CAPS, *PHIDP_BUTTON_CAPS; - -typedef struct _HIDP_VALUE_CAPS { - USAGE UsagePage; - UCHAR ReportID; - BOOLEAN IsAlias; - USHORT BitField; - USHORT LinkCollection; - USAGE LinkUsage; - USAGE LinkUsagePage; - BOOLEAN IsRange; - BOOLEAN IsStringRange; - BOOLEAN IsDesignatorRange; - BOOLEAN IsAbsolute; - BOOLEAN HasNull; - UCHAR Reserved; - USHORT BitSize; - USHORT ReportCount; - USHORT Reserved2[5]; - ULONG UnitsExp; - ULONG Units; - LONG LogicalMin, LogicalMax; - LONG PhysicalMin, PhysicalMax; - union { - struct { - USAGE UsageMin, UsageMax; - USHORT StringMin, StringMax; - USHORT DesignatorMin, DesignatorMax; - USHORT DataIndexMin, DataIndexMax; - } Range; - struct { - USAGE Usage, Reserved1; - USHORT StringIndex, Reserved2; - USHORT DesignatorIndex, Reserved3; - USHORT DataIndex, Reserved4; - } NotRange; - }; -} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS; - -typedef PUCHAR PHIDP_REPORT_DESCRIPTOR; -typedef struct _HIDP_PREPARSED_DATA *PHIDP_PREPARSED_DATA; - -typedef struct _HIDP_CAPS { - USAGE Usage; - USAGE UsagePage; - USHORT InputReportByteLength; - USHORT OutputReportByteLength; - USHORT FeatureReportByteLength; - USHORT Reserved[17]; - USHORT NumberLinkCollectionNodes; - USHORT NumberInputButtonCaps; - USHORT NumberInputValueCaps; - USHORT NumberInputDataIndices; - USHORT NumberOutputButtonCaps; - USHORT NumberOutputValueCaps; - USHORT NumberOutputDataIndices; - USHORT NumberFeatureButtonCaps; - USHORT NumberFeatureValueCaps; - USHORT NumberFeatureDataIndices; -} HIDP_CAPS, *PHIDP_CAPS; - -typedef struct _HIDP_DATA { - USHORT DataIndex; - USHORT Reserved; - union { - ULONG RawValue; - BOOLEAN On; - }; -} HIDP_DATA, *PHIDP_DATA; - -typedef LONG NTSTATUS; -typedef NTSTATUS (__stdcall *pHidP_GetCaps)(PHIDP_PREPARSED_DATA, PHIDP_CAPS); -typedef NTSTATUS (__stdcall *pHidP_GetButtonCaps)(HIDP_REPORT_TYPE, PHIDP_BUTTON_CAPS, PUSHORT, PHIDP_PREPARSED_DATA); -typedef NTSTATUS (__stdcall *pHidP_GetValueCaps)(HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PUSHORT, PHIDP_PREPARSED_DATA); -typedef NTSTATUS (__stdcall *pHidP_GetData)(HIDP_REPORT_TYPE, PHIDP_DATA, PULONG, PHIDP_PREPARSED_DATA, PCHAR, ULONG); -typedef ULONG (__stdcall *pHidP_MaxDataListLength)(HIDP_REPORT_TYPE, PHIDP_PREPARSED_DATA); +#include "phidsdi.h" static pHidP_GetCaps _HidP_GetCaps = nullptr; static pHidP_GetButtonCaps _HidP_GetButtonCaps = nullptr; From f8d7941fe808cd68c10d43f97164398f859a7c3a Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 6 Feb 2019 22:03:44 +0100 Subject: [PATCH 066/144] device: fix a bad axis mapping on Linux --- panda/src/device/evdevInputDevice.cxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/panda/src/device/evdevInputDevice.cxx b/panda/src/device/evdevInputDevice.cxx index b137888d6d..6c1a09b866 100644 --- a/panda/src/device/evdevInputDevice.cxx +++ b/panda/src/device/evdevInputDevice.cxx @@ -82,7 +82,7 @@ static const struct DeviceMapping { {0x28de, 0x1142, InputDevice::DeviceClass::unknown, QB_steam_controller}, // Jess Tech Colour Rumble Pad {0x0f30, 0x0111, InputDevice::DeviceClass::gamepad, 0}, - // Trust GXT 24 + // SPEED Link SL-6535-SBK-01 {0x0079, 0x0006, InputDevice::DeviceClass::gamepad, 0}, // 3Dconnexion Space Traveller 3D Mouse {0x046d, 0xc623, InputDevice::DeviceClass::spatial_mouse, 0}, @@ -521,7 +521,10 @@ init_device() { } break; case ABS_THROTTLE: - if (quirks & QB_rudder_from_throttle) { + if (_device_class == DeviceClass::gamepad) { + // Apparently needed for 8bitdo N30 Pro controller + axis = InputDevice::Axis::right_x; + } else if (quirks & QB_rudder_from_throttle) { axis = InputDevice::Axis::rudder; } else { axis = InputDevice::Axis::throttle; From 0ef9f9bef5548ce83881cd01d5ff2ca604c06821 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 6 Feb 2019 22:06:43 +0100 Subject: [PATCH 067/144] device: various button/axis mapping fixes in Windows raw impl Now uses a table like on Linux with the various mappings. --- panda/src/device/winRawInputDevice.cxx | 138 ++++++++++++++++--------- 1 file changed, 90 insertions(+), 48 deletions(-) diff --git a/panda/src/device/winRawInputDevice.cxx b/panda/src/device/winRawInputDevice.cxx index 262ee515ff..583ad920da 100644 --- a/panda/src/device/winRawInputDevice.cxx +++ b/panda/src/device/winRawInputDevice.cxx @@ -14,6 +14,7 @@ #include "winRawInputDevice.h" #include "gamepadButton.h" #include "mouseButton.h" +#include "buttonRegistry.h" #if defined(_WIN32) && !defined(CPPPARSER) @@ -21,6 +22,49 @@ #include #include "phidsdi.h" +enum QuirkBits : int { + // Has no trigger axes. + QB_no_analog_triggers = 1, + + // Throttle goes from -1 to 1 rather than from 0 to 1. + QB_centered_throttle = 2, + + // Throttle is reversed. + QB_reversed_throttle = 4, +}; + +// Some nonstandard gamepads have different button mappings. +static const struct DeviceMapping { + unsigned short vendor; + unsigned short product; + InputDevice::DeviceClass device_class; + int quirks; + const char *buttons[16]; +} mapping_presets[] = { + // SNES-style USB gamepad + {0x0810, 0xe501, InputDevice::DeviceClass::gamepad, QB_no_analog_triggers, + {"face_x", "face_a", "face_b", "face_y", "lshoulder", "rshoulder", "none", "none", "back", "start"} + }, + // SPEED Link SL-6535-SBK-01 + {0x0079, 0x0006, InputDevice::DeviceClass::gamepad, QB_no_analog_triggers, + {"face_y", "face_b", "face_a", "face_x", "lshoulder", "rshoulder", "ltrigger", "rtrigger", "back", "start", "lstick", "rstick"} + }, + // T.Flight Hotas X + {0x044f, 0xb108, InputDevice::DeviceClass::flight_stick, QB_centered_throttle | QB_reversed_throttle, + {0} + }, + // NVIDIA Shield Controller + {0x0955, 0x7214, InputDevice::DeviceClass::gamepad, 0, + {"face_a", "face_b", "n", "face_x", "face_y", "rshoulder", "lshoulder", "rshoulder", "e", "f", "g", "start", "h", "lstick", "rstick", "i"} + }, + {0}, +}; + +// This is our fallback button mapping, used with Xbox 360 and other devices. +static const char *default_gamepad_mapping[16] = { + "face_a", "face_b", "face_x", "face_y", "lshoulder", "rshoulder", "back", "start", "lstick", "rstick" +}; + static pHidP_GetCaps _HidP_GetCaps = nullptr; static pHidP_GetButtonCaps _HidP_GetButtonCaps = nullptr; static pHidP_GetValueCaps _HidP_GetValueCaps = nullptr; @@ -102,6 +146,9 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { _name = std::move(name); + int quirks = 0; + const char *const *gamepad_buttons = default_gamepad_mapping; + switch (info.dwType) { case RIM_TYPEMOUSE: _device_class = DeviceClass::mouse; @@ -120,7 +167,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { info.hid.usUsage == HID_USAGE_GENERIC_GAMEPAD) { _device_class = DeviceClass::gamepad; - // Flight sticks + // Various game controllers, incl. flight sticks and some gamepads } else if (info.hid.usUsagePage == HID_USAGE_PAGE_GENERIC && info.hid.usUsage == HID_USAGE_GENERIC_JOYSTICK) { _device_class = DeviceClass::flight_stick; @@ -129,11 +176,6 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { // Well, it claims to be a gamepad... _device_class = DeviceClass::gamepad; } - //TODO: better solution for this - if (_vendor_id == 0x0079 && _product_id == 0x0006) { - // Trust GXT 24 - _device_class = DeviceClass::gamepad; - } // Mice } else if (info.hid.usUsagePage == HID_USAGE_PAGE_GENERIC && @@ -162,6 +204,28 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { return false; } + if (_device_class == DeviceClass::gamepad || + _device_class == DeviceClass::flight_stick) { + // Do we have a built-in mapping? + const DeviceMapping *mapping = mapping_presets; + while (mapping->vendor != 0) { + if (info.hid.dwVendorId == mapping->vendor && + info.hid.dwProductId == mapping->product) { + _device_class = mapping->device_class; + gamepad_buttons = mapping->buttons; + quirks = mapping->quirks; + if (device_cat.is_debug()) { + device_cat.debug() + << "Using preset mapping for " << mapping->device_class + << " with VID=" << std::hex << mapping->vendor + << " PID=" << mapping->product << std::dec << "\n"; + } + break; + } + ++mapping; + } + } + // Initialize hid.dll, which provides the HID parser functions. static bool hid_initialized = false; if (!hid_initialized) { @@ -198,38 +262,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { << caps.NumberInputValueCaps << " value caps\n"; } - // Do we have a button mapping? - static const ButtonHandle gamepad_buttons_common[] = { - ButtonHandle::none(), - GamepadButton::face_a(), - GamepadButton::face_b(), - GamepadButton::face_x(), - GamepadButton::face_y(), - GamepadButton::lshoulder(), - GamepadButton::rshoulder(), - GamepadButton::start(), - GamepadButton::back(), - GamepadButton::lstick(), - GamepadButton::rstick(), - }; - const ButtonHandle *gamepad_buttons = gamepad_buttons_common; - if (_vendor_id == 0x0810 && _product_id == 0xe501) { - // SNES-style USB gamepad - static const ButtonHandle gamepad_buttons_snes[] = { - ButtonHandle::none(), - GamepadButton::face_x(), - GamepadButton::face_a(), - GamepadButton::face_b(), - GamepadButton::face_y(), - GamepadButton::lshoulder(), - GamepadButton::rshoulder(), - ButtonHandle::none(), - ButtonHandle::none(), - GamepadButton::back(), - GamepadButton::start(), - }; - gamepad_buttons = gamepad_buttons_snes; - } + ButtonRegistry *registry = ButtonRegistry::ptr(); // Prepare a mapping of data indices to button/axis indices. _indices.resize(caps.NumberInputDataIndices); @@ -270,7 +303,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { } } - nassertd(cap.Range.DataIndexMin + upper < _indices.size()) continue; + nassertd(cap.Range.DataIndexMin + upper < (int)_indices.size()) continue; // Windows will only tell us which buttons in a report are "on", so we // need to keep track of which buttons exist in which report so that we @@ -285,8 +318,10 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { switch (cap.UsagePage) { case HID_USAGE_PAGE_BUTTON: if (_device_class == DeviceClass::gamepad) { - if (usage < sizeof(gamepad_buttons_common) / sizeof(ButtonHandle)) { - handle = gamepad_buttons[usage]; + if (usage > 0 && usage - 1 < _countof(default_gamepad_mapping)) { + if (gamepad_buttons[usage - 1] != nullptr) { + handle = registry->find_button(gamepad_buttons[usage - 1]); + } } } else if (_device_class == DeviceClass::flight_stick) { if (usage > 0) { @@ -347,7 +382,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { } } - nassertd(cap.Range.DataIndexMin + upper < _indices.size()) continue; + nassertd(cap.Range.DataIndexMin + upper < (int)_indices.size()) continue; for (int j = 0; j <= upper; ++j) { USAGE usage = j + cap.Range.UsageMin; @@ -386,9 +421,17 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { break; case HID_USAGE_GENERIC_Z: if (_device_class == DeviceClass::gamepad) { - axis = Axis::left_trigger; + if ((quirks & QB_no_analog_triggers) == 0) { + axis = Axis::left_trigger; + } } else if (_device_class == DeviceClass::flight_stick) { axis = Axis::throttle; + if ((quirks & QB_reversed_throttle) != 0) { + std::swap(cap.LogicalMin, cap.LogicalMax); + } + if ((quirks & QB_centered_throttle) != 0) { + is_signed = false; + } } else { axis = Axis::z; swap(cap.LogicalMin, cap.LogicalMax); @@ -411,7 +454,9 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { break; case HID_USAGE_GENERIC_RZ: if (_device_class == DeviceClass::gamepad) { - axis = Axis::right_trigger; + if ((quirks & QB_no_analog_triggers) == 0) { + axis = Axis::right_trigger; + } } else { // Flip to match Panda's convention for heading. axis = Axis::yaw; @@ -436,10 +481,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { } int axis_index; - if (_vendor_id == 0x044f && _product_id == 0xb108 && axis == Axis::throttle) { - // T.Flight Hotas X throttle is reversed and can go backwards. - axis_index = add_axis(axis, cap.LogicalMax, cap.LogicalMin, true); - } else if (!is_signed) { + if (!is_signed) { // All axes on the weird XInput-style mappings go from -1 to 1 axis_index = add_axis(axis, cap.LogicalMin, cap.LogicalMax, true); } else { From 666568a5139b2e07f6ea30010f1ea669745fe417 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 6 Feb 2019 22:08:25 +0100 Subject: [PATCH 068/144] prc: fix recursive use of non-recursive mutex --- dtool/src/prc/configVariableBool.cxx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dtool/src/prc/configVariableBool.cxx b/dtool/src/prc/configVariableBool.cxx index 701f40c65d..27556f3f2b 100644 --- a/dtool/src/prc/configVariableBool.cxx +++ b/dtool/src/prc/configVariableBool.cxx @@ -12,6 +12,7 @@ */ #include "configVariableBool.h" +#include "mutexImpl.h" /** * Refreshes the cached value. @@ -21,7 +22,10 @@ reload_value() const { // NB. MSVC doesn't guarantee that this mutex is initialized in a // thread-safe manner. But chances are that the first time this is called // is at static init time, when there is no risk of data races. - static MutexImpl lock; + + // This needs to be a recursive mutex, because get_bool_word() may end up + // indirectly querying another bool config variable. + static ReMutexImpl lock; lock.lock(); // We check again for cache validity since another thread may have beaten From c4f52bfdfea15b9f36a5af00b0a82b25310268bb Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 6 Feb 2019 23:00:12 +0100 Subject: [PATCH 069/144] pipeline: don't require holding lock for ConditionVar.notify() As far as I know, none of the implementations strictly require this, and this may cause the waiting thread to wake up only for it to immediately have to wait for the lock again. This change brings our implementation closer to C++11 std::condition_variable semantics. --- panda/src/pipeline/conditionVarDebug.cxx | 6 ++++-- panda/src/pipeline/conditionVarFullDebug.cxx | 12 ++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/panda/src/pipeline/conditionVarDebug.cxx b/panda/src/pipeline/conditionVarDebug.cxx index bbf9ce0d22..30a12695ad 100644 --- a/panda/src/pipeline/conditionVarDebug.cxx +++ b/panda/src/pipeline/conditionVarDebug.cxx @@ -165,9 +165,9 @@ void ConditionVarDebug:: notify() { _mutex._global_lock->lock(); - Thread *current_thread = Thread::get_current_thread(); - + /* if (!_mutex.do_debug_is_locked()) { + Thread *current_thread = Thread::get_current_thread(); ostringstream ostr; ostr << *current_thread << " attempted to notify " << *this << " without holding " << _mutex; @@ -175,8 +175,10 @@ notify() { _mutex._global_lock->unlock(); return; } + */ if (thread_cat->is_spam()) { + Thread *current_thread = Thread::get_current_thread(); thread_cat.spam() << *current_thread << " notifying " << *this << "\n"; } diff --git a/panda/src/pipeline/conditionVarFullDebug.cxx b/panda/src/pipeline/conditionVarFullDebug.cxx index 746991e79c..6b8b7feaa7 100644 --- a/panda/src/pipeline/conditionVarFullDebug.cxx +++ b/panda/src/pipeline/conditionVarFullDebug.cxx @@ -165,9 +165,9 @@ void ConditionVarFullDebug:: notify() { _mutex._global_lock->lock(); - Thread *current_thread = Thread::get_current_thread(); - + /* if (!_mutex.do_debug_is_locked()) { + Thread *current_thread = Thread::get_current_thread(); ostringstream ostr; ostr << *current_thread << " attempted to notify " << *this << " without holding " << _mutex; @@ -175,8 +175,10 @@ notify() { _mutex._global_lock->unlock(); return; } + */ if (thread_cat->is_spam()) { + Thread *current_thread = Thread::get_current_thread(); thread_cat.spam() << *current_thread << " notifying " << *this << "\n"; } @@ -198,9 +200,9 @@ void ConditionVarFullDebug:: notify_all() { _mutex._global_lock->lock(); - Thread *current_thread = Thread::get_current_thread(); - + /* if (!_mutex.do_debug_is_locked()) { + Thread *current_thread = Thread::get_current_thread(); ostringstream ostr; ostr << *current_thread << " attempted to notify " << *this << " without holding " << _mutex; @@ -208,8 +210,10 @@ notify_all() { _mutex._global_lock->unlock(); return; } + */ if (thread_cat->is_spam()) { + Thread *current_thread = Thread::get_current_thread(); thread_cat.spam() << *current_thread << " notifying all " << *this << "\n"; } From 3f1bd1744b9f229b0f83a0e0415c5aec855a29f3 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 6 Feb 2019 23:01:16 +0100 Subject: [PATCH 070/144] tests: add threaded unit tests for Mutex and ConditionVar --- tests/pipeline/test_condition_var.py | 137 +++++++++++++++++++++++++++ tests/pipeline/test_mutex.py | 66 +++++++++++++ 2 files changed, 203 insertions(+) create mode 100644 tests/pipeline/test_condition_var.py diff --git a/tests/pipeline/test_condition_var.py b/tests/pipeline/test_condition_var.py new file mode 100644 index 0000000000..6aa8bcf320 --- /dev/null +++ b/tests/pipeline/test_condition_var.py @@ -0,0 +1,137 @@ +from panda3d.core import Mutex, ConditionVarFull +from panda3d import core +from direct.stdpy import thread +import pytest + + +def yield_thread(): + # Thread.force_yield() is not enough for true-threading builds, whereas + # time.sleep() does not yield in simple-thread builds. Thread.sleep() + # seems to do the job in all cases, however. + core.Thread.sleep(0.002) + + +def test_cvar_notify(): + # Just tests that notifying without waiting does no harm. + m = Mutex() + cv = ConditionVarFull(m) + + cv.notify() + cv.notify_all() + del cv + + +def test_cvar_notify_locked(): + # Tests the same thing, but with the lock held. + m = Mutex() + cv = ConditionVarFull(m) + + m.acquire() + cv.notify() + m.release() + + m.acquire() + cv.notify_all() + m.release() + del cv + + +@pytest.mark.parametrize("num_threads", [1, 2, 3, 4]) +@pytest.mark.skipif(not core.Thread.is_threading_supported(), + reason="Threading support disabled") +def test_cvar_notify_thread(num_threads): + # Tests notify() with some number of threads waiting. + m = Mutex() + cv = ConditionVarFull(m) + + # We prematurely notify, so that we can test that it's not doing anything. + m.acquire() + cv.notify() + + state = {'waiting': 0} + + def wait_thread(): + m.acquire() + state['waiting'] += 1 + cv.wait() + state['waiting'] -= 1 + m.release() + + # Start the threads, and yield to it, giving it a chance to mess up. + threads = [] + for i in range(num_threads): + thread = core.PythonThread(wait_thread, (), "", "") + thread.start(core.TP_high, True) + + # Yield until all of the threads are waiting for the condition variable. + for i in range(1000): + m.release() + yield_thread() + m.acquire() + if state['waiting'] == num_threads: + break + + assert state['waiting'] == num_threads + m.release() + + # OK, now signal it, and yield. One thread must be unblocked per notify. + for i in range(num_threads): + cv.notify() + yield_thread() + m.acquire() + assert state['waiting'] == num_threads - i - 1 + m.release() + + for thread in threads: + thread.join() + cv = None + + +@pytest.mark.parametrize("num_threads", [1, 2, 3, 4]) +@pytest.mark.skipif(not core.Thread.is_threading_supported(), + reason="Threading support disabled") +def test_cvar_notify_all_threads(num_threads): + # Tests notify_all() with some number of threads waiting. + m = Mutex() + cv = ConditionVarFull(m) + + # We prematurely notify, so that we can test that it's not doing anything. + m.acquire() + cv.notify_all() + + state = {'waiting': 0} + + def wait_thread(): + m.acquire() + state['waiting'] += 1 + cv.wait() + state['waiting'] -= 1 + m.release() + + # Start the threads, and yield to it, giving it a chance to mess up. + threads = [] + for i in range(num_threads): + thread = core.PythonThread(wait_thread, (), "", "") + thread.start(core.TP_high, True) + + # Yield until all of the threads are waiting for the condition variable. + for i in range(1000): + m.release() + yield_thread() + m.acquire() + if state['waiting'] == num_threads: + break + + assert state['waiting'] == num_threads + m.release() + + # OK, now signal it, and yield. All threads must unblock. + cv.notify_all() + yield_thread() + m.acquire() + assert state['waiting'] == 0 + m.release() + + for thread in threads: + thread.join() + cv = None diff --git a/tests/pipeline/test_mutex.py b/tests/pipeline/test_mutex.py index 2073c09efa..668d275b08 100644 --- a/tests/pipeline/test_mutex.py +++ b/tests/pipeline/test_mutex.py @@ -1,4 +1,7 @@ from panda3d.core import Mutex, ReMutex +from panda3d import core +from random import random +import pytest def test_mutex_acquire_release(): @@ -31,6 +34,69 @@ def test_mutex_try_acquire(): m.release() +@pytest.mark.skipif(not core.Thread.is_threading_supported(), + reason="Threading support disabled") +def test_mutex_contention(): + # As a smoke test for mutexes, we just spawn a bunch of threads that do a + # lot of mutexing and hope that we can catch any obvious issues with the + # mutex implementation, especially when compiling with DEBUG_THREADS. + m1 = Mutex() + m2 = Mutex() + m3 = Mutex() + m4 = Mutex() + + def thread_acq_rel(m): + for i in range(5000): + m.acquire() + m.release() + + def thread_nested(): + for i in range(5000): + m1.acquire() + m4.acquire() + m4.release() + m1.release() + + def thread_hand_over_hand(): + m1.acquire() + for i in range(5000): + m2.acquire() + m1.release() + m3.acquire() + m2.release() + m1.acquire() + m3.release() + + m1.release() + + def thread_sleep(m): + for i in range(250): + m.acquire() + core.Thread.sleep(random() * 0.003) + m.release() + + threads = [ + core.PythonThread(thread_acq_rel, (m1,), "", ""), + core.PythonThread(thread_acq_rel, (m2,), "", ""), + core.PythonThread(thread_acq_rel, (m3,), "", ""), + core.PythonThread(thread_acq_rel, (m4,), "", ""), + core.PythonThread(thread_nested, (), "", ""), + core.PythonThread(thread_nested, (), "", ""), + core.PythonThread(thread_nested, (), "", ""), + core.PythonThread(thread_hand_over_hand, (), "", ""), + core.PythonThread(thread_hand_over_hand, (), "", ""), + core.PythonThread(thread_sleep, (m1,), "", ""), + core.PythonThread(thread_sleep, (m2,), "", ""), + core.PythonThread(thread_sleep, (m3,), "", ""), + core.PythonThread(thread_sleep, (m4,), "", ""), + ] + for thread in threads: + thread.start(core.TP_normal, True) + + for thread in threads: + thread.join() + + def test_remutex_acquire_release(): m = ReMutex() m.acquire() From 7e0952e3678435af87c53a896014d83e49123ef7 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 6 Feb 2019 23:21:44 +0100 Subject: [PATCH 071/144] parser-inc: add synchapi.h and winnt.h headers --- dtool/src/parser-inc/synchapi.h | 10 ++++++++++ dtool/src/parser-inc/winnt.h | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100755 dtool/src/parser-inc/synchapi.h create mode 100755 dtool/src/parser-inc/winnt.h diff --git a/dtool/src/parser-inc/synchapi.h b/dtool/src/parser-inc/synchapi.h new file mode 100755 index 0000000000..3332ebd6e7 --- /dev/null +++ b/dtool/src/parser-inc/synchapi.h @@ -0,0 +1,10 @@ +#ifndef SYNCHAPI_H +#define SYNCHAPI_H + +#include "winnt.h" + +#define SRWLOCK_INIT RTL_SRWLOCK_INIT + +typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; + +#endif diff --git a/dtool/src/parser-inc/winnt.h b/dtool/src/parser-inc/winnt.h new file mode 100755 index 0000000000..0984c7312f --- /dev/null +++ b/dtool/src/parser-inc/winnt.h @@ -0,0 +1,16 @@ +#ifndef WINNT_H +#define WINNT_H + +typedef void *PVOID; + +typedef struct _RTL_SRWLOCK { + PVOID Ptr; +} RTL_SRWLOCK, *PRTL_SRWLOCK; + +#define RTL_SRWLOCK_INIT {0} + +typedef struct _RTL_CONDITION_VARIABLE { + PVOID Ptr; +} RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE; + +#endif From 89392f0e2dbed6044b490f9583ef94a492512050 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 6 Feb 2019 23:55:46 +0100 Subject: [PATCH 072/144] dtoolbase: new mutex and condition variable impl on Windows This uses SRWLock on Vista and above, and uses a hand-rolled implementation on Windows XP that uses Events (and a spinlock, if this is a multi-core system). Since SRWLocks aren't recursive, ReMutexWin32Impl has been added to implement recursive mutices, using old-fashioned critical sections. MutexImpl now has a constexpr constructor on all implementations. --- dtool/src/dtoolbase/mutexImpl.h | 2 +- dtool/src/dtoolbase/mutexWin32Impl.I | 42 +- dtool/src/dtoolbase/mutexWin32Impl.cxx | 376 +++++++++++++++++- dtool/src/dtoolbase/mutexWin32Impl.h | 58 ++- .../src/pipeline/conditionVarFullWin32Impl.I | 79 +--- .../src/pipeline/conditionVarFullWin32Impl.h | 10 +- panda/src/pipeline/conditionVarWin32Impl.I | 12 +- panda/src/pipeline/conditionVarWin32Impl.h | 2 +- 8 files changed, 492 insertions(+), 89 deletions(-) diff --git a/dtool/src/dtoolbase/mutexImpl.h b/dtool/src/dtoolbase/mutexImpl.h index f309634ffa..add705bc39 100644 --- a/dtool/src/dtoolbase/mutexImpl.h +++ b/dtool/src/dtoolbase/mutexImpl.h @@ -34,7 +34,7 @@ typedef MutexSpinlockImpl MutexImpl; #include "mutexWin32Impl.h" typedef MutexWin32Impl MutexImpl; -typedef MutexWin32Impl ReMutexImpl; // Win32 Mutexes are always reentrant. +typedef ReMutexWin32Impl ReMutexImpl; #define HAVE_REMUTEXIMPL 1 #elif defined(THREAD_POSIX_IMPL) diff --git a/dtool/src/dtoolbase/mutexWin32Impl.I b/dtool/src/dtoolbase/mutexWin32Impl.I index acbbd68b56..a0867d94fb 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.I +++ b/dtool/src/dtoolbase/mutexWin32Impl.I @@ -16,7 +16,11 @@ */ INLINE MutexWin32Impl:: ~MutexWin32Impl() { - DeleteCriticalSection(&_lock); + // If the lock has been contended, and we use the Windows XP implementation, + // we have a handle to close. Otherwise, this field will be null. + if (_lock[1] != nullptr) { + CloseHandle(_lock[1]); + } } /** @@ -24,7 +28,7 @@ INLINE MutexWin32Impl:: */ INLINE void MutexWin32Impl:: lock() { - EnterCriticalSection(&_lock); + _funcs._lock(_lock); } /** @@ -32,13 +36,45 @@ lock() { */ INLINE bool MutexWin32Impl:: try_lock() { - return (TryEnterCriticalSection(&_lock) != 0); + return _funcs._try_lock(_lock); } /** * */ INLINE void MutexWin32Impl:: +unlock() { + _funcs._unlock(_lock); +} + +/** + * + */ +INLINE ReMutexWin32Impl:: +~ReMutexWin32Impl() { + DeleteCriticalSection(&_lock); +} + +/** + * + */ +INLINE void ReMutexWin32Impl:: +lock() { + EnterCriticalSection(&_lock); +} + +/** + * + */ +INLINE bool ReMutexWin32Impl:: +try_lock() { + return (TryEnterCriticalSection(&_lock) != 0); +} + +/** + * + */ +INLINE void ReMutexWin32Impl:: unlock() { LeaveCriticalSection(&_lock); } diff --git a/dtool/src/dtoolbase/mutexWin32Impl.cxx b/dtool/src/dtoolbase/mutexWin32Impl.cxx index 594f6c0962..c544555db3 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.cxx +++ b/dtool/src/dtoolbase/mutexWin32Impl.cxx @@ -13,16 +13,384 @@ #include "selectThreadImpl.h" -#ifdef WIN32_VC +#if defined(WIN32_VC) && !defined(CPPPARSER) #include "mutexWin32Impl.h" +// If this is true, we will use SRWLock on Windows Vista and above instead of +// our own implementation. +static const bool prefer_srwlock = true; + +// These configure our own Windows XP implementation. +static const uintptr_t lock_bit = 0x40000000; +static const unsigned int spin_count = 4000; + +// This gets set to spin_count if we are on a multi-core system. +static unsigned int effective_spin_count = 0; + +/** + * Windows XP implementation of lock(), which uses a combination of a spinlock + * and an event. + */ +static void __stdcall lock_xp(volatile PVOID *lock) { + // In the Windows XP case, lock consists of two words: the first one is a + // number of waiters plus a bit to indicate that it is locked, the second + // one is the handle of an event that is created in case of contention. + // The first word can be in the following states: + // + // lock bit | waiters | meaning + // ---------|---------|--------- + // unset | 0 | unlocked + // set | 0 | locked, nobody waiting on event + // set | >0 | locked, at least one thread waiting on event + // unset | >0 | handing off lock to one of waiters + // + // The last state is a little subtle: at this point, the thread that was + // holding the lock has stopped holding it, but is about to fire off a + // signal to a waiting thread, which will attempt to grab the lock. In this + // case, the waiting thread has first dibs on the lock, and any new threads + // will still treat it as locked and wait until there are no more waiters. + + // First try to acquire the lock without suspending the thread. This only + // works if the waiter count is 0; this way, we give priority to threads + // that are already waiting for the event. + if (InterlockedCompareExchangePointer(lock, (void *)lock_bit, nullptr) == nullptr) { + // Got the lock on the first try. + return; + } + + // On multi-core systems, we keep trying for the configured spin_count. + const unsigned int max_spins = effective_spin_count; + for (unsigned int spins = 0; spins < max_spins; ++spins) { + if (InterlockedCompareExchangePointer(lock, (void *)lock_bit, nullptr) == nullptr) { + // We managed to acquire the lock. + return; + } + + // Emit the pause instruction. This is NOT a thread yield. + YieldProcessor(); + } + + // Looks like we might have to go to sleep for a while using an event. + HANDLE event = lock[1]; + if (event == nullptr) { + // We don't have an event yet. Create an auto-reset event. + HANDLE new_event = CreateEvent(nullptr, false, false, nullptr); + while (new_event == nullptr) { + // Hmm, out of memory? Just yield to another thread for now until the + // lock is either freed or until we can create an event. + Sleep(1); + if (InterlockedCompareExchangePointer(lock, (void *)lock_bit, nullptr) == 0) { + return; + } + new_event = CreateEvent(nullptr, false, false, nullptr); + } + + // Push the new event. + event = InterlockedCompareExchangePointer(lock + 1, new_event, nullptr); + if (event == nullptr) { + // Set successfully. + event = new_event; + } else { + // Another thread created an event; delete ours and use that one instead. + CloseHandle(new_event); + } + } + + // OK, now we have an event. We need to let the unlock() function know that + // we are waiting. + while (true) { + uintptr_t waiters = (uintptr_t)lock[0]; + if (waiters == 0) { + // It became unlocked while we were creating an event. Quick, grab it. + if (InterlockedCompareExchangePointer(lock, (void *)lock_bit, nullptr) == nullptr) { + return; + } + } + + // If the lock bit gets unset while we try this, just keep trying. It + // would be dangerous to increment this while the lock bit is unset. + waiters |= lock_bit; + uintptr_t new_waiters = (uintptr_t)InterlockedCompareExchangePointer(lock, (void *)(waiters + 1), (void *)waiters); + if (new_waiters == waiters) { + // Made the change successfully. + break; + } else if (new_waiters == 0) { + // It just became unlocked. Quick, grab it. + if (InterlockedCompareExchangePointer(lock, (void *)lock_bit, nullptr) == nullptr) { + return; + } + } + YieldProcessor(); + } + + // Sleep well, thread. + while (true) { + WaitForSingleObjectEx(event, INFINITE, FALSE); + + // We were woken up. Does that mean the lock can be ours? + while (true) { + uintptr_t waiters = (uintptr_t)lock[0]; + if (waiters & lock_bit) { + // False alarm. Go back to sleep. + break; + } + assert(waiters > 0); + + // Grab the lock immediately, and simultaneously tell it that we are no + // longer waiting. + uintptr_t new_waiters = (uintptr_t)InterlockedCompareExchangePointer(lock, (void *)((waiters - 1) | lock_bit), (void *)waiters); + if (new_waiters == waiters) { + // The lock is ours. + return; + } else if (new_waiters & lock_bit) { + // Another thread beat us to it. Go back to sleep. + break; + } + YieldProcessor(); + } + } + + // Never supposed to get here. + assert(false); +} + +/** + * Windows XP implementation of try_lock(). + */ +static BOOL __stdcall try_lock_xp(volatile PVOID *lock) { + return (InterlockedCompareExchangePointer(lock, (void *)lock_bit, nullptr) == nullptr); +} + +/** + * Windows XP implementation of unlock(). + */ +static void __stdcall unlock_xp(volatile PVOID *lock) { + // Clear the lock flag. +#ifdef _WIN64 + uintptr_t waiters = _InterlockedAnd64((volatile __int64 *)lock, ~lock_bit); +#else + uintptr_t waiters = _InterlockedAnd((volatile long *)lock, ~lock_bit); +#endif + + // If this triggers, the lock wasn't held to begin with. + assert((waiters & lock_bit) != 0); + + // Have any threads begun to sleep (or are about to) waiting for this lock? + if ((waiters & ~lock_bit) == 0) { + // No contention, nothing to do. + return; + } else { + // By signalling the auto-resetting event, we wake up one waiting thread. + HANDLE event = lock[1]; + assert(event != nullptr); + SetEvent(event); + } +} + +/** + * Windows XP implementation to wait for a condition variable. + */ +static BOOL __stdcall +cvar_wait_xp(volatile PVOID *cvar, volatile PVOID *lock, DWORD timeout, ULONG) { + // Increment the number of waiters. +#ifdef _WIN64 + _InterlockedIncrement64((volatile __int64 *)cvar); +#else + _InterlockedIncrement((volatile long *)cvar); +#endif + + // Make sure we have two events created: one auto-reset event and one + // manual-reset, to handle signal and broadcast, respectively. + if (cvar[1] == nullptr) { + cvar[1] = CreateEvent(nullptr, false, false, nullptr); + } + if (cvar[2] == nullptr) { + cvar[2] = CreateEvent(nullptr, true, false, nullptr); + } + + // It's ok to release the external_mutex here since Win32 manual-reset + // events maintain state when used with SetEvent(). This avoids the "lost + // wakeup" bug... + unlock_xp(lock); + + // Wait for either event to become signaled due to notify() being called or + // notify_all() being called. + int result = WaitForMultipleObjects(2, (const HANDLE *)(cvar + 1), FALSE, timeout); + + // Decrement the counter. If it reached zero, we were the last waiter. +#ifdef _WIN64 + bool nonzero = (_InterlockedDecrement64((volatile __int64 *)cvar) != 0); +#else + bool nonzero = (_InterlockedDecrement((volatile long *)cvar) != 0); +#endif + bool last_waiter = (result == WAIT_OBJECT_0 + 1 && !nonzero); + + // Some thread called notify_all(). + if (last_waiter) { + // We're the last waiter to be notified or to stop waiting, so reset the + // manual event. + ResetEvent(cvar[2]); + } + + // Reacquire the . + lock_xp(lock); + return TRUE; +} + +/** + * Wakes one thread waiting for a condition variable. + */ +static void __stdcall +cvar_notify_one_xp(volatile PVOID *cvar) { + // If there are any waiters, signal one of them to wake up by signalling the + // auto-reset event. + if ((uintptr_t)cvar[0] > 0) { + SetEvent(cvar[1]); + } +} + +/** + * Wakes all threads waiting for a condition variable. + */ +static void __stdcall +cvar_notify_all_xp(volatile PVOID *cvar) { + // If there are any waiters, signal the manual-reset event, which will be + // reset by the last thread to wake up. + if ((uintptr_t)cvar[0] > 0) { + SetEvent(cvar[2]); + } +} + +/** + * This is put initially in the _lock slot; it makes sure that the lock + * functions get initialized the first time someone tries to grab a lock. + */ +void __stdcall MutexWin32Impl:: +lock_initially(volatile PVOID *lock) { + MutexWin32Impl::init_lock_funcs(); + MutexWin32Impl::_funcs._lock(lock); +} + +/** + * This is put initially in the _try_lock slot; it makes sure that the lock + * functions get initialized the first time someone tries to grab a lock. + */ +BOOL __stdcall MutexWin32Impl:: +try_lock_initially(volatile PVOID *lock) { + MutexWin32Impl::init_lock_funcs(); + return MutexWin32Impl::_funcs._try_lock(lock); +} + +#ifndef NDEBUG +/** + * This gets put initially in the _unlock slot and should never be called, + * since the initial lock/try_lock implementation will replace the pointers. + */ +void __stdcall MutexWin32Impl:: +unlock_initially(volatile PVOID *) { + std::cerr << "Attempt to release a mutex at static init time before acquiring it!\n"; + assert(false); +} +#endif + +/** + * Does nothing. + */ +static void __stdcall +noop(volatile PVOID *) { +} + +// We initially set the function pointers to functions that do initialization +// first. +MutexWin32Impl::LockFunctions MutexWin32Impl::_funcs = { + &MutexWin32Impl::lock_initially, + &MutexWin32Impl::try_lock_initially, +#ifndef NDEBUG + &MutexWin32Impl::unlock_initially, +#else + &noop, +#endif + + &cvar_wait_xp, +#ifndef NDEBUG + &MutexWin32Impl::unlock_initially, + &MutexWin32Impl::unlock_initially, +#else + &noop, + &noop, +#endif +}; + +/** + * Called the first time a lock is grabbed. + */ +void MutexWin32Impl:: +init_lock_funcs() { + if (MutexWin32Impl::_funcs._lock != &MutexWin32Impl::lock_initially) { + // Already initialized. + return; + } + + // We don't need to be very thread safe here. This can only ever be called + // at static init time, when there is still only one thread. + if (prefer_srwlock) { + HMODULE module = GetModuleHandleA("kernel32"); + if (module != nullptr) { + _funcs._lock = (LockFunc)GetProcAddress(module, "AcquireSRWLockExclusive"); + _funcs._try_lock = (TryLockFunc)GetProcAddress(module, "TryAcquireSRWLockExclusive"); + _funcs._unlock = (LockFunc)GetProcAddress(module, "ReleaseSRWLockExclusive"); + _funcs._cvar_wait = (CondWaitFunc)GetProcAddress(module, "SleepConditionVariableSRW"); + _funcs._cvar_notify_one = (LockFunc)GetProcAddress(module, "WakeConditionVariable"); + _funcs._cvar_notify_all = (LockFunc)GetProcAddress(module, "WakeAllConditionVariable"); + if (_funcs._lock != nullptr && + _funcs._try_lock != nullptr && + _funcs._unlock != nullptr && + _funcs._cvar_wait != nullptr && + _funcs._cvar_notify_one != nullptr && + _funcs._cvar_notify_all != nullptr) { + return; + } + } + } + + // Fall back to our custom Event-based implementation on Windows XP. + _funcs._lock = &lock_xp; + _funcs._try_lock = &try_lock_xp; + _funcs._unlock = &unlock_xp; + _funcs._cvar_wait = &cvar_wait_xp; + _funcs._cvar_notify_one = &cvar_notify_one_xp; + _funcs._cvar_notify_all = &cvar_notify_all_xp; + + // Are we on a multi-core system? If so, enable the spinlock. + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + if (sysinfo.dwNumberOfProcessors > 1) { + effective_spin_count = spin_count; + } else { + effective_spin_count = 0; + } +} + +/** + * Ensures that the lock functions are initialized at static init time. This + * prevents us from having to implement synchronization in our initialization. + */ +class LockFuncsInitializer { +public: + LockFuncsInitializer() { + MutexWin32Impl::init_lock_funcs(); + } +}; + +static LockFuncsInitializer _lock_funcs_init; + /** * */ -MutexWin32Impl:: -MutexWin32Impl() { - InitializeCriticalSectionAndSpinCount(&_lock, 4000); +ReMutexWin32Impl:: +ReMutexWin32Impl() { + InitializeCriticalSectionAndSpinCount(&_lock, spin_count); } #endif // WIN32_VC diff --git a/dtool/src/dtoolbase/mutexWin32Impl.h b/dtool/src/dtoolbase/mutexWin32Impl.h index 550d4944ab..9b34973b1d 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.h +++ b/dtool/src/dtoolbase/mutexWin32Impl.h @@ -24,11 +24,12 @@ #include /** - * Uses Windows native calls to implement a mutex. + * Uses SRWLock on Vista and above to implement a mutex. Older versions of + * Windows fall back to a combination of a spinlock and an Event object. */ class EXPCL_DTOOL_DTOOLBASE MutexWin32Impl { public: - MutexWin32Impl(); + constexpr MutexWin32Impl() = default; MutexWin32Impl(const MutexWin32Impl ©) = delete; INLINE ~MutexWin32Impl(); @@ -39,12 +40,63 @@ public: INLINE bool try_lock(); INLINE void unlock(); + static void init_lock_funcs(); + private: - CRITICAL_SECTION _lock; +#ifndef CPPPARSER + // Store function pointers; these point directly to the SRWLock Win32 API + // functions on Vista and above, or to our own implementation on Windows XP. + typedef void (__stdcall *LockFunc)(volatile PVOID *lock); + typedef BOOL (__stdcall *TryLockFunc)(volatile PVOID *lock); + typedef BOOL (__stdcall *CondWaitFunc)(volatile PVOID *cvar, volatile PVOID *lock, DWORD, ULONG); + + struct LockFunctions { + LockFunc _lock; + TryLockFunc _try_lock; + LockFunc _unlock; + + CondWaitFunc _cvar_wait; + LockFunc _cvar_notify_one; + LockFunc _cvar_notify_all; + }; + + static LockFunctions _funcs; + + static void __stdcall lock_initially(volatile PVOID *lock); + static BOOL __stdcall try_lock_initially(volatile PVOID *lock); + static void __stdcall unlock_initially(volatile PVOID *lock); +#endif + +private: + // In the SRWLock implementation, only the first field is used. On Windows + // XP, the first field contains a waiter count and lock bit, and the second + // field contains an Event handle if contention has occurred. + volatile PVOID _lock[2] = {nullptr, nullptr}; + friend class ConditionVarWin32Impl; friend class ConditionVarFullWin32Impl; }; +/** + * Uses CRITICAL_SECTION to implement a recursive mutex. + */ +class EXPCL_DTOOL_DTOOLBASE ReMutexWin32Impl { +public: + ReMutexWin32Impl(); + ReMutexWin32Impl(const ReMutexWin32Impl ©) = delete; + INLINE ~ReMutexWin32Impl(); + + ReMutexWin32Impl &operator = (const ReMutexWin32Impl ©) = delete; + +public: + INLINE void lock(); + INLINE bool try_lock(); + INLINE void unlock(); + +private: + CRITICAL_SECTION _lock; +}; + #include "mutexWin32Impl.I" #endif // WIN32_VC diff --git a/panda/src/pipeline/conditionVarFullWin32Impl.I b/panda/src/pipeline/conditionVarFullWin32Impl.I index 386a9d5784..62e8d04e06 100644 --- a/panda/src/pipeline/conditionVarFullWin32Impl.I +++ b/panda/src/pipeline/conditionVarFullWin32Impl.I @@ -15,14 +15,7 @@ * */ INLINE ConditionVarFullWin32Impl:: -ConditionVarFullWin32Impl(MutexWin32Impl &mutex) { - _external_mutex = &mutex._lock; - - // Create an auto-reset event and a manual-reset event. - _event_signal = CreateEvent(nullptr, false, false, nullptr); - _event_broadcast = CreateEvent(nullptr, true, false, nullptr); - - _waiters_count = 0; +ConditionVarFullWin32Impl(MutexWin32Impl &mutex) : _mutex(mutex) { } /** @@ -30,8 +23,14 @@ ConditionVarFullWin32Impl(MutexWin32Impl &mutex) { */ INLINE ConditionVarFullWin32Impl:: ~ConditionVarFullWin32Impl() { - CloseHandle(_event_signal); - CloseHandle(_event_broadcast); + // These fields are only set in the Windows XP implementation, when these + // both contain events. + if (_cvar[1] != nullptr) { + CloseHandle(_cvar[1]); + } + if (_cvar[2] != nullptr) { + CloseHandle(_cvar[2]); + } } /** @@ -39,29 +38,7 @@ INLINE ConditionVarFullWin32Impl:: */ INLINE void ConditionVarFullWin32Impl:: wait() { - AtomicAdjust::inc(_waiters_count); - - // It's ok to release the external_mutex here since Win32 manual-reset - // events maintain state when used with SetEvent(). This avoids the "lost - // wakeup" bug... - LeaveCriticalSection(_external_mutex); - - // Wait for either event to become signaled due to notify() being called or - // notify_all() being called. - int result = WaitForMultipleObjects(2, &_event_signal, FALSE, INFINITE); - - bool nonzero = AtomicAdjust::dec(_waiters_count); - bool last_waiter = (result == WAIT_OBJECT_0 + 1 && !nonzero); - - // Some thread called notify_all(). - if (last_waiter) { - // We're the last waiter to be notified or to stop waiting, so reset the - // manual event. - ResetEvent(_event_broadcast); - } - - // Reacquire the . - EnterCriticalSection(_external_mutex); + MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, INFINITE, 0); } /** @@ -69,29 +46,7 @@ wait() { */ INLINE void ConditionVarFullWin32Impl:: wait(double timeout) { - AtomicAdjust::inc(_waiters_count); - - // It's ok to release the external_mutex here since Win32 manual-reset - // events maintain state when used with SetEvent(). This avoids the "lost - // wakeup" bug... - LeaveCriticalSection(_external_mutex); - - // Wait for either event to become signaled due to notify() being called or - // notify_all() being called. - int result = WaitForMultipleObjects(2, &_event_signal, FALSE, (DWORD)(timeout * 1000.0)); - - bool nonzero = AtomicAdjust::dec(_waiters_count); - bool last_waiter = (result == WAIT_OBJECT_0 + 1 && !nonzero); - - // Some thread called notify_all(). - if (last_waiter) { - // We're the last waiter to be notified or to stop waiting, so reset the - // manual event. - ResetEvent(_event_broadcast); - } - - // Reacquire the . - EnterCriticalSection(_external_mutex); + MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, (DWORD)(timeout * 1000.0), 0); } /** @@ -99,11 +54,7 @@ wait(double timeout) { */ INLINE void ConditionVarFullWin32Impl:: notify() { - bool have_waiters = AtomicAdjust::get(_waiters_count) > 0; - - if (have_waiters) { - SetEvent(_event_signal); - } + MutexWin32Impl::_funcs._cvar_notify_one(_cvar); } /** @@ -111,9 +62,5 @@ notify() { */ INLINE void ConditionVarFullWin32Impl:: notify_all() { - bool have_waiters = AtomicAdjust::get(_waiters_count) > 0; - - if (have_waiters) { - SetEvent(_event_broadcast); - } + MutexWin32Impl::_funcs._cvar_notify_all(_cvar); } diff --git a/panda/src/pipeline/conditionVarFullWin32Impl.h b/panda/src/pipeline/conditionVarFullWin32Impl.h index a42d4d86a8..5c621412e7 100644 --- a/panda/src/pipeline/conditionVarFullWin32Impl.h +++ b/panda/src/pipeline/conditionVarFullWin32Impl.h @@ -50,10 +50,12 @@ public: INLINE void notify_all(); private: - CRITICAL_SECTION *_external_mutex; - HANDLE _event_signal; - HANDLE _event_broadcast; - TVOLATILE AtomicAdjust::Integer _waiters_count; + MutexWin32Impl &_mutex; + + // On Windows XP, the first field contains a Signal (auto-reset) event, + // the second field a broadcast (manual reset) event, third a waiter count. + // On Windows Vista and above, the first contains a PCONDITION_VARIABLE. + volatile PVOID _cvar[3] = {nullptr, nullptr, nullptr}; }; #include "conditionVarFullWin32Impl.I" diff --git a/panda/src/pipeline/conditionVarWin32Impl.I b/panda/src/pipeline/conditionVarWin32Impl.I index 5994c638d5..82ba9dea39 100644 --- a/panda/src/pipeline/conditionVarWin32Impl.I +++ b/panda/src/pipeline/conditionVarWin32Impl.I @@ -15,9 +15,7 @@ * */ INLINE ConditionVarWin32Impl:: -ConditionVarWin32Impl(MutexWin32Impl &mutex) { - _external_mutex = &mutex._lock; - +ConditionVarWin32Impl(MutexWin32Impl &mutex) : _mutex(mutex) { // Create an auto-reset event. _event_signal = CreateEvent(nullptr, false, false, nullptr); } @@ -35,12 +33,12 @@ INLINE ConditionVarWin32Impl:: */ INLINE void ConditionVarWin32Impl:: wait() { - LeaveCriticalSection(_external_mutex); + _mutex.unlock(); DWORD result = WaitForSingleObject(_event_signal, INFINITE); nassertv(result == WAIT_OBJECT_0); - EnterCriticalSection(_external_mutex); + _mutex.lock(); } /** @@ -48,12 +46,12 @@ wait() { */ INLINE void ConditionVarWin32Impl:: wait(double timeout) { - LeaveCriticalSection(_external_mutex); + _mutex.unlock(); DWORD result = WaitForSingleObject(_event_signal, (DWORD)(timeout * 1000.0)); nassertv(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT); - EnterCriticalSection(_external_mutex); + _mutex.lock(); } /** diff --git a/panda/src/pipeline/conditionVarWin32Impl.h b/panda/src/pipeline/conditionVarWin32Impl.h index 7ed6513d6e..a0c4d882c7 100644 --- a/panda/src/pipeline/conditionVarWin32Impl.h +++ b/panda/src/pipeline/conditionVarWin32Impl.h @@ -44,7 +44,7 @@ public: INLINE void notify(); private: - CRITICAL_SECTION *_external_mutex; + MutexWin32Impl &_mutex; HANDLE _event_signal; }; From 96bb90b5e9f01109abe307adb27fde776673c6d8 Mon Sep 17 00:00:00 2001 From: tc Date: Thu, 7 Feb 2019 22:18:10 +0100 Subject: [PATCH 073/144] cocoa: guarantee 24bit depth when Config.prc has `depth-bits` set to `1` Checks if the value of Config.prc for `depth-bits` is `1` and sets it manually to 24. This prevents getting a 16 bit depth buffer on macos Intended to address #501 Closes #551 --- panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm b/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm index aac8beb033..357582180b 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm @@ -248,8 +248,17 @@ choose_pixel_format(const FrameBufferProperties &properties, attribs.push_back(aux_buffers); attribs.push_back(NSOpenGLPFAColorSize); attribs.push_back(properties.get_color_bits()); + + // Set the depth buffer bits to 24 manually when 1 is requested. + // This prevents getting a depth buffer of only 16 bits when requesting 1. attribs.push_back(NSOpenGLPFADepthSize); - attribs.push_back(properties.get_depth_bits()); + if (properties.get_depth_bits() == 1) { + attribs.push_back(24); + } + else { + attribs.push_back(properties.get_depth_bits()); + } + attribs.push_back(NSOpenGLPFAStencilSize); attribs.push_back(properties.get_stencil_bits()); From 3875cc8259eb5aa61d767410b5e17dc3238433e1 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 7 Feb 2019 22:28:04 +0100 Subject: [PATCH 074/144] device: add proper mapping for 8bitdo N30 Pro Controller on Linux --- panda/src/device/evdevInputDevice.cxx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/panda/src/device/evdevInputDevice.cxx b/panda/src/device/evdevInputDevice.cxx index 6c1a09b866..4ebbc55498 100644 --- a/panda/src/device/evdevInputDevice.cxx +++ b/panda/src/device/evdevInputDevice.cxx @@ -84,6 +84,8 @@ static const struct DeviceMapping { {0x0f30, 0x0111, InputDevice::DeviceClass::gamepad, 0}, // SPEED Link SL-6535-SBK-01 {0x0079, 0x0006, InputDevice::DeviceClass::gamepad, 0}, + // 8bitdo N30 Pro Controller + {0x2dc8, 0x9001, InputDevice::DeviceClass::gamepad, QB_rstick_from_z}, // 3Dconnexion Space Traveller 3D Mouse {0x046d, 0xc623, InputDevice::DeviceClass::spatial_mouse, 0}, // 3Dconnexion Space Pilot 3D Mouse @@ -521,10 +523,7 @@ init_device() { } break; case ABS_THROTTLE: - if (_device_class == DeviceClass::gamepad) { - // Apparently needed for 8bitdo N30 Pro controller - axis = InputDevice::Axis::right_x; - } else if (quirks & QB_rudder_from_throttle) { + if (quirks & QB_rudder_from_throttle) { axis = InputDevice::Axis::rudder; } else { axis = InputDevice::Axis::throttle; From 33d11dba27730c61033327fc68c28d43bdc25339 Mon Sep 17 00:00:00 2001 From: tc Date: Fri, 8 Feb 2019 13:20:46 +0100 Subject: [PATCH 075/144] ParticlePanel: fixed an issue that prevented saving with Python 3 Since in Python 3 `str == bytes` no longer holds true, I modified the source to write a text file, which it actually is, instead of a binary file. Closes #553 Fixes #543 --- direct/src/particles/ParticleEffect.py | 65 ++++++++++++-------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/direct/src/particles/ParticleEffect.py b/direct/src/particles/ParticleEffect.py index c58b7b4d46..f801432b7e 100644 --- a/direct/src/particles/ParticleEffect.py +++ b/direct/src/particles/ParticleEffect.py @@ -163,44 +163,41 @@ class ParticleEffect(NodePath): def saveConfig(self, filename): filename = Filename(filename) - f = open(filename.toOsSpecific(), 'wb') - # Add a blank line - f.write('\n') + with open(filename.toOsSpecific(), 'w') as f: + # Add a blank line + f.write('\n') - # Make sure we start with a clean slate - f.write('self.reset()\n') + # Make sure we start with a clean slate + f.write('self.reset()\n') - pos = self.getPos() - hpr = self.getHpr() - scale = self.getScale() - f.write('self.setPos(%0.3f, %0.3f, %0.3f)\n' % - (pos[0], pos[1], pos[2])) - f.write('self.setHpr(%0.3f, %0.3f, %0.3f)\n' % - (hpr[0], hpr[1], hpr[2])) - f.write('self.setScale(%0.3f, %0.3f, %0.3f)\n' % - (scale[0], scale[1], scale[2])) + pos = self.getPos() + hpr = self.getHpr() + scale = self.getScale() + f.write('self.setPos(%0.3f, %0.3f, %0.3f)\n' % + (pos[0], pos[1], pos[2])) + f.write('self.setHpr(%0.3f, %0.3f, %0.3f)\n' % + (hpr[0], hpr[1], hpr[2])) + f.write('self.setScale(%0.3f, %0.3f, %0.3f)\n' % + (scale[0], scale[1], scale[2])) - # Save all the particles to file - num = 0 - for p in list(self.particlesDict.values()): - target = 'p%d' % num - num = num + 1 - f.write(target + ' = Particles.Particles(\'%s\')\n' % p.getName()) - p.printParams(f, target) - f.write('self.addParticles(%s)\n' % target) + # Save all the particles to file + num = 0 + for p in list(self.particlesDict.values()): + target = 'p%d' % num + num = num + 1 + f.write(target + ' = Particles.Particles(\'%s\')\n' % p.getName()) + p.printParams(f, target) + f.write('self.addParticles(%s)\n' % target) - # Save all the forces to file - num = 0 - for fg in list(self.forceGroupDict.values()): - target = 'f%d' % num - num = num + 1 - f.write(target + ' = ForceGroup.ForceGroup(\'%s\')\n' % \ - fg.getName()) - fg.printParams(f, target) - f.write('self.addForceGroup(%s)\n' % target) - - # Close the file - f.close() + # Save all the forces to file + num = 0 + for fg in list(self.forceGroupDict.values()): + target = 'f%d' % num + num = num + 1 + f.write(target + ' = ForceGroup.ForceGroup(\'%s\')\n' % \ + fg.getName()) + fg.printParams(f, target) + f.write('self.addForceGroup(%s)\n' % target) def loadConfig(self, filename): data = vfs.readFile(filename, 1) From f741c9476f2d32a846562819e3a9b3a4961f965c Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 10 Feb 2019 16:19:24 +0100 Subject: [PATCH 076/144] display: fix lighting being disabled when only AmbientLight is on --- panda/src/display/graphicsStateGuardian.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 93a3f36651..233d47bc09 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -2823,6 +2823,12 @@ do_issue_light() { } } else { + // Don't forget to still enable lighting if we have only an ambient light. + if (!_lighting_enabled) { + enable_lighting(true); + _lighting_enabled = true; + } + set_ambient_light(target_light->get_ambient_contribution()); } From ab569916b1f204d45308c5efc903f10900b52fc3 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 9 Feb 2019 22:54:17 +0100 Subject: [PATCH 077/144] Disable WinXP mutex emulation when _WIN32_WINNT >= 0x0600 --- dtool/src/dtoolbase/mutexWin32Impl.cxx | 36 +++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/dtool/src/dtoolbase/mutexWin32Impl.cxx b/dtool/src/dtoolbase/mutexWin32Impl.cxx index c544555db3..4b0e63a357 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.cxx +++ b/dtool/src/dtoolbase/mutexWin32Impl.cxx @@ -17,13 +17,18 @@ #include "mutexWin32Impl.h" +// The number of spins to do before suspending the thread. +static const unsigned int spin_count = 4000; + +// Only compile the below nonsense if we're not compiling for a Vista minimum. +#if _WIN32_WINNT < 0x0600 + // If this is true, we will use SRWLock on Windows Vista and above instead of // our own implementation. static const bool prefer_srwlock = true; // These configure our own Windows XP implementation. static const uintptr_t lock_bit = 0x40000000; -static const unsigned int spin_count = 4000; // This gets set to spin_count if we are on a multi-core system. static unsigned int effective_spin_count = 0; @@ -262,6 +267,8 @@ cvar_notify_all_xp(volatile PVOID *cvar) { } } +#endif // _WIN32_WINNT < 0x0600 + /** * This is put initially in the _lock slot; it makes sure that the lock * functions get initialized the first time someone tries to grab a lock. @@ -282,17 +289,29 @@ try_lock_initially(volatile PVOID *lock) { return MutexWin32Impl::_funcs._try_lock(lock); } -#ifndef NDEBUG /** * This gets put initially in the _unlock slot and should never be called, * since the initial lock/try_lock implementation will replace the pointers. */ void __stdcall MutexWin32Impl:: unlock_initially(volatile PVOID *) { +#if !defined(NDEBUG) || defined(DEBUG_THREADS) std::cerr << "Attempt to release a mutex at static init time before acquiring it!\n"; assert(false); -} #endif +} + +/** + * Same as above for condition variables. + */ +static BOOL __stdcall +cvar_wait_initially(volatile PVOID *cvar, volatile PVOID *lock, DWORD timeout, ULONG) { +#if !defined(NDEBUG) || defined(DEBUG_THREADS) + std::cerr << "Attempt to wait for condition variable at static init time before acquiring mutex!\n"; + assert(false); +#endif + return FALSE; +} /** * Does nothing. @@ -312,7 +331,7 @@ MutexWin32Impl::LockFunctions MutexWin32Impl::_funcs = { &noop, #endif - &cvar_wait_xp, + &cvar_wait_initially, #ifndef NDEBUG &MutexWin32Impl::unlock_initially, &MutexWin32Impl::unlock_initially, @@ -332,6 +351,14 @@ init_lock_funcs() { return; } +#if _WIN32_WINNT >= 0x0600 + _funcs._lock = (LockFunc)AcquireSRWLockExclusive; + _funcs._try_lock = (TryLockFunc)TryAcquireSRWLockExclusive; + _funcs._unlock = (LockFunc)ReleaseSRWLockExclusive; + _funcs._cvar_wait = (CondWaitFunc)SleepConditionVariableSRW; + _funcs._cvar_notify_one = (LockFunc)WakeConditionVariable; + _funcs._cvar_notify_all = (LockFunc)WakeAllConditionVariable; +#else // We don't need to be very thread safe here. This can only ever be called // at static init time, when there is still only one thread. if (prefer_srwlock) { @@ -370,6 +397,7 @@ init_lock_funcs() { } else { effective_spin_count = 0; } +#endif // _WIN32_WINNT < 0x0600 } /** From fb5191e812ff157fa7a033c233c2f9322f37ad6b Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 11 Feb 2019 15:29:35 +0100 Subject: [PATCH 078/144] pipeline: unify ConditionVarFull and ConditionVar See #550. Now that we use the Vista API for condition variables, the only place where the distinction is still relevant is Windows XP, and it's just not worth it for that one corner case. --- dtool/src/dtoolbase/mutexWin32Impl.h | 1 - panda/src/event/asyncFuture.h | 1 - panda/src/pipeline/conditionVar.h | 10 +- panda/src/pipeline/conditionVarDebug.cxx | 41 ++- panda/src/pipeline/conditionVarDebug.h | 1 + panda/src/pipeline/conditionVarDirect.I | 15 +- panda/src/pipeline/conditionVarDirect.h | 1 + panda/src/pipeline/conditionVarFull.I | 40 --- panda/src/pipeline/conditionVarFull.cxx | 14 -- panda/src/pipeline/conditionVarFull.h | 42 +--- panda/src/pipeline/conditionVarFullDebug.I | 20 -- panda/src/pipeline/conditionVarFullDebug.cxx | 234 ------------------ panda/src/pipeline/conditionVarFullDebug.h | 64 ----- panda/src/pipeline/conditionVarFullDirect.I | 103 -------- panda/src/pipeline/conditionVarFullDirect.cxx | 27 -- panda/src/pipeline/conditionVarFullDirect.h | 64 ----- .../src/pipeline/conditionVarFullWin32Impl.I | 66 ----- .../pipeline/conditionVarFullWin32Impl.cxx | 20 -- .../src/pipeline/conditionVarFullWin32Impl.h | 65 ----- panda/src/pipeline/conditionVarImpl.h | 8 +- panda/src/pipeline/conditionVarWin32Impl.I | 35 +-- panda/src/pipeline/conditionVarWin32Impl.h | 26 +- panda/src/pipeline/mutexDebug.h | 1 - panda/src/pipeline/mutexDirect.h | 1 - panda/src/pipeline/p3pipeline_composite1.cxx | 3 - panda/src/pipeline/thread.cxx | 7 +- panda/src/pipeline/thread.h | 3 - 27 files changed, 91 insertions(+), 822 deletions(-) delete mode 100644 panda/src/pipeline/conditionVarFull.I delete mode 100644 panda/src/pipeline/conditionVarFull.cxx delete mode 100644 panda/src/pipeline/conditionVarFullDebug.I delete mode 100644 panda/src/pipeline/conditionVarFullDebug.cxx delete mode 100644 panda/src/pipeline/conditionVarFullDebug.h delete mode 100644 panda/src/pipeline/conditionVarFullDirect.I delete mode 100644 panda/src/pipeline/conditionVarFullDirect.cxx delete mode 100644 panda/src/pipeline/conditionVarFullDirect.h delete mode 100644 panda/src/pipeline/conditionVarFullWin32Impl.I delete mode 100644 panda/src/pipeline/conditionVarFullWin32Impl.cxx delete mode 100644 panda/src/pipeline/conditionVarFullWin32Impl.h diff --git a/dtool/src/dtoolbase/mutexWin32Impl.h b/dtool/src/dtoolbase/mutexWin32Impl.h index 9b34973b1d..47f31a2e8f 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.h +++ b/dtool/src/dtoolbase/mutexWin32Impl.h @@ -74,7 +74,6 @@ private: volatile PVOID _lock[2] = {nullptr, nullptr}; friend class ConditionVarWin32Impl; - friend class ConditionVarFullWin32Impl; }; /** diff --git a/panda/src/event/asyncFuture.h b/panda/src/event/asyncFuture.h index c12bccb7d0..27fa1db29c 100644 --- a/panda/src/event/asyncFuture.h +++ b/panda/src/event/asyncFuture.h @@ -22,7 +22,6 @@ class AsyncTaskManager; class AsyncTask; -class ConditionVarFull; /** * This class represents a thread-safe handle to a promised future result of diff --git a/panda/src/pipeline/conditionVar.h b/panda/src/pipeline/conditionVar.h index fe90e22063..47ad3c973d 100644 --- a/panda/src/pipeline/conditionVar.h +++ b/panda/src/pipeline/conditionVar.h @@ -24,11 +24,6 @@ * condition variable can be used to "wake up" a thread when some arbitrary * condition has changed. * - * The ConditionVar class does not support the full semantics of POSIX - * condition variables. In particular, it does not support the broadcast or - * notify_all function. See ConditionVarFull for a more complete (but - * possibly more expensive) API. - * * A condition variable is associated with a single mutex, and several * condition variables may share the same mutex. * @@ -51,10 +46,7 @@ PUBLISHED: // These methods are inherited from the base class. //INLINE void wait(); //INLINE void notify(); - - // The notify_all() method is specifically *not* provided by ConditionVar. - // Use ConditionVarFull if you need to call this method. - void notify_all() = delete; + //INLINE void notify_all(); INLINE Mutex &get_mutex() const; }; diff --git a/panda/src/pipeline/conditionVarDebug.cxx b/panda/src/pipeline/conditionVarDebug.cxx index 30a12695ad..c38bdc6d52 100644 --- a/panda/src/pipeline/conditionVarDebug.cxx +++ b/panda/src/pipeline/conditionVarDebug.cxx @@ -78,8 +78,7 @@ wait() { << *current_thread << " waiting on " << *this << "\n"; } - nassertd(current_thread->_waiting_on_cvar == nullptr && - current_thread->_waiting_on_cvar_full == nullptr) { + nassertd(current_thread->_waiting_on_cvar == nullptr) { } current_thread->_waiting_on_cvar = this; @@ -128,8 +127,7 @@ wait(double timeout) { << ", with timeout " << timeout << "\n"; } - nassertd(current_thread->_waiting_on_cvar == nullptr && - current_thread->_waiting_on_cvar_full == nullptr) { + nassertd(current_thread->_waiting_on_cvar == nullptr) { } current_thread->_waiting_on_cvar = this; @@ -156,9 +154,6 @@ wait(double timeout) { * predict which one. It is possible that more than one thread will be woken * up. * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * * If no threads are waiting, this is a no-op: the notify event is lost. */ void ConditionVarDebug:: @@ -187,6 +182,38 @@ notify() { _mutex._global_lock->unlock(); } +/** + * Informs all of the other threads who are currently blocked on wait() that + * the relevant condition has changed. + * + * If no threads are waiting, this is a no-op: the notify event is lost. + */ +void ConditionVarDebug:: +notify_all() { + _mutex._global_lock->lock(); + + /* + if (!_mutex.do_debug_is_locked()) { + Thread *current_thread = Thread::get_current_thread(); + ostringstream ostr; + ostr << *current_thread << " attempted to notify " + << *this << " without holding " << _mutex; + nassert_raise(ostr.str()); + _mutex._global_lock->unlock(); + return; + } + */ + + if (thread_cat->is_spam()) { + Thread *current_thread = Thread::get_current_thread(); + thread_cat.spam() + << *current_thread << " notifying all " << *this << "\n"; + } + + _impl.notify_all(); + _mutex._global_lock->unlock(); +} + /** * This method is declared virtual in ConditionVarDebug, but non-virtual in * ConditionVarDirect. diff --git a/panda/src/pipeline/conditionVarDebug.h b/panda/src/pipeline/conditionVarDebug.h index 85da3fde2e..d7aa8e7ecb 100644 --- a/panda/src/pipeline/conditionVarDebug.h +++ b/panda/src/pipeline/conditionVarDebug.h @@ -43,6 +43,7 @@ PUBLISHED: BLOCKING void wait(); BLOCKING void wait(double timeout); void notify(); + void notify_all(); virtual void output(std::ostream &out) const; private: diff --git a/panda/src/pipeline/conditionVarDirect.I b/panda/src/pipeline/conditionVarDirect.I index bf8e42aea5..3a5074fd65 100644 --- a/panda/src/pipeline/conditionVarDirect.I +++ b/panda/src/pipeline/conditionVarDirect.I @@ -76,9 +76,6 @@ wait(double timeout) { * predict which one. It is possible that more than one thread will be woken * up. * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * * If no threads are waiting, this is a no-op: the notify event is lost. */ INLINE void ConditionVarDirect:: @@ -86,3 +83,15 @@ notify() { TAU_PROFILE("ConditionVarDirect::notify()", " ", TAU_USER); _impl.notify(); } + +/** + * Informs all of the other threads who are currently blocked on wait() that + * the relevant condition has changed. + * + * If no threads are waiting, this is a no-op: the notify event is lost. + */ +INLINE void ConditionVarDirect:: +notify_all() { + TAU_PROFILE("ConditionVarDirect::notify()", " ", TAU_USER); + _impl.notify_all(); +} diff --git a/panda/src/pipeline/conditionVarDirect.h b/panda/src/pipeline/conditionVarDirect.h index 2a8c9197cb..17ecca68d9 100644 --- a/panda/src/pipeline/conditionVarDirect.h +++ b/panda/src/pipeline/conditionVarDirect.h @@ -43,6 +43,7 @@ PUBLISHED: BLOCKING INLINE void wait(); BLOCKING INLINE void wait(double timeout); INLINE void notify(); + INLINE void notify_all(); void output(std::ostream &out) const; private: diff --git a/panda/src/pipeline/conditionVarFull.I b/panda/src/pipeline/conditionVarFull.I deleted file mode 100644 index b796e7aed2..0000000000 --- a/panda/src/pipeline/conditionVarFull.I +++ /dev/null @@ -1,40 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFull.I - * @author drose - * @date 2006-08-28 - */ - -/** - * You must pass in a Mutex to the condition variable constructor. This mutex - * may be shared by other condition variables, if desired. It is the caller's - * responsibility to ensure the Mutex object does not destruct during the - * lifetime of the condition variable. - */ -INLINE ConditionVarFull:: -ConditionVarFull(Mutex &mutex) : -#ifdef DEBUG_THREADS - ConditionVarFullDebug(mutex) -#else - ConditionVarFullDirect(mutex) -#endif // DEBUG_THREADS -{ -} - -/** - * Returns the mutex associated with this condition variable. - */ -INLINE Mutex &ConditionVarFull:: -get_mutex() const { -#ifdef DEBUG_THREADS - return (Mutex &)ConditionVarFullDebug::get_mutex(); -#else - return (Mutex &)ConditionVarFullDirect::get_mutex(); -#endif // DEBUG_THREADS -} diff --git a/panda/src/pipeline/conditionVarFull.cxx b/panda/src/pipeline/conditionVarFull.cxx deleted file mode 100644 index b5a32d477c..0000000000 --- a/panda/src/pipeline/conditionVarFull.cxx +++ /dev/null @@ -1,14 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFull.cxx - * @author drose - * @date 2006-08-28 - */ - -#include "conditionVarFull.h" diff --git a/panda/src/pipeline/conditionVarFull.h b/panda/src/pipeline/conditionVarFull.h index 37a9af1e11..f7effac224 100644 --- a/panda/src/pipeline/conditionVarFull.h +++ b/panda/src/pipeline/conditionVarFull.h @@ -14,46 +14,8 @@ #ifndef CONDITIONVARFULL_H #define CONDITIONVARFULL_H -#include "pandabase.h" -#include "conditionVarFullDebug.h" -#include "conditionVarFullDirect.h" +#include "conditionVar.h" -/** - * This class implements a condition variable; see ConditionVar for a brief - * introduction to this class. The ConditionVarFull class provides a more - * complete implementation than ConditionVar; in particular, it provides the - * notify_all() method, which is guaranteed to wake up all threads currently - * waiting on the condition (whereas notify() is guaranteed to wake up at - * least one thread, but may or may not wake up all of them). - * - * This class exists because on certain platforms (e.g. Win32), implementing - * notify_all() requires more overhead, so you should use ConditionVar for - * cases when you do not require the notify_all() semantics. - * - * There are still some minor semantics that POSIX condition variables provide - * which this implementation does not. For instance, it is required (not - * optional) that the caller of notify() or notify_all() is holding the - * condition variable's mutex before the call. - * - * This class inherits its implementation either from ConditionVarFullDebug or - * ConditionVarFullDirect, depending on the definition of DEBUG_THREADS. - */ -#ifdef DEBUG_THREADS -class EXPCL_PANDA_PIPELINE ConditionVarFull : public ConditionVarFullDebug -#else -class EXPCL_PANDA_PIPELINE ConditionVarFull : public ConditionVarFullDirect -#endif // DEBUG_THREADS -{ -PUBLISHED: - INLINE explicit ConditionVarFull(Mutex &mutex); - ConditionVarFull(const ConditionVarFull ©) = delete; - ~ConditionVarFull() = default; - - ConditionVarFull &operator = (const ConditionVarFull ©) = delete; - - INLINE Mutex &get_mutex() const; -}; - -#include "conditionVarFull.I" +typedef ConditionVar ConditionVarFull; #endif diff --git a/panda/src/pipeline/conditionVarFullDebug.I b/panda/src/pipeline/conditionVarFullDebug.I deleted file mode 100644 index 5a09f03a3d..0000000000 --- a/panda/src/pipeline/conditionVarFullDebug.I +++ /dev/null @@ -1,20 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDebug.I - * @author drose - * @date 2006-08-28 - */ - -/** - * Returns the mutex associated with this condition variable. - */ -INLINE MutexDebug &ConditionVarFullDebug:: -get_mutex() const { - return _mutex; -} diff --git a/panda/src/pipeline/conditionVarFullDebug.cxx b/panda/src/pipeline/conditionVarFullDebug.cxx deleted file mode 100644 index 6b8b7feaa7..0000000000 --- a/panda/src/pipeline/conditionVarFullDebug.cxx +++ /dev/null @@ -1,234 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDebug.cxx - * @author drose - * @date 2006-08-28 - */ - -#include "conditionVarFullDebug.h" -#include "thread.h" -#include "config_pipeline.h" - -#ifdef DEBUG_THREADS - -using std::ostream; -using std::ostringstream; - -/** - * You must pass in a Mutex to the condition variable constructor. This mutex - * may be shared by other condition variables, if desired. It is the caller's - * responsibility to ensure the Mutex object does not destruct during the - * lifetime of the condition variable. - */ -ConditionVarFullDebug:: -ConditionVarFullDebug(MutexDebug &mutex) : - _mutex(mutex), - _impl(*mutex.get_global_lock()) -{ - nassertv(!_mutex._allow_recursion); -} - -/** - * - */ -ConditionVarFullDebug:: -~ConditionVarFullDebug() { -} - -/** - * Waits on the condition. The caller must already be holding the lock - * associated with the condition variable before calling this function. - * - * wait() will release the lock, then go to sleep until some other thread - * calls notify() on this condition variable. At that time at least one - * thread waiting on the same ConditionVarFullDebug will grab the lock again, - * and then return from wait(). - * - * It is possible that wait() will return even if no one has called notify(). - * It is the responsibility of the calling process to verify the condition on - * return from wait, and possibly loop back to wait again if necessary. - * - * Note the semantics of a condition variable: the mutex must be held before - * wait() is called, and it will still be held when wait() returns. However, - * it will be temporarily released during the wait() call itself. - */ -void ConditionVarFullDebug:: -wait() { - _mutex._global_lock->lock(); - - Thread *current_thread = Thread::get_current_thread(); - - if (!_mutex.do_debug_is_locked()) { - ostringstream ostr; - ostr << *current_thread << " attempted to wait on " - << *this << " without holding " << _mutex; - nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); - return; - } - - if (thread_cat->is_spam()) { - thread_cat.spam() - << *current_thread << " waiting on " << *this << "\n"; - } - - nassertd(current_thread->_waiting_on_cvar == nullptr && - current_thread->_waiting_on_cvar_full == nullptr) { - } - current_thread->_waiting_on_cvar_full = this; - - _mutex.do_unlock(); - _impl.wait(); // temporarily releases _global_lock - _mutex.do_lock(current_thread); - - nassertd(current_thread->_waiting_on_cvar_full == this) { - } - current_thread->_waiting_on_cvar_full = nullptr; - - if (thread_cat.is_spam()) { - thread_cat.spam() - << *current_thread << " awake on " << *this << "\n"; - } - - _mutex._global_lock->unlock(); -} - -/** - * Waits on the condition, with a timeout. The function will return when the - * condition variable is notified, or the timeout occurs. There is no way to - * directly tell which happened, and it is possible that neither in fact - * happened (spurious wakeups are possible). - * - * See wait() with no parameters for more. - */ -void ConditionVarFullDebug:: -wait(double timeout) { - _mutex._global_lock->lock(); - - Thread *current_thread = Thread::get_current_thread(); - - if (!_mutex.do_debug_is_locked()) { - ostringstream ostr; - ostr << *current_thread << " attempted to wait on " - << *this << " without holding " << _mutex; - nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); - return; - } - - if (thread_cat.is_spam()) { - thread_cat.spam() - << *current_thread << " waiting on " << *this - << ", with timeout " << timeout << "\n"; - } - - nassertd(current_thread->_waiting_on_cvar == nullptr && - current_thread->_waiting_on_cvar_full == nullptr) { - } - current_thread->_waiting_on_cvar_full = this; - - _mutex.do_unlock(); - _impl.wait(timeout); // temporarily releases _global_lock - _mutex.do_lock(current_thread); - - nassertd(current_thread->_waiting_on_cvar_full == this) { - } - current_thread->_waiting_on_cvar_full = nullptr; - - if (thread_cat.is_spam()) { - thread_cat.spam() - << *current_thread << " awake on " << *this << "\n"; - } - - _mutex._global_lock->unlock(); -} - -/** - * Informs one of the other threads who are currently blocked on wait() that - * the relevant condition has changed. If multiple threads are currently - * waiting, at least one of them will be woken up, although there is no way to - * predict which one. It is possible that more than one thread will be woken - * up. - * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * - * If no threads are waiting, this is a no-op: the notify event is lost. - */ -void ConditionVarFullDebug:: -notify() { - _mutex._global_lock->lock(); - - /* - if (!_mutex.do_debug_is_locked()) { - Thread *current_thread = Thread::get_current_thread(); - ostringstream ostr; - ostr << *current_thread << " attempted to notify " - << *this << " without holding " << _mutex; - nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); - return; - } - */ - - if (thread_cat->is_spam()) { - Thread *current_thread = Thread::get_current_thread(); - thread_cat.spam() - << *current_thread << " notifying " << *this << "\n"; - } - - _impl.notify(); - _mutex._global_lock->unlock(); -} - -/** - * Informs all of the other threads who are currently blocked on wait() that - * the relevant condition has changed. - * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * - * If no threads are waiting, this is a no-op: the notify event is lost. - */ -void ConditionVarFullDebug:: -notify_all() { - _mutex._global_lock->lock(); - - /* - if (!_mutex.do_debug_is_locked()) { - Thread *current_thread = Thread::get_current_thread(); - ostringstream ostr; - ostr << *current_thread << " attempted to notify " - << *this << " without holding " << _mutex; - nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); - return; - } - */ - - if (thread_cat->is_spam()) { - Thread *current_thread = Thread::get_current_thread(); - thread_cat.spam() - << *current_thread << " notifying all " << *this << "\n"; - } - - _impl.notify_all(); - _mutex._global_lock->unlock(); -} - -/** - * This method is declared virtual in ConditionVarFullDebug, but non-virtual - * in ConditionVarFullDirect. - */ -void ConditionVarFullDebug:: -output(ostream &out) const { - out << "ConditionVarFull " << (void *)this << " on " << _mutex; -} - -#endif // DEBUG_THREADS diff --git a/panda/src/pipeline/conditionVarFullDebug.h b/panda/src/pipeline/conditionVarFullDebug.h deleted file mode 100644 index cefb27cad7..0000000000 --- a/panda/src/pipeline/conditionVarFullDebug.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDebug.h - * @author drose - * @date 2006-08-28 - */ - -#ifndef CONDITIONVARFULLDEBUG_H -#define CONDITIONVARFULLDEBUG_H - -#include "pandabase.h" -#include "pmutex.h" -#include "conditionVarImpl.h" - -#ifdef DEBUG_THREADS - -/** - * A condition variable, usually used to communicate information about - * changing state to a thread that is waiting for something to happen. A - * condition variable can be used to "wake up" a thread when some arbitrary - * condition has changed. - * - * A condition variable is associated with a single mutex, and several - * condition variables may share the same mutex. - */ -class EXPCL_PANDA_PIPELINE ConditionVarFullDebug { -public: - explicit ConditionVarFullDebug(MutexDebug &mutex); - ConditionVarFullDebug(const ConditionVarFullDebug ©) = delete; - virtual ~ConditionVarFullDebug(); - - ConditionVarFullDebug &operator = (const ConditionVarFullDebug ©) = delete; - -PUBLISHED: - INLINE MutexDebug &get_mutex() const; - - BLOCKING void wait(); - BLOCKING void wait(double timeout); - void notify(); - void notify_all(); - virtual void output(std::ostream &out) const; - -private: - MutexDebug &_mutex; - ConditionVarFullImpl _impl; -}; - -INLINE std::ostream & -operator << (std::ostream &out, const ConditionVarFullDebug &cv) { - cv.output(out); - return out; -} - -#include "conditionVarFullDebug.I" - -#endif // DEBUG_THREADS - -#endif diff --git a/panda/src/pipeline/conditionVarFullDirect.I b/panda/src/pipeline/conditionVarFullDirect.I deleted file mode 100644 index 207cb01538..0000000000 --- a/panda/src/pipeline/conditionVarFullDirect.I +++ /dev/null @@ -1,103 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDirect.I - * @author drose - * @date 2006-08-28 - */ - -/** - * You must pass in a Mutex to the condition variable constructor. This mutex - * may be shared by other condition variables, if desired. It is the caller's - * responsibility to ensure the Mutex object does not destruct during the - * lifetime of the condition variable. - */ -INLINE ConditionVarFullDirect:: -ConditionVarFullDirect(MutexDirect &mutex) : - _mutex(mutex), - _impl(mutex._impl) -{ -} - -/** - * Returns the mutex associated with this condition variable. - */ -INLINE MutexDirect &ConditionVarFullDirect:: -get_mutex() const { - return _mutex; -} - -/** - * Waits on the condition. The caller must already be holding the lock - * associated with the condition variable before calling this function. - * - * wait() will release the lock, then go to sleep until some other thread - * calls notify() on this condition variable. At that time at least one - * thread waiting on the same ConditionVarFullDirect will grab the lock again, - * and then return from wait(). - * - * It is possible that wait() will return even if no one has called notify(). - * It is the responsibility of the calling process to verify the condition on - * return from wait, and possibly loop back to wait again if necessary. - * - * Note the semantics of a condition variable: the mutex must be held before - * wait() is called, and it will still be held when wait() returns. However, - * it will be temporarily released during the wait() call itself. - */ -INLINE void ConditionVarFullDirect:: -wait() { - TAU_PROFILE("ConditionVarFullDirect::wait()", " ", TAU_USER); - _impl.wait(); -} - -/** - * Waits on the condition, with a timeout. The function will return when the - * condition variable is notified, or the timeout occurs. There is no way to - * directly tell which happened, and it is possible that neither in fact - * happened (spurious wakeups are possible). - * - * See wait() with no parameters for more. - */ -void ConditionVarFullDirect:: -wait(double timeout) { - TAU_PROFILE("ConditionVarFullDirect::wait(double)", " ", TAU_USER); - _impl.wait(timeout); -} - -/** - * Informs one of the other threads who are currently blocked on wait() that - * the relevant condition has changed. If multiple threads are currently - * waiting, at least one of them will be woken up, although there is no way to - * predict which one. It is possible that more than one thread will be woken - * up. - * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * - * If no threads are waiting, this is a no-op: the notify is lost. - */ -INLINE void ConditionVarFullDirect:: -notify() { - TAU_PROFILE("ConditionVarFullDirect::notify()", " ", TAU_USER); - _impl.notify(); -} - -/** - * Informs all of the other threads who are currently blocked on wait() that - * the relevant condition has changed. - * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * - * If no threads are waiting, this is a no-op: the notify event is lost. - */ -INLINE void ConditionVarFullDirect:: -notify_all() { - TAU_PROFILE("ConditionVarFullDirect::notify()", " ", TAU_USER); - _impl.notify_all(); -} diff --git a/panda/src/pipeline/conditionVarFullDirect.cxx b/panda/src/pipeline/conditionVarFullDirect.cxx deleted file mode 100644 index 04f9c647ed..0000000000 --- a/panda/src/pipeline/conditionVarFullDirect.cxx +++ /dev/null @@ -1,27 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDirect.cxx - * @author drose - * @date 2006-08-28 - */ - -#include "conditionVarFullDirect.h" - -#ifndef DEBUG_THREADS - -/** - * This method is declared virtual in ConditionVarFullDebug, but non-virtual - * in ConditionVarFullDirect. - */ -void ConditionVarFullDirect:: -output(std::ostream &out) const { - out << "ConditionVarFull " << (void *)this << " on " << _mutex; -} - -#endif // !DEBUG_THREADS diff --git a/panda/src/pipeline/conditionVarFullDirect.h b/panda/src/pipeline/conditionVarFullDirect.h deleted file mode 100644 index 729185501b..0000000000 --- a/panda/src/pipeline/conditionVarFullDirect.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDirect.h - * @author drose - * @date 2006-08-28 - */ - -#ifndef CONDITIONVARFULLDIRECT_H -#define CONDITIONVARFULLDIRECT_H - -#include "pandabase.h" -#include "mutexDirect.h" -#include "conditionVarImpl.h" - -#ifndef DEBUG_THREADS - -/** - * A condition variable, usually used to communicate information about - * changing state to a thread that is waiting for something to happen. A - * condition variable can be used to "wake up" a thread when some arbitrary - * condition has changed. - * - * A condition variable is associated with a single mutex, and several - * condition variables may share the same mutex. - */ -class EXPCL_PANDA_PIPELINE ConditionVarFullDirect { -public: - INLINE explicit ConditionVarFullDirect(MutexDirect &mutex); - ConditionVarFullDirect(const ConditionVarFullDirect ©) = delete; - ~ConditionVarFullDirect() = default; - - ConditionVarFullDirect &operator = (const ConditionVarFullDirect ©) = delete; - -PUBLISHED: - INLINE MutexDirect &get_mutex() const; - - BLOCKING INLINE void wait(); - BLOCKING INLINE void wait(double timeout); - INLINE void notify(); - INLINE void notify_all(); - void output(std::ostream &out) const; - -private: - MutexDirect &_mutex; - ConditionVarFullImpl _impl; -}; - -INLINE std::ostream & -operator << (std::ostream &out, const ConditionVarFullDirect &cv) { - cv.output(out); - return out; -} - -#include "conditionVarFullDirect.I" - -#endif // !DEBUG_THREADS - -#endif diff --git a/panda/src/pipeline/conditionVarFullWin32Impl.I b/panda/src/pipeline/conditionVarFullWin32Impl.I deleted file mode 100644 index 62e8d04e06..0000000000 --- a/panda/src/pipeline/conditionVarFullWin32Impl.I +++ /dev/null @@ -1,66 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullWin32Impl.I - * @author drose - * @date 2006-08-28 - */ - -/** - * - */ -INLINE ConditionVarFullWin32Impl:: -ConditionVarFullWin32Impl(MutexWin32Impl &mutex) : _mutex(mutex) { -} - -/** - * - */ -INLINE ConditionVarFullWin32Impl:: -~ConditionVarFullWin32Impl() { - // These fields are only set in the Windows XP implementation, when these - // both contain events. - if (_cvar[1] != nullptr) { - CloseHandle(_cvar[1]); - } - if (_cvar[2] != nullptr) { - CloseHandle(_cvar[2]); - } -} - -/** - * - */ -INLINE void ConditionVarFullWin32Impl:: -wait() { - MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, INFINITE, 0); -} - -/** - * - */ -INLINE void ConditionVarFullWin32Impl:: -wait(double timeout) { - MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, (DWORD)(timeout * 1000.0), 0); -} - -/** - * - */ -INLINE void ConditionVarFullWin32Impl:: -notify() { - MutexWin32Impl::_funcs._cvar_notify_one(_cvar); -} - -/** - * - */ -INLINE void ConditionVarFullWin32Impl:: -notify_all() { - MutexWin32Impl::_funcs._cvar_notify_all(_cvar); -} diff --git a/panda/src/pipeline/conditionVarFullWin32Impl.cxx b/panda/src/pipeline/conditionVarFullWin32Impl.cxx deleted file mode 100644 index 6d664735d6..0000000000 --- a/panda/src/pipeline/conditionVarFullWin32Impl.cxx +++ /dev/null @@ -1,20 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullWin32Impl.cxx - * @author drose - * @date 2006-08-28 - */ - -#include "selectThreadImpl.h" - -#if defined(WIN32_VC) || defined(WIN64_VC) - -#include "conditionVarFullWin32Impl.h" - -#endif // WIN32_VC diff --git a/panda/src/pipeline/conditionVarFullWin32Impl.h b/panda/src/pipeline/conditionVarFullWin32Impl.h deleted file mode 100644 index 5c621412e7..0000000000 --- a/panda/src/pipeline/conditionVarFullWin32Impl.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullWin32Impl.h - * @author drose - * @date 2006-08-28 - */ - -#ifndef CONDITIONVARFULLWIN32IMPL_H -#define CONDITIONVARFULLWIN32IMPL_H - -#include "pandabase.h" -#include "selectThreadImpl.h" - -#if defined(WIN32_VC) - -#include "mutexWin32Impl.h" -#include "pnotify.h" -#include "atomicAdjust.h" - -class MutexWin32Impl; - -/** - * Uses Windows native calls to implement a conditionVarFull. - * - * We follow the "SetEvent" implementation suggested by - * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html . This allows us to - * implement both notify() and notify_all(), but it has more overhead than the - * simpler implementation of ConditionVarWin32Impl. - * - * As described by the above reference, this implementation suffers from a few - * weaknesses; in particular, it does not necessarily wake up all threads - * fairly; and it may sometimes incorrectly wake up a thread that was not - * waiting at the time notify() was called. But we figure it's good enough - * for our purposes. - */ -class EXPCL_PANDA_PIPELINE ConditionVarFullWin32Impl { -public: - INLINE ConditionVarFullWin32Impl(MutexWin32Impl &mutex); - INLINE ~ConditionVarFullWin32Impl(); - - INLINE void wait(); - INLINE void wait(double timeout); - INLINE void notify(); - INLINE void notify_all(); - -private: - MutexWin32Impl &_mutex; - - // On Windows XP, the first field contains a Signal (auto-reset) event, - // the second field a broadcast (manual reset) event, third a waiter count. - // On Windows Vista and above, the first contains a PCONDITION_VARIABLE. - volatile PVOID _cvar[3] = {nullptr, nullptr, nullptr}; -}; - -#include "conditionVarFullWin32Impl.I" - -#endif // WIN32_VC - -#endif diff --git a/panda/src/pipeline/conditionVarImpl.h b/panda/src/pipeline/conditionVarImpl.h index 7837622ba6..774ab72753 100644 --- a/panda/src/pipeline/conditionVarImpl.h +++ b/panda/src/pipeline/conditionVarImpl.h @@ -21,35 +21,31 @@ #include "conditionVarDummyImpl.h" typedef ConditionVarDummyImpl ConditionVarImpl; -typedef ConditionVarDummyImpl ConditionVarFullImpl; #elif defined(THREAD_SIMPLE_IMPL) #include "conditionVarSimpleImpl.h" typedef ConditionVarSimpleImpl ConditionVarImpl; -typedef ConditionVarSimpleImpl ConditionVarFullImpl; #elif defined(MUTEX_SPINLOCK) #include "conditionVarSpinlockImpl.h" typedef ConditionVarSpinlockImpl ConditionVarImpl; -typedef ConditionVarSpinlockImpl ConditionVarFullImpl; #elif defined(THREAD_WIN32_IMPL) #include "conditionVarWin32Impl.h" -#include "conditionVarFullWin32Impl.h" typedef ConditionVarWin32Impl ConditionVarImpl; -typedef ConditionVarFullWin32Impl ConditionVarFullImpl; #elif defined(THREAD_POSIX_IMPL) #include "conditionVarPosixImpl.h" typedef ConditionVarPosixImpl ConditionVarImpl; -typedef ConditionVarPosixImpl ConditionVarFullImpl; #endif +typedef ConditionVarImpl ConditionVarFullImpl; + #if defined(WIN32_VC) #include "conditionVarWin32Impl.h" typedef ConditionVarWin32Impl TrueConditionVarImpl; diff --git a/panda/src/pipeline/conditionVarWin32Impl.I b/panda/src/pipeline/conditionVarWin32Impl.I index 82ba9dea39..7f2b24a079 100644 --- a/panda/src/pipeline/conditionVarWin32Impl.I +++ b/panda/src/pipeline/conditionVarWin32Impl.I @@ -16,8 +16,6 @@ */ INLINE ConditionVarWin32Impl:: ConditionVarWin32Impl(MutexWin32Impl &mutex) : _mutex(mutex) { - // Create an auto-reset event. - _event_signal = CreateEvent(nullptr, false, false, nullptr); } /** @@ -25,7 +23,14 @@ ConditionVarWin32Impl(MutexWin32Impl &mutex) : _mutex(mutex) { */ INLINE ConditionVarWin32Impl:: ~ConditionVarWin32Impl() { - CloseHandle(_event_signal); + // These fields are only set in the Windows XP implementation, when these + // both contain events. + if (_cvar[1] != nullptr) { + CloseHandle(_cvar[1]); + } + if (_cvar[2] != nullptr) { + CloseHandle(_cvar[2]); + } } /** @@ -33,12 +38,7 @@ INLINE ConditionVarWin32Impl:: */ INLINE void ConditionVarWin32Impl:: wait() { - _mutex.unlock(); - - DWORD result = WaitForSingleObject(_event_signal, INFINITE); - nassertv(result == WAIT_OBJECT_0); - - _mutex.lock(); + MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, INFINITE, 0); } /** @@ -46,12 +46,7 @@ wait() { */ INLINE void ConditionVarWin32Impl:: wait(double timeout) { - _mutex.unlock(); - - DWORD result = WaitForSingleObject(_event_signal, (DWORD)(timeout * 1000.0)); - nassertv(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT); - - _mutex.lock(); + MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, (DWORD)(timeout * 1000.0), 0); } /** @@ -59,5 +54,13 @@ wait(double timeout) { */ INLINE void ConditionVarWin32Impl:: notify() { - SetEvent(_event_signal); + MutexWin32Impl::_funcs._cvar_notify_one(_cvar); +} + +/** + * + */ +INLINE void ConditionVarWin32Impl:: +notify_all() { + MutexWin32Impl::_funcs._cvar_notify_all(_cvar); } diff --git a/panda/src/pipeline/conditionVarWin32Impl.h b/panda/src/pipeline/conditionVarWin32Impl.h index a0c4d882c7..213cacdf9e 100644 --- a/panda/src/pipeline/conditionVarWin32Impl.h +++ b/panda/src/pipeline/conditionVarWin32Impl.h @@ -25,14 +25,19 @@ class MutexWin32Impl; /** - * Uses Windows native calls to implement a conditionVar. + * Uses Windows native calls to implement a ConditionVar. * - * The Windows native synchronization primitives don't actually implement a - * full POSIX-style condition variable, but the Event primitive does a fair - * job if we disallow notify_all() (POSIX broadcast). See - * ConditionVarFullWin32Impl for a full implementation that includes - * notify_all(). This class is much simpler than that full implementation, so - * we can avoid the overhead required to support broadcast. + * On Windows Vista and above, we use the system's native condition variables. + * + * On Windows XP, we follow the "SetEvent" implementation suggested by + * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html . This allows us to + * implement both notify() and notify_all(). + * + * As described by the above reference, this implementation suffers from a few + * weaknesses; in particular, it does not necessarily wake up all threads + * fairly; and it may sometimes incorrectly wake up a thread that was not + * waiting at the time notify() was called. But we figure it's good enough + * for our purposes. */ class EXPCL_PANDA_PIPELINE ConditionVarWin32Impl { public: @@ -42,10 +47,15 @@ public: INLINE void wait(); INLINE void wait(double timeout); INLINE void notify(); + INLINE void notify_all(); private: MutexWin32Impl &_mutex; - HANDLE _event_signal; + + // On Windows XP, the first field contains a Signal (auto-reset) event, + // the second field a broadcast (manual reset) event, third a waiter count. + // On Windows Vista and above, the first contains a PCONDITION_VARIABLE. + volatile PVOID _cvar[3] = {nullptr, nullptr, nullptr}; }; #include "conditionVarWin32Impl.I" diff --git a/panda/src/pipeline/mutexDebug.h b/panda/src/pipeline/mutexDebug.h index 094f2eafc6..298fd9f7ca 100644 --- a/panda/src/pipeline/mutexDebug.h +++ b/panda/src/pipeline/mutexDebug.h @@ -83,7 +83,6 @@ private: static MutexTrueImpl *_global_lock; friend class ConditionVarDebug; - friend class ConditionVarFullDebug; }; INLINE std::ostream & diff --git a/panda/src/pipeline/mutexDirect.h b/panda/src/pipeline/mutexDirect.h index 068f5fc5c4..9e578abd52 100644 --- a/panda/src/pipeline/mutexDirect.h +++ b/panda/src/pipeline/mutexDirect.h @@ -57,7 +57,6 @@ private: mutable MutexTrueImpl _impl; friend class ConditionVarDirect; - friend class ConditionVarFullDirect; }; INLINE std::ostream & diff --git a/panda/src/pipeline/p3pipeline_composite1.cxx b/panda/src/pipeline/p3pipeline_composite1.cxx index 487c5ca0ad..5a9e929283 100644 --- a/panda/src/pipeline/p3pipeline_composite1.cxx +++ b/panda/src/pipeline/p3pipeline_composite1.cxx @@ -2,9 +2,6 @@ #include "conditionVarDebug.cxx" #include "conditionVarDirect.cxx" #include "conditionVarDummyImpl.cxx" -#include "conditionVarFull.cxx" -#include "conditionVarFullDebug.cxx" -#include "conditionVarFullDirect.cxx" #include "conditionVarPosixImpl.cxx" #include "conditionVarWin32Impl.cxx" #include "conditionVarSimpleImpl.cxx" diff --git a/panda/src/pipeline/thread.cxx b/panda/src/pipeline/thread.cxx index 80c32fa7f5..81152a8095 100644 --- a/panda/src/pipeline/thread.cxx +++ b/panda/src/pipeline/thread.cxx @@ -17,7 +17,6 @@ #include "config_pipeline.h" #include "mutexDebug.h" #include "conditionVarDebug.h" -#include "conditionVarFullDebug.h" Thread *Thread::_main_thread; Thread *Thread::_external_thread; @@ -52,7 +51,6 @@ Thread(const std::string &name, const std::string &sync_name) : #ifdef DEBUG_THREADS _blocked_on_mutex = nullptr; _waiting_on_cvar = nullptr; - _waiting_on_cvar_full = nullptr; #endif } @@ -63,8 +61,7 @@ Thread:: ~Thread() { #ifdef DEBUG_THREADS nassertv(_blocked_on_mutex == nullptr && - _waiting_on_cvar == nullptr && - _waiting_on_cvar_full == nullptr); + _waiting_on_cvar == nullptr); #endif } @@ -145,8 +142,6 @@ output_blocker(std::ostream &out) const { _blocked_on_mutex->output_with_holder(out); } else if (_waiting_on_cvar != nullptr) { out << *_waiting_on_cvar; - } else if (_waiting_on_cvar_full != nullptr) { - out << *_waiting_on_cvar_full; } #endif // DEBUG_THREADS } diff --git a/panda/src/pipeline/thread.h b/panda/src/pipeline/thread.h index 69b878725a..159b93c9df 100644 --- a/panda/src/pipeline/thread.h +++ b/panda/src/pipeline/thread.h @@ -31,7 +31,6 @@ class Mutex; class ReMutex; class MutexDebug; class ConditionVarDebug; -class ConditionVarFullDebug; class AsyncTask; /** @@ -156,7 +155,6 @@ private: #ifdef DEBUG_THREADS MutexDebug *_blocked_on_mutex; ConditionVarDebug *_waiting_on_cvar; - ConditionVarFullDebug *_waiting_on_cvar_full; #endif // DEBUG_THREADS private: @@ -184,7 +182,6 @@ private: friend class MutexDebug; friend class ConditionVarDebug; - friend class ConditionVarFullDebug; friend class ThreadDummyImpl; friend class ThreadWin32Impl; From b466e77fe3d075070e79c956876da6ceea957b71 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 11 Feb 2019 15:45:54 +0100 Subject: [PATCH 079/144] dtoolbase: make TypeRegistry lock statically initialized This is possible now that all MutexImpl have a constexpr constructor. --- dtool/src/dtoolbase/typeRegistry.I | 10 --- dtool/src/dtoolbase/typeRegistry.cxx | 96 ++++++++++++++-------------- dtool/src/dtoolbase/typeRegistry.h | 4 +- 3 files changed, 48 insertions(+), 62 deletions(-) diff --git a/dtool/src/dtoolbase/typeRegistry.I b/dtool/src/dtoolbase/typeRegistry.I index 7d47c7f7f7..77c83de82c 100644 --- a/dtool/src/dtoolbase/typeRegistry.I +++ b/dtool/src/dtoolbase/typeRegistry.I @@ -36,16 +36,6 @@ ptr() { return _global_pointer; } -/** - * Ensures the lock pointer has been allocated. - */ -INLINE void TypeRegistry:: -init_lock() { - if (_lock == nullptr) { - _lock = new MutexImpl; - } -} - /** * Returns the TypeRegistryNode associated with the indicated TypeHandle. If * there is no associated TypeRegistryNode, reports an error condition and diff --git a/dtool/src/dtoolbase/typeRegistry.cxx b/dtool/src/dtoolbase/typeRegistry.cxx index 16f551ec33..f2646eddb9 100644 --- a/dtool/src/dtoolbase/typeRegistry.cxx +++ b/dtool/src/dtoolbase/typeRegistry.cxx @@ -25,7 +25,7 @@ using std::ostream; using std::ostringstream; using std::string; -MutexImpl *TypeRegistry::_lock = nullptr; +MutexImpl TypeRegistry::_lock; TypeRegistry *TypeRegistry::_global_pointer = nullptr; /** @@ -37,7 +37,7 @@ TypeRegistry *TypeRegistry::_global_pointer = nullptr; */ bool TypeRegistry:: register_type(TypeHandle &type_handle, const string &name) { - _lock->lock(); + _lock.lock(); if (type_handle != TypeHandle::none()) { // Here's a type that was already registered. Just make sure everything's @@ -45,7 +45,7 @@ register_type(TypeHandle &type_handle, const string &name) { TypeRegistryNode *rnode = look_up(type_handle, nullptr); if (&type_handle == &rnode->_ref) { // No problem. - _lock->unlock(); + _lock.unlock(); assert(rnode->_name == name); return false; } @@ -67,7 +67,7 @@ register_type(TypeHandle &type_handle, const string &name) { _derivations_fresh = false; type_handle = new_handle; - _lock->unlock(); + _lock.unlock(); return true; } TypeRegistryNode *rnode = (*ri).second; @@ -83,7 +83,7 @@ register_type(TypeHandle &type_handle, const string &name) { if (type_handle == rnode->_handle) { // No problem. - _lock->unlock(); + _lock.unlock(); return false; } // But wait--the type_handle has changed! We kept a reference to the @@ -92,7 +92,7 @@ register_type(TypeHandle &type_handle, const string &name) { // time, but now it's different! Bad juju. cerr << "Reregistering " << name << "\n"; type_handle = rnode->_handle; - _lock->unlock(); + _lock.unlock(); return false; } @@ -108,7 +108,7 @@ register_type(TypeHandle &type_handle, const string &name) { type_handle = rnode->_handle; } - _lock->unlock(); + _lock.unlock(); return false; } @@ -119,7 +119,7 @@ register_type(TypeHandle &type_handle, const string &name) { */ TypeHandle TypeRegistry:: register_dynamic_type(const string &name) { - _lock->lock(); + _lock.lock(); NameRegistry::iterator ri; ri = _name_registry.find(name); @@ -139,14 +139,14 @@ register_dynamic_type(const string &name) { _name_registry[name] = rnode; _derivations_fresh = false; - _lock->unlock(); + _lock.unlock(); return *new_handle; } // Return the TypeHandle previously obtained. TypeRegistryNode *rnode = (*ri).second; TypeHandle handle = rnode->_handle; - _lock->unlock(); + _lock.unlock(); return handle; } @@ -157,7 +157,7 @@ register_dynamic_type(const string &name) { */ void TypeRegistry:: record_derivation(TypeHandle child, TypeHandle parent) { - _lock->lock(); + _lock.lock(); TypeRegistryNode *cnode = look_up(child, nullptr); assert(cnode != nullptr); @@ -176,7 +176,7 @@ record_derivation(TypeHandle child, TypeHandle parent) { _derivations_fresh = false; } - _lock->unlock(); + _lock.unlock(); } /** @@ -187,7 +187,7 @@ record_derivation(TypeHandle child, TypeHandle parent) { */ void TypeRegistry:: record_alternate_name(TypeHandle type, const string &name) { - _lock->lock(); + _lock.lock(); TypeRegistryNode *rnode = look_up(type, nullptr); if (rnode != nullptr) { @@ -195,7 +195,7 @@ record_alternate_name(TypeHandle type, const string &name) { _name_registry.insert(NameRegistry::value_type(name, rnode)).first; if ((*ri).second != rnode) { - _lock->unlock(); + _lock.unlock(); cerr << "Name " << name << " already assigned to TypeHandle " << rnode->_name << "; cannot reassign to " << type << "\n"; @@ -204,7 +204,7 @@ record_alternate_name(TypeHandle type, const string &name) { } - _lock->unlock(); + _lock.unlock(); } #ifdef HAVE_PYTHON @@ -214,14 +214,14 @@ record_alternate_name(TypeHandle type, const string &name) { */ void TypeRegistry:: record_python_type(TypeHandle type, PyObject *python_type) { - _lock->lock(); + _lock.lock(); TypeRegistryNode *rnode = look_up(type, nullptr); if (rnode != nullptr) { rnode->_python_type = python_type; } - _lock->unlock(); + _lock.unlock(); } #endif @@ -231,7 +231,7 @@ record_python_type(TypeHandle type, PyObject *python_type) { */ TypeHandle TypeRegistry:: find_type(const string &name) const { - _lock->lock(); + _lock.lock(); TypeHandle handle = TypeHandle::none(); NameRegistry::const_iterator ri; @@ -239,7 +239,7 @@ find_type(const string &name) const { if (ri != _name_registry.end()) { handle = (*ri).second->_handle; } - _lock->unlock(); + _lock.unlock(); return handle; } @@ -271,11 +271,11 @@ find_type_by_id(int id) const { */ string TypeRegistry:: get_name(TypeHandle type, TypedObject *object) const { - _lock->lock(); + _lock.lock(); TypeRegistryNode *rnode = look_up(type, object); assert(rnode != nullptr); string name = rnode->_name; - _lock->unlock(); + _lock.unlock(); return name; } @@ -296,7 +296,7 @@ get_name(TypeHandle type, TypedObject *object) const { bool TypeRegistry:: is_derived_from(TypeHandle child, TypeHandle base, TypedObject *child_object) { - _lock->lock(); + _lock.lock(); const TypeRegistryNode *child_node = look_up(child, child_object); const TypeRegistryNode *base_node = look_up(base, nullptr); @@ -307,7 +307,7 @@ is_derived_from(TypeHandle child, TypeHandle base, freshen_derivations(); bool result = TypeRegistryNode::is_derived_from(child_node, base_node); - _lock->unlock(); + _lock.unlock(); return result; } @@ -316,9 +316,9 @@ is_derived_from(TypeHandle child, TypeHandle base, */ int TypeRegistry:: get_num_typehandles() { - _lock->lock(); + _lock.lock(); int num_types = (int)_handle_registry.size(); - _lock->unlock(); + _lock.unlock(); return num_types; } @@ -327,12 +327,12 @@ get_num_typehandles() { */ TypeHandle TypeRegistry:: get_typehandle(int n) { - _lock->lock(); + _lock.lock(); TypeRegistryNode *rnode = nullptr; if (n >= 0 && n < (int)_handle_registry.size()) { rnode = _handle_registry[n]; } - _lock->unlock(); + _lock.unlock(); if (rnode != nullptr) { return rnode->_handle; @@ -347,10 +347,10 @@ get_typehandle(int n) { */ int TypeRegistry:: get_num_root_classes() { - _lock->lock(); + _lock.lock(); freshen_derivations(); int num_roots = (int)_root_classes.size(); - _lock->unlock(); + _lock.unlock(); return num_roots; } @@ -359,7 +359,7 @@ get_num_root_classes() { */ TypeHandle TypeRegistry:: get_root_class(int n) { - _lock->lock(); + _lock.lock(); freshen_derivations(); TypeHandle handle; if (n >= 0 && n < (int)_root_classes.size()) { @@ -367,7 +367,7 @@ get_root_class(int n) { } else { handle = TypeHandle::none(); } - _lock->unlock(); + _lock.unlock(); return handle; } @@ -385,11 +385,11 @@ get_root_class(int n) { */ int TypeRegistry:: get_num_parent_classes(TypeHandle child, TypedObject *child_object) const { - _lock->lock(); + _lock.lock(); TypeRegistryNode *rnode = look_up(child, child_object); assert(rnode != nullptr); int num_parents = (int)rnode->_parent_classes.size(); - _lock->unlock(); + _lock.unlock(); return num_parents; } @@ -399,7 +399,7 @@ get_num_parent_classes(TypeHandle child, TypedObject *child_object) const { */ TypeHandle TypeRegistry:: get_parent_class(TypeHandle child, int index) const { - _lock->lock(); + _lock.lock(); TypeHandle handle; TypeRegistryNode *rnode = look_up(child, nullptr); assert(rnode != nullptr); @@ -408,7 +408,7 @@ get_parent_class(TypeHandle child, int index) const { } else { handle = TypeHandle::none(); } - _lock->unlock(); + _lock.unlock(); return handle; } @@ -422,11 +422,11 @@ get_parent_class(TypeHandle child, int index) const { */ int TypeRegistry:: get_num_child_classes(TypeHandle child, TypedObject *child_object) const { - _lock->lock(); + _lock.lock(); TypeRegistryNode *rnode = look_up(child, child_object); assert(rnode != nullptr); int num_children = (int)rnode->_child_classes.size(); - _lock->unlock(); + _lock.unlock(); return num_children; } @@ -436,7 +436,7 @@ get_num_child_classes(TypeHandle child, TypedObject *child_object) const { */ TypeHandle TypeRegistry:: get_child_class(TypeHandle child, int index) const { - _lock->lock(); + _lock.lock(); TypeHandle handle; TypeRegistryNode *rnode = look_up(child, nullptr); assert(rnode != nullptr); @@ -445,7 +445,7 @@ get_child_class(TypeHandle child, int index) const { } else { handle = TypeHandle::none(); } - _lock->unlock(); + _lock.unlock(); return handle; } @@ -462,7 +462,7 @@ get_child_class(TypeHandle child, int index) const { TypeHandle TypeRegistry:: get_parent_towards(TypeHandle child, TypeHandle base, TypedObject *child_object) { - _lock->lock(); + _lock.lock(); TypeHandle handle; const TypeRegistryNode *child_node = look_up(child, child_object); const TypeRegistryNode *base_node = look_up(base, nullptr); @@ -470,7 +470,7 @@ get_parent_towards(TypeHandle child, TypeHandle base, base_node != nullptr); freshen_derivations(); handle = TypeRegistryNode::get_parent_towards(child_node, base_node); - _lock->unlock(); + _lock.unlock(); return handle; } @@ -484,8 +484,7 @@ get_parent_towards(TypeHandle child, TypeHandle base, */ void TypeRegistry:: reregister_types() { - init_lock(); - _lock->lock(); + _lock.lock(); HandleRegistry::iterator ri; TypeRegistry *reg = ptr(); for (ri = reg->_handle_registry.begin(); @@ -496,7 +495,7 @@ reregister_types() { cerr << "Reregistering " << rnode->_name << "\n"; } } - _lock->unlock(); + _lock.unlock(); } @@ -506,9 +505,9 @@ reregister_types() { */ void TypeRegistry:: write(ostream &out) const { - _lock->lock(); + _lock.lock(); do_write(out); - _lock->unlock(); + _lock.unlock(); } /** @@ -540,7 +539,6 @@ TypeRegistry() { */ void TypeRegistry:: init_global_pointer() { - init_lock(); init_memory_hook(); _global_pointer = new TypeRegistry; } @@ -636,9 +634,9 @@ look_up_invalid(TypeHandle handle, TypedObject *object) const { // But we're lucky enough to have a TypedObject pointer handy! Maybe we // can use it to resolve the error. We have to drop the lock while we // do this, so we don't get a recursive lock. - _lock->unlock(); + _lock.unlock(); handle = object->force_init_type(); - _lock->lock(); + _lock.lock(); if (handle._index == 0) { // Strange. diff --git a/dtool/src/dtoolbase/typeRegistry.h b/dtool/src/dtoolbase/typeRegistry.h index 43b1b8e41f..0051ba68a4 100644 --- a/dtool/src/dtoolbase/typeRegistry.h +++ b/dtool/src/dtoolbase/typeRegistry.h @@ -101,8 +101,6 @@ private: void write_node(std::ostream &out, int indent_level, const TypeRegistryNode *node) const; - static INLINE void init_lock(); - typedef std::vector HandleRegistry; HandleRegistry _handle_registry; @@ -114,7 +112,7 @@ private: bool _derivations_fresh; - static MutexImpl *_lock; + static MutexImpl _lock; static TypeRegistry *_global_pointer; friend class TypeHandle; From 3df3b27a4e79127c5ed7a82b931f537b49d3ceae Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 11 Feb 2019 15:54:56 +0100 Subject: [PATCH 080/144] prc: prefer global-scope static MutexImpl over local one MutexImpl guarantees nowadays to be initialized at constant init time, so this is safer on Windows, where we can't rely on magic statics. --- dtool/src/prc/configDeclaration.cxx | 15 ++++++--------- dtool/src/prc/configVariableFilename.cxx | 11 +++++------ dtool/src/prc/configVariableString.cxx | 11 +++++------ 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/dtool/src/prc/configDeclaration.cxx b/dtool/src/prc/configDeclaration.cxx index b401df73d4..3f8e7582cd 100644 --- a/dtool/src/prc/configDeclaration.cxx +++ b/dtool/src/prc/configDeclaration.cxx @@ -21,6 +21,8 @@ using std::string; +static MutexImpl this_prc_dir_lock; + /** * Use the ConfigPage::make_declaration() interface to create a new * declaration. @@ -139,13 +141,6 @@ set_double_word(size_t n, double value) { */ Filename ConfigDeclaration:: get_filename_value() const { - // Since we are about to set THIS_PRC_DIR globally, we need to ensure that - // no two threads call this method at the same time. - // NB. MSVC doesn't guarantee that this mutex is initialized in a - // thread-safe manner. But chances are that the first time this is called - // is at static init time, when there is no risk of data races. - static MutexImpl lock; - string str = _string_value; // Are there any variables to be expanded? @@ -153,11 +148,13 @@ get_filename_value() const { Filename page_filename(_page->get_name()); Filename page_dirname = page_filename.get_dirname(); - lock.lock(); + // Since we are about to set THIS_PRC_DIR globally, we need to ensure that + // no two threads call this method at the same time. + this_prc_dir_lock.lock(); ExecutionEnvironment::shadow_environment_variable("THIS_PRC_DIR", page_dirname.to_os_specific()); str = ExecutionEnvironment::expand_string(str); ExecutionEnvironment::clear_shadow("THIS_PRC_DIR"); - lock.unlock(); + this_prc_dir_lock.unlock(); } Filename fn; diff --git a/dtool/src/prc/configVariableFilename.cxx b/dtool/src/prc/configVariableFilename.cxx index 1015a32e66..026ad80d68 100644 --- a/dtool/src/prc/configVariableFilename.cxx +++ b/dtool/src/prc/configVariableFilename.cxx @@ -13,17 +13,16 @@ #include "configVariableFilename.h" #include "executionEnvironment.h" +#include "mutexImpl.h" + +static MutexImpl filename_lock; /** * Recopies the config variable into the Filename for returning its value. */ void ConfigVariableFilename:: reload_cache() { - // NB. MSVC doesn't guarantee that this mutex is initialized in a - // thread-safe manner. But chances are that the first time this is called - // is at static init time, when there is no risk of data races. - static MutexImpl lock; - lock.lock(); + filename_lock.lock(); // We check again for cache validity since another thread may have beaten // us to the punch while we were waiting for the lock. @@ -34,5 +33,5 @@ reload_cache() { _cache = decl->get_filename_value(); mark_cache_valid(_local_modified); } - lock.unlock(); + filename_lock.unlock(); } diff --git a/dtool/src/prc/configVariableString.cxx b/dtool/src/prc/configVariableString.cxx index ebb4a751d2..8ecf2b1830 100644 --- a/dtool/src/prc/configVariableString.cxx +++ b/dtool/src/prc/configVariableString.cxx @@ -12,17 +12,16 @@ */ #include "configVariableString.h" +#include "mutexImpl.h" + +static MutexImpl string_lock; /** * Refreshes the variable's cached value. */ void ConfigVariableString:: reload_cache() { - // NB. MSVC doesn't guarantee that this mutex is initialized in a - // thread-safe manner. But chances are that the first time this is called - // is at static init time, when there is no risk of data races. - static MutexImpl lock; - lock.lock(); + string_lock.lock(); // We check again for cache validity since another thread may have beaten // us to the punch while we were waiting for the lock. @@ -31,5 +30,5 @@ reload_cache() { mark_cache_valid(_local_modified); } - lock.unlock(); + string_lock.unlock(); } From afed80e83a5c033f03497bcf38353794e662eedf Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 11 Feb 2019 16:01:43 +0100 Subject: [PATCH 081/144] pipeline: use constant-initi static MutexImpl for global debug lock --- panda/src/pipeline/conditionVarDebug.cxx | 26 +++++++-------- panda/src/pipeline/mutexDebug.I | 42 ++++++++---------------- panda/src/pipeline/mutexDebug.cxx | 16 ++++----- panda/src/pipeline/mutexDebug.h | 4 +-- 4 files changed, 36 insertions(+), 52 deletions(-) diff --git a/panda/src/pipeline/conditionVarDebug.cxx b/panda/src/pipeline/conditionVarDebug.cxx index c38bdc6d52..8485ad1272 100644 --- a/panda/src/pipeline/conditionVarDebug.cxx +++ b/panda/src/pipeline/conditionVarDebug.cxx @@ -29,7 +29,7 @@ using std::ostringstream; ConditionVarDebug:: ConditionVarDebug(MutexDebug &mutex) : _mutex(mutex), - _impl(*mutex.get_global_lock()) + _impl(mutex._global_lock) { nassertv(!_mutex._allow_recursion); } @@ -60,7 +60,7 @@ ConditionVarDebug:: */ void ConditionVarDebug:: wait() { - _mutex._global_lock->lock(); + _mutex._global_lock.lock(); Thread *current_thread = Thread::get_current_thread(); @@ -69,7 +69,7 @@ wait() { ostr << *current_thread << " attempted to wait on " << *this << " without holding " << _mutex; nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); + _mutex._global_lock.unlock(); return; } @@ -95,7 +95,7 @@ wait() { << *current_thread << " awake on " << *this << "\n"; } - _mutex._global_lock->unlock(); + _mutex._global_lock.unlock(); } /** @@ -108,7 +108,7 @@ wait() { */ void ConditionVarDebug:: wait(double timeout) { - _mutex._global_lock->lock(); + _mutex._global_lock.lock(); Thread *current_thread = Thread::get_current_thread(); @@ -117,7 +117,7 @@ wait(double timeout) { ostr << *current_thread << " attempted to wait on " << *this << " without holding " << _mutex; nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); + _mutex._global_lock.unlock(); return; } @@ -144,7 +144,7 @@ wait(double timeout) { << *current_thread << " awake on " << *this << "\n"; } - _mutex._global_lock->unlock(); + _mutex._global_lock.unlock(); } /** @@ -158,7 +158,7 @@ wait(double timeout) { */ void ConditionVarDebug:: notify() { - _mutex._global_lock->lock(); + _mutex._global_lock.lock(); /* if (!_mutex.do_debug_is_locked()) { @@ -167,7 +167,7 @@ notify() { ostr << *current_thread << " attempted to notify " << *this << " without holding " << _mutex; nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); + _mutex._global_lock.unlock(); return; } */ @@ -179,7 +179,7 @@ notify() { } _impl.notify(); - _mutex._global_lock->unlock(); + _mutex._global_lock.unlock(); } /** @@ -190,7 +190,7 @@ notify() { */ void ConditionVarDebug:: notify_all() { - _mutex._global_lock->lock(); + _mutex._global_lock.lock(); /* if (!_mutex.do_debug_is_locked()) { @@ -199,7 +199,7 @@ notify_all() { ostr << *current_thread << " attempted to notify " << *this << " without holding " << _mutex; nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); + _mutex._global_lock.unlock(); return; } */ @@ -211,7 +211,7 @@ notify_all() { } _impl.notify_all(); - _mutex._global_lock->unlock(); + _mutex._global_lock.unlock(); } /** diff --git a/panda/src/pipeline/mutexDebug.I b/panda/src/pipeline/mutexDebug.I index ae3ce74967..0995d78db0 100644 --- a/panda/src/pipeline/mutexDebug.I +++ b/panda/src/pipeline/mutexDebug.I @@ -18,9 +18,9 @@ INLINE void MutexDebug:: lock() { TAU_PROFILE("void MutexDebug::acquire()", " ", TAU_USER); - _global_lock->lock(); + _global_lock.lock(); ((MutexDebug *)this)->do_lock(Thread::get_current_thread()); - _global_lock->unlock(); + _global_lock.unlock(); } /** @@ -30,9 +30,9 @@ lock() { INLINE bool MutexDebug:: try_lock() { TAU_PROFILE("void MutexDebug::try_lock()", " ", TAU_USER); - _global_lock->lock(); + _global_lock.lock(); bool acquired = ((MutexDebug *)this)->do_try_lock(Thread::get_current_thread()); - _global_lock->unlock(); + _global_lock.unlock(); return acquired; } @@ -43,9 +43,9 @@ try_lock() { INLINE void MutexDebug:: unlock() { TAU_PROFILE("void MutexDebug::unlock()", " ", TAU_USER); - _global_lock->lock(); + _global_lock.lock(); ((MutexDebug *)this)->do_unlock(); - _global_lock->unlock(); + _global_lock.unlock(); } /** @@ -62,9 +62,9 @@ INLINE void MutexDebug:: acquire(Thread *current_thread) const { TAU_PROFILE("void MutexDebug::acquire(Thread *)", " ", TAU_USER); nassertv(current_thread == Thread::get_current_thread()); - _global_lock->lock(); + _global_lock.lock(); ((MutexDebug *)this)->do_lock(current_thread); - _global_lock->unlock(); + _global_lock.unlock(); } /** @@ -75,9 +75,9 @@ INLINE bool MutexDebug:: try_acquire(Thread *current_thread) const { TAU_PROFILE("void MutexDebug::try_acquire(Thread *)", " ", TAU_USER); nassertr(current_thread == Thread::get_current_thread(), false); - _global_lock->lock(); + _global_lock.lock(); bool acquired = ((MutexDebug *)this)->do_try_lock(current_thread); - _global_lock->unlock(); + _global_lock.unlock(); return acquired; } @@ -114,9 +114,9 @@ elevate_lock() const { INLINE void MutexDebug:: release() const { TAU_PROFILE("void MutexDebug::release()", " ", TAU_USER); - _global_lock->lock(); + _global_lock.lock(); ((MutexDebug *)this)->do_unlock(); - _global_lock->unlock(); + _global_lock.unlock(); } /** @@ -128,22 +128,8 @@ release() const { INLINE bool MutexDebug:: debug_is_locked() const { TAU_PROFILE("bool MutexDebug::debug_is_locked()", " ", TAU_USER); - _global_lock->lock(); + _global_lock.lock(); bool is_locked = do_debug_is_locked(); - _global_lock->unlock(); + _global_lock.unlock(); return is_locked; } - -/** - * Ensures the global MutexImpl pointer has been created, and returns its - * pointer. Since this method is called by the MutexDebug constructor, any - * other (non-static) methods of MutexDebug may simply assume that the pointer - * has already been created. - */ -INLINE MutexTrueImpl *MutexDebug:: -get_global_lock() { - if (_global_lock == nullptr) { - _global_lock = new MutexTrueImpl; - } - return _global_lock; -} diff --git a/panda/src/pipeline/mutexDebug.cxx b/panda/src/pipeline/mutexDebug.cxx index d1e0194e6f..daa6f3a7ed 100644 --- a/panda/src/pipeline/mutexDebug.cxx +++ b/panda/src/pipeline/mutexDebug.cxx @@ -21,7 +21,7 @@ using std::ostream; using std::ostringstream; int MutexDebug::_pstats_count = 0; -MutexTrueImpl *MutexDebug::_global_lock; +MutexTrueImpl MutexDebug::_global_lock; /** * @@ -34,7 +34,7 @@ MutexDebug(const std::string &name, bool allow_recursion, bool lightweight) : _locking_thread(nullptr), _lock_count(0), _deleted_name(nullptr), - _cvar_impl(*get_global_lock()) + _cvar_impl(_global_lock) { #ifndef SIMPLE_THREADS // If we're using real threads, there's no such thing as a lightweight @@ -87,12 +87,12 @@ output(ostream &out) const { */ void MutexDebug:: output_with_holder(ostream &out) const { - _global_lock->lock(); + _global_lock.lock(); output(out); if (_locking_thread != nullptr) { out << " (held by " << *_locking_thread << ")\n"; } - _global_lock->unlock(); + _global_lock.unlock(); } /** @@ -102,9 +102,9 @@ output_with_holder(ostream &out) const { */ void MutexDebug:: increment_pstats() { - _global_lock->lock(); + _global_lock.lock(); ++_pstats_count; - _global_lock->unlock(); + _global_lock.unlock(); } /** @@ -113,9 +113,9 @@ increment_pstats() { */ void MutexDebug:: decrement_pstats() { - _global_lock->lock(); + _global_lock.lock(); --_pstats_count; - _global_lock->unlock(); + _global_lock.unlock(); } /** diff --git a/panda/src/pipeline/mutexDebug.h b/panda/src/pipeline/mutexDebug.h index 298fd9f7ca..775ff12966 100644 --- a/panda/src/pipeline/mutexDebug.h +++ b/panda/src/pipeline/mutexDebug.h @@ -65,8 +65,6 @@ private: void report_deadlock(Thread *current_thread); private: - INLINE static MutexTrueImpl *get_global_lock(); - bool _allow_recursion; bool _lightweight; Thread *_locking_thread; @@ -80,7 +78,7 @@ private: ConditionVarImpl _cvar_impl; static int _pstats_count; - static MutexTrueImpl *_global_lock; + static MutexTrueImpl _global_lock; friend class ConditionVarDebug; }; From 11b5f09819bd66dbe011ddced36f60c9e7b47bb8 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 11 Feb 2019 16:17:33 +0100 Subject: [PATCH 082/144] general: replace remaining references to ConditionVarFull. --- panda/src/chan/animControl.h | 4 ++-- panda/src/event/asyncFuture.cxx | 1 - panda/src/event/asyncTaskChain.h | 4 ++-- panda/src/event/asyncTaskManager.h | 4 ++-- panda/src/gobj/texture.h | 4 ++-- panda/src/gobj/vertexDataPage.h | 3 +-- panda/src/net/datagramQueue.h | 4 ++-- 7 files changed, 11 insertions(+), 13 deletions(-) diff --git a/panda/src/chan/animControl.h b/panda/src/chan/animControl.h index d52b2e4835..7b9f973cd7 100644 --- a/panda/src/chan/animControl.h +++ b/panda/src/chan/animControl.h @@ -24,7 +24,7 @@ #include "typedReferenceCount.h" #include "namable.h" #include "pmutex.h" -#include "conditionVarFull.h" +#include "conditionVar.h" class PartBundle; class AnimChannelBase; @@ -79,7 +79,7 @@ private: bool _pending; std::string _pending_done_event; Mutex _pending_lock; // protects the above two. - ConditionVarFull _pending_cvar; // signals when _pending goes true. + ConditionVar _pending_cvar; // signals when _pending goes true. // This is a PT(PartGroup) instead of a PT(PartBundle), just because we // can't include partBundle.h for circular reasons. But it actually keeps a diff --git a/panda/src/event/asyncFuture.cxx b/panda/src/event/asyncFuture.cxx index 4805650260..f9efddbad7 100644 --- a/panda/src/event/asyncFuture.cxx +++ b/panda/src/event/asyncFuture.cxx @@ -14,7 +14,6 @@ #include "asyncFuture.h" #include "asyncTask.h" #include "asyncTaskManager.h" -#include "conditionVarFull.h" #include "config_event.h" #include "pStatTimer.h" #include "throw_event.h" diff --git a/panda/src/event/asyncTaskChain.h b/panda/src/event/asyncTaskChain.h index c211b30c85..6de098b6ed 100644 --- a/panda/src/event/asyncTaskChain.h +++ b/panda/src/event/asyncTaskChain.h @@ -20,7 +20,7 @@ #include "asyncTaskCollection.h" #include "typedReferenceCount.h" #include "thread.h" -#include "conditionVarFull.h" +#include "conditionVar.h" #include "pvector.h" #include "pdeque.h" #include "pStatCollector.h" @@ -159,7 +159,7 @@ protected: AsyncTaskManager *_manager; - ConditionVarFull _cvar; // signaled when one of the task heaps, _state, or _current_sort changes, or a task finishes. + ConditionVar _cvar; // signaled when one of the task heaps, _state, or _current_sort changes, or a task finishes. enum State { S_initial, // no threads yet diff --git a/panda/src/event/asyncTaskManager.h b/panda/src/event/asyncTaskManager.h index 69711ab6f6..0bb137deb4 100644 --- a/panda/src/event/asyncTaskManager.h +++ b/panda/src/event/asyncTaskManager.h @@ -23,7 +23,7 @@ #include "thread.h" #include "pmutex.h" #include "mutexHolder.h" -#include "conditionVarFull.h" +#include "conditionVar.h" #include "pvector.h" #include "pdeque.h" #include "pStatCollector.h" @@ -130,7 +130,7 @@ protected: TasksByName _tasks_by_name; PT(ClockObject) _clock; - ConditionVarFull _frame_cvar; // Signalled when the clock ticks. + ConditionVar _frame_cvar; // Signalled when the clock ticks. static AsyncTaskManager* _global_ptr; diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index 7cb5f305fb..4bde90c973 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -29,7 +29,7 @@ #include "pStatCollector.h" #include "pmutex.h" #include "mutexHolder.h" -#include "conditionVarFull.h" +#include "conditionVar.h" #include "loaderOptions.h" #include "string_utils.h" #include "cycleData.h" @@ -1034,7 +1034,7 @@ protected: Mutex _lock; // Used to implement unlocked_reload_ram_image(). - ConditionVarFull _cvar; // condition: _reloading is true. + ConditionVar _cvar; // condition: _reloading is true. bool _reloading; // A Texture keeps a list (actually, a map) of all the diff --git a/panda/src/gobj/vertexDataPage.h b/panda/src/gobj/vertexDataPage.h index bceca6adea..4aafeebac1 100644 --- a/panda/src/gobj/vertexDataPage.h +++ b/panda/src/gobj/vertexDataPage.h @@ -21,7 +21,6 @@ #include "vertexDataSaveFile.h" #include "pmutex.h" #include "conditionVar.h" -#include "conditionVarFull.h" #include "thread.h" #include "mutexHolder.h" #include "pdeque.h" @@ -147,7 +146,7 @@ private: // Signaled when anything new is added to either of the above queues, or // when _shutdown is set true. This wakes up any pending thread. - ConditionVarFull _pending_cvar; + ConditionVar _pending_cvar; PageThreads _threads; friend class PageThread; diff --git a/panda/src/net/datagramQueue.h b/panda/src/net/datagramQueue.h index 131de070cc..9dac974f5d 100644 --- a/panda/src/net/datagramQueue.h +++ b/panda/src/net/datagramQueue.h @@ -18,7 +18,7 @@ #include "netDatagram.h" #include "pmutex.h" -#include "conditionVarFull.h" +#include "conditionVar.h" #include "pdeque.h" /** @@ -41,7 +41,7 @@ public: private: Mutex _cvlock; - ConditionVarFull _cv; // signaled when queue contents change. + ConditionVar _cv; // signaled when queue contents change. typedef pdeque QueueType; QueueType _queue; From d93fb702eb9a84fbe6a42bf0ec523de4161e16a8 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 11 Feb 2019 18:53:52 +0100 Subject: [PATCH 083/144] makepanda: fix various syntax warnings in Python 3.8 --- makepanda/installpanda.py | 2 +- makepanda/makechm.py | 18 +++++++++--------- makepanda/makepanda.py | 16 ++++++++-------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/makepanda/installpanda.py b/makepanda/installpanda.py index ef8ddeab7e..dcb18a72bf 100644 --- a/makepanda/installpanda.py +++ b/makepanda/installpanda.py @@ -62,7 +62,7 @@ def WriteMimeXMLFile(fname, info): fhandle.write("\t\n" % (mime)) fhandle.write("\t\t%s\n" % (desc)) fhandle.write("\t\t\n" % (ext)) - fhandle.write("\t\s") + fhandle.write("\t\n") fhandle.write("\n") fhandle.close() diff --git a/makepanda/makechm.py b/makepanda/makechm.py index 1127eb41f5..5a14813380 100755 --- a/makepanda/makechm.py +++ b/makepanda/makechm.py @@ -213,11 +213,11 @@ def makeCHM(outputfile, dirname, title, special = None): # Now, execute the command to compile the files. if "PROGRAMFILES" in os.environ and os.path.isdir("%s\\HTML Help Workshop" % os.environ["PROGRAMFILES"]): cmd = "\"%s\\HTML Help Workshop\\hhc.exe\" %s.hhp" % (os.environ["PROGRAMFILES"], base) - elif os.path.isdir("C:\Program Files\HTML Help Workshop"): + elif os.path.isdir("C:\\Program Files\\HTML Help Workshop"): cmd = "\"C:\\Program Files\\HTML Help Workshop\\hhc.exe\" %s.hhp" % base else: cmd = "hhc \"%s.hhp\"" % base - print cmd + print(cmd) os.system(cmd) if not KEEPTEMP: if os.path.isfile("%s.hhp" % base): os.remove("%s.hhp" % base) @@ -225,7 +225,7 @@ def makeCHM(outputfile, dirname, title, special = None): if os.path.isfile("%s.hhk" % base): os.remove("%s.hhk" % base) if os.path.isfile("%s.chw" % base): os.remove("%s.chw" % base) if not os.path.isfile(base + ".chm"): - print "An error has occurred!" + print("An error has occurred!") if __name__ == "__main__": exit(1) else: @@ -246,7 +246,7 @@ if __name__ == "__main__": VERSION = None try: f = file("built/include/pandaVersion.h","r") - pattern = re.compile('^\s*[#]\s*define\s+PANDA_VERSION_STR\s+["]([0-9.]+)["]') + pattern = re.compile('^\\s*[#]\\s*define\\s+PANDA_VERSION_STR\\s+["]([0-9.]+)["]') for line in f: match = pattern.match(line,0) if (match): @@ -260,22 +260,22 @@ if __name__ == "__main__": # Now, make CHM's for both the manual and reference, if we have them. for lang in ["python", "cxx"]: if not os.path.isdir("manual-" + lang): - print "No directory named 'manual-%s' found" % lang + print("No directory named 'manual-%s' found" % lang) else: - print "Making CHM file for manual-%s..." % lang + print("Making CHM file for manual-%s..." % lang) if VERSION == None: makeManualCHM("manual-%s.chm" % lang, "manual-" + lang, "Panda3D Manual") else: makeManualCHM("manual-%s-%s.chm" % (VERSION, lang), "manual-" + lang, "Panda3D %s Manual" % VERSION) if not os.path.isdir("reference-" + lang): - print "No directory named 'reference-%s' found" % lang + print("No directory named 'reference-%s' found" % lang) else: - print "Making CHM file for reference-%s..." % lang + print("Making CHM file for reference-%s..." % lang) if VERSION == None: makeReferenceCHM("reference-%s.chm" % lang, "reference-" + lang, "Panda3D Reference") else: makeReferenceCHM("reference-%s-%s.chm" % (VERSION, lang), "reference-" + lang, "Panda3D %s Reference" % VERSION) - print "Done!" + print("Done!") diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 792bf5ebfc..3251c3272a 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -1570,7 +1570,7 @@ def CompileIgate(woutd,wsrc,opts): # NOTE: this 1600 value is the version number for VC2010. cmd += ' -D_MSC_VER=1600 -D"__declspec(param)=" -D__cdecl -D_near -D_far -D__near -D__far -D__stdcall' if (COMPILER=="GCC"): - cmd += ' -D__attribute__\(x\)=' + cmd += ' -D__attribute__\\(x\\)=' target_arch = GetTargetArch() if target_arch in ("x86_64", "amd64"): cmd += ' -D_LP64' @@ -1675,9 +1675,9 @@ def CompileLib(lib, obj, opts): cmd += " /MACHINE:" + GetTargetArch().upper() cmd += ' /OUT:' + BracketNameWithQuotes(lib) for x in obj: cmd += ' ' + BracketNameWithQuotes(x) - cmd += ' /LIBPATH:"C:\Program Files (x86)\Intel\Composer XE 2011 SP1\ipp\lib\ia32"' - cmd += ' /LIBPATH:"C:\Program Files (x86)\Intel\Composer XE 2011 SP1\TBB\Lib\ia32\vc10"' - cmd += ' /LIBPATH:"C:\Program Files (x86)\Intel\Composer XE 2011 SP1\compiler\lib\ia32"' + cmd += ' /LIBPATH:"C:\\Program Files (x86)\\Intel\\Composer XE 2011 SP1\\ipp\\lib\\ia32"' + cmd += ' /LIBPATH:"C:\\Program Files (x86)\\Intel\\Composer XE 2011 SP1\\TBB\\Lib\\ia32\\vc10"' + cmd += ' /LIBPATH:"C:\\Program Files (x86)\\Intel\\Composer XE 2011 SP1\\compiler\\lib\\ia32"' oscmd(cmd) if (COMPILER=="GCC"): @@ -1783,9 +1783,9 @@ def CompileLink(dll, obj, opts): cmd += " /NOD:MFC90.LIB /NOD:MFC80.LIB /NOD:LIBCMT" cmd += " /NOD:LIBCI.LIB /DEBUG" cmd += " /nod:libc /nod:libcmtd /nod:atlthunk /nod:atls" - cmd += ' /LIBPATH:"C:\Program Files (x86)\Intel\Composer XE 2011 SP1\ipp\lib\ia32"' - cmd += ' /LIBPATH:"C:\Program Files (x86)\Intel\Composer XE 2011 SP1\TBB\Lib\ia32\vc10"' - cmd += ' /LIBPATH:"C:\Program Files (x86)\Intel\Composer XE 2011 SP1\compiler\lib\ia32"' + cmd += ' /LIBPATH:"C:\\Program Files (x86)\\Intel\\Composer XE 2011 SP1\\ipp\\lib\\ia32"' + cmd += ' /LIBPATH:"C:\\Program Files (x86)\\Intel\\Composer XE 2011 SP1\\TBB\\Lib\\ia32\\vc10"' + cmd += ' /LIBPATH:"C:\\Program Files (x86)\\Intel\\Composer XE 2011 SP1\\compiler\\lib\\ia32"' if (GetOrigExt(dll) != ".exe"): cmd += " /DLL" optlevel = GetOptimizeOption(opts) if (optlevel==1): cmd += " /MAP /MAPINFO:EXPORTS /NOD:MSVCRT.LIB /NOD:MSVCPRT.LIB /NOD:MSVCIRT.LIB" @@ -6648,7 +6648,7 @@ if PkgSkip("PYTHON") == 0: if GetTarget() == 'linux' or GetTarget() == 'freebsd': # Setup rpath so libs can be found in the same directory as the deployed game - LibName('DEPLOYSTUB', "-Wl,-rpath,\$ORIGIN") + LibName('DEPLOYSTUB', "-Wl,-rpath,\\$ORIGIN") LibName('DEPLOYSTUB', "-Wl,-z,origin") LibName('DEPLOYSTUB', "-rdynamic") PyTargetAdd('deploy-stub.exe', input='deploy-stub.obj') From 3024e6daebb1aba99be2831fe85579b3ec04a7d2 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 11 Feb 2019 23:35:56 +0100 Subject: [PATCH 084/144] direct: fix various syntax warnings in Python 3.8 --- direct/src/actor/Actor.py | 2 +- direct/src/directscripts/gendocs.py | 6 +++--- direct/src/dist/FreezeTool.py | 10 +++++----- direct/src/showbase/FindCtaPaths.py | 2 +- direct/src/showbase/PythonUtil.py | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/direct/src/actor/Actor.py b/direct/src/actor/Actor.py index b7d48f2d87..ff6dced979 100644 --- a/direct/src/actor/Actor.py +++ b/direct/src/actor/Actor.py @@ -2507,7 +2507,7 @@ class Actor(DirectObject, NodePath): else: animNames = [animName] for animName in animNames: - if animName is 'nothing': + if animName == 'nothing': continue thisAnim = '' totalEffect = 0. diff --git a/direct/src/directscripts/gendocs.py b/direct/src/directscripts/gendocs.py index 6bb83c9567..a8f8bc62ff 100644 --- a/direct/src/directscripts/gendocs.py +++ b/direct/src/directscripts/gendocs.py @@ -56,9 +56,9 @@ import os, sys, parser, symbol, token, re # ######################################################################## -SECHEADER = re.compile("^[A-Z][a-z]+\s*:") -JUNKHEADER = re.compile("^((Function)|(Access))\s*:") -IMPORTSTAR = re.compile("^from\s+([a-zA-Z0-9_.]+)\s+import\s+[*]\s*$") +SECHEADER = re.compile("^[A-Z][a-z]+\\s*:") +JUNKHEADER = re.compile("^((Function)|(Access))\\s*:") +IMPORTSTAR = re.compile("^from\\s+([a-zA-Z0-9_.]+)\\s+import\\s+[*]\\s*$") IDENTIFIER = re.compile("[a-zA-Z0-9_]+") FILEHEADER = re.compile( r"""^// Filename: [a-zA-Z.]+ diff --git a/direct/src/dist/FreezeTool.py b/direct/src/dist/FreezeTool.py index 5b2cd99043..87d70b0c1f 100644 --- a/direct/src/dist/FreezeTool.py +++ b/direct/src/dist/FreezeTool.py @@ -210,15 +210,15 @@ class CompilationEnvironment: if ('MAKEPANDA' in os.environ): self.compileObjExe = 'cl /wd4996 /Fo%(basename)s.obj /nologo /c %(MD)s /Zi /O2 /Ob2 /EHsc /Zm300 /W3 /I"%(pythonIPath)s" %(filename)s' self.compileObjDll = self.compileObjExe - self.linkExe = 'link /nologo /MAP:NUL /FIXED:NO /OPT:REF /STACK:4194304 /INCREMENTAL:NO /LIBPATH:"%(python)s\libs" /out:%(basename)s.exe %(basename)s.obj' - self.linkDll = 'link /nologo /DLL /MAP:NUL /FIXED:NO /OPT:REF /INCREMENTAL:NO /LIBPATH:"%(python)s\libs" /out:%(basename)s%(dllext)s.pyd %(basename)s.obj' + self.linkExe = 'link /nologo /MAP:NUL /FIXED:NO /OPT:REF /STACK:4194304 /INCREMENTAL:NO /LIBPATH:"%(python)s\\libs" /out:%(basename)s.exe %(basename)s.obj' + self.linkDll = 'link /nologo /DLL /MAP:NUL /FIXED:NO /OPT:REF /INCREMENTAL:NO /LIBPATH:"%(python)s\\libs" /out:%(basename)s%(dllext)s.pyd %(basename)s.obj' else: os.environ['PATH'] += ';' + self.MSVC + '\\bin' + self.suffix64 + ';' + self.MSVC + '\\Common7\\IDE;' + self.PSDK + '\\bin' - self.compileObjExe = 'cl /wd4996 /Fo%(basename)s.obj /nologo /c %(MD)s /Zi /O2 /Ob2 /EHsc /Zm300 /W3 /I"%(pythonIPath)s" /I"%(PSDK)s\include" /I"%(MSVC)s\include" %(filename)s' + self.compileObjExe = 'cl /wd4996 /Fo%(basename)s.obj /nologo /c %(MD)s /Zi /O2 /Ob2 /EHsc /Zm300 /W3 /I"%(pythonIPath)s" /I"%(PSDK)s\\include" /I"%(MSVC)s\\include" %(filename)s' self.compileObjDll = self.compileObjExe - self.linkExe = 'link /nologo /MAP:NUL /FIXED:NO /OPT:REF /STACK:4194304 /INCREMENTAL:NO /LIBPATH:"%(PSDK)s\lib" /LIBPATH:"%(MSVC)s\\lib%(suffix64)s" /LIBPATH:"%(python)s\libs" /out:%(basename)s.exe %(basename)s.obj' - self.linkDll = 'link /nologo /DLL /MAP:NUL /FIXED:NO /OPT:REF /INCREMENTAL:NO /LIBPATH:"%(PSDK)s\lib" /LIBPATH:"%(MSVC)s\\lib%(suffix64)s" /LIBPATH:"%(python)s\libs" /out:%(basename)s%(dllext)s.pyd %(basename)s.obj' + self.linkExe = 'link /nologo /MAP:NUL /FIXED:NO /OPT:REF /STACK:4194304 /INCREMENTAL:NO /LIBPATH:"%(PSDK)s\\lib" /LIBPATH:"%(MSVC)s\\lib%(suffix64)s" /LIBPATH:"%(python)s\\libs" /out:%(basename)s.exe %(basename)s.obj' + self.linkDll = 'link /nologo /DLL /MAP:NUL /FIXED:NO /OPT:REF /INCREMENTAL:NO /LIBPATH:"%(PSDK)s\\lib" /LIBPATH:"%(MSVC)s\\lib%(suffix64)s" /LIBPATH:"%(python)s\\libs" /out:%(basename)s%(dllext)s.pyd %(basename)s.obj' elif self.platform.startswith('osx_'): # OSX diff --git a/direct/src/showbase/FindCtaPaths.py b/direct/src/showbase/FindCtaPaths.py index 4832400b46..038257f5c6 100755 --- a/direct/src/showbase/FindCtaPaths.py +++ b/direct/src/showbase/FindCtaPaths.py @@ -21,7 +21,7 @@ def deCygwinify(path): dirs = path.split('/') if len(dirs) > 2 and len(dirs[1]) == 1: - path = '%s:\%s' % (dirs[1], '\\'.join(dirs[2:])) + path = '%s:\\%s' % (dirs[1], '\\'.join(dirs[2:])) else: # Otherwise, prepend $PANDA_ROOT and flip the slashes. diff --git a/direct/src/showbase/PythonUtil.py b/direct/src/showbase/PythonUtil.py index 2cd4e62d15..721a67453e 100644 --- a/direct/src/showbase/PythonUtil.py +++ b/direct/src/showbase/PythonUtil.py @@ -2513,7 +2513,7 @@ class AlphabetCounter: index = -1 while True: curChar = self._curCounter[index] - if curChar is 'Z': + if curChar == 'Z': nextChar = 'A' carry = True else: From 5310945f4cc4a253cd9a137499095ccac1b02634 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 11 Feb 2019 23:36:30 +0100 Subject: [PATCH 085/144] py_panda: fix use of macro that was removed in Python 3.8 --- dtool/src/interrogatedb/py_wrappers.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dtool/src/interrogatedb/py_wrappers.cxx b/dtool/src/interrogatedb/py_wrappers.cxx index 0b8a751cad..e004246249 100644 --- a/dtool/src/interrogatedb/py_wrappers.cxx +++ b/dtool/src/interrogatedb/py_wrappers.cxx @@ -1091,7 +1091,11 @@ static PyObject *Dtool_GeneratorWrapper_iternext(PyObject *self) { */ static void Dtool_StaticProperty_dealloc(PyDescrObject *descr) { +#if PY_VERSION_HEX >= 0x03080000 + PyObject_GC_UnTrack(descr); +#else _PyObject_GC_UNTRACK(descr); +#endif Py_XDECREF(descr->d_type); Py_XDECREF(descr->d_name); //#if PY_MAJOR_VERSION >= 3 From 4d0970c072aa21bb1b261d20a69b05e4a7a58b7e Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 11 Feb 2019 23:48:00 +0100 Subject: [PATCH 086/144] pgraph: StencilAttrib.make() takes default write_mask argument --- panda/src/pgraph/stencilAttrib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/pgraph/stencilAttrib.h b/panda/src/pgraph/stencilAttrib.h index 6382bc3cd3..ffc205179c 100644 --- a/panda/src/pgraph/stencilAttrib.h +++ b/panda/src/pgraph/stencilAttrib.h @@ -88,7 +88,7 @@ PUBLISHED: StencilOperation front_stencil_pass_z_pass_operation, unsigned int reference, unsigned int read_mask, - unsigned int write_mask); + unsigned int write_mask=~(unsigned int)0); static CPT(RenderAttrib) make_2_sided( bool front_enable, From 35d28cdd0de936d82476f482ee5186f9cbfdc7ac Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 12 Feb 2019 00:29:30 +0100 Subject: [PATCH 087/144] doc: update release notes for 1.10.1 --- doc/ReleaseNotes | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index 07139af55b..108111071c 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -1,7 +1,33 @@ ------------------------ RELEASE 1.10.1 ----------------------- +This is a bugfix release intended to fix several issues in 1.10.0. + +* Fix crashes when gamepad is plugged in on 32-bit Windows +* Fix deploy-ng error regarding 'exist_ok' on Python 2 +* Fix compatibility issues with upcoming Python 3.8 * Fix regression with Audio3DManager.setSoundVelocityAuto() +* Fix issues when awaiting loader.loadModel in Python 3.7 * Audio3DManager accepts tuple in setSoundVelocity/setListenerVelocity +* Fix lighting being disabled when only an AmbientLight is active +* Fix an error saving from Particle Panel in Python 3 +* Depth buffer now defaults to 24-bit on macOS (fixes flickering) +* Fix no devices being detected on Windows with threading-model +* Implement collision tests from Capsule and Box into InvSphere +* Fix SpriteAnim error in particle system +* Fix ShaderGenerator error when using too many shadowing lights +* Fix interrogate crash in Python 3 with optional wstring args +* Fix compilation errors for x86 Android platform +* Fix permissions of directories created by installpanda +* Improvements to API reference documentation +* Fix incorrect features printed out when printing an InputDevice +* Support cross-compiling for Android platforms in makepanda +* Work around various bugs when compiling with OS X 10.7's libc++ +* Fix wrong error sometimes being reported when loading plug-in +* Allow getting NodePath from CullTraverserData object +* Add config options to Assimp loader for generating normals +* Fix multisampling in floating-point framebuffers on OpenGL +* Parse egg files with 4-component tangents (must be 1 or -1) +* StencilAttrib.make() write_mask argument is now optional ------------------------ RELEASE 1.10.0 ----------------------- From 18b73504002c3b5a5dba6c22865a45dd47028e25 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 12 Feb 2019 00:31:13 +0100 Subject: [PATCH 088/144] egg: update prebuilt parser.cxx and parser.h --- panda/src/egg/parser.cxx.prebuilt | 4325 +++++++++++++---------------- panda/src/egg/parser.h.prebuilt | 226 +- 2 files changed, 2058 insertions(+), 2493 deletions(-) diff --git a/panda/src/egg/parser.cxx.prebuilt b/panda/src/egg/parser.cxx.prebuilt index f9a81a30a5..f39d54d456 100644 --- a/panda/src/egg/parser.cxx.prebuilt +++ b/panda/src/egg/parser.cxx.prebuilt @@ -1,20 +1,19 @@ -/* A Bison parser, made by GNU Bison 2.4.2. */ +/* A Bison parser, made by GNU Bison 3.2.2. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc. -/* Skeleton implementation for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2006, 2009-2010 Free Software - Foundation, Inc. - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -27,7 +26,7 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ @@ -41,11 +40,14 @@ define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ +/* Undocumented macros, especially those whose name start with YY_, + are private implementation details. Do not rely on them. */ + /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.4.2" +#define YYBISON_VERSION "3.2.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -59,23 +61,19 @@ /* Pull parsers. */ #define YYPULL 1 -/* Using locations. */ -#define YYLSP_NEEDED 0 /* Substitute the variable and function names. */ #define yyparse eggyyparse #define yylex eggyylex #define yyerror eggyyerror -#define yylval eggyylval -#define yychar eggyychar #define yydebug eggyydebug #define yynerrs eggyynerrs +#define yylval eggyylval +#define yychar eggyychar -/* Copy the first part of user declarations. */ - -/* Line 189 of yacc.c */ -#line 6 "parser.yxx" +/* First part of user prologue. */ +#line 7 "panda/src/egg/parser.yxx" /* yacc.c:338 */ #include "pandabase.h" @@ -205,7 +203,7 @@ egg_cleanup_parser() { eggyyerror("Undefined vertex pool " + pool->get_name()); } else { eggyyerror("Undefined vertices in pool " + pool->get_name()); - + egg_cat.error(false) << "Undefined vertex index numbers:"; EggVertexPool::const_iterator vi; @@ -216,7 +214,7 @@ egg_cleanup_parser() { << " " << vertex->get_index(); } } - egg_cat.error(false) + egg_cat.error(false) << "\n"; } } @@ -232,14 +230,18 @@ egg_cleanup_parser() { } - -/* Line 189 of yacc.c */ -#line 234 "y.tab.c" - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif +#line 234 "built/tmp/parser.yxx.c" /* yacc.c:338 */ +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE @@ -249,108 +251,113 @@ egg_cleanup_parser() { # define YYERROR_VERBOSE 0 #endif -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 +/* In a future release of Bison, this section will be replaced + by #include "parser.yxx.h". */ +#ifndef YY_EGGYY_BUILT_TMP_PARSER_YXX_H_INCLUDED +# define YY_EGGYY_BUILT_TMP_PARSER_YXX_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int eggyydebug; #endif - -/* Tokens. */ +/* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - EGG_NUMBER = 258, - EGG_ULONG = 259, - EGG_STRING = 260, - ANIMPRELOAD = 261, - BEZIERCURVE = 262, - BFACE = 263, - BILLBOARD = 264, - BILLBOARDCENTER = 265, - BINORMAL = 266, - BUNDLE = 267, - CLOSED = 268, - COLLIDE = 269, - COMMENT = 270, - COMPONENT = 271, - COORDSYSTEM = 272, - CV = 273, - DART = 274, - DNORMAL = 275, - DRGBA = 276, - DUV = 277, - DXYZ = 278, - DCS = 279, - DISTANCE = 280, - DTREF = 281, - DYNAMICVERTEXPOOL = 282, - EXTERNAL_FILE = 283, - GROUP = 284, - DEFAULTPOSE = 285, - JOINT = 286, - KNOTS = 287, - INCLUDE = 288, - INSTANCE = 289, - LINE = 290, - LOOP = 291, - MATERIAL = 292, - MATRIX3 = 293, - MATRIX4 = 294, - MODEL = 295, - MREF = 296, - NORMAL = 297, - NURBSCURVE = 298, - NURBSSURFACE = 299, - OBJECTTYPE = 300, - ORDER = 301, - OUTTANGENT = 302, - PATCH = 303, - POINTLIGHT = 304, - POLYGON = 305, - REF = 306, - RGBA = 307, - ROTATE = 308, - ROTX = 309, - ROTY = 310, - ROTZ = 311, - SANIM = 312, - SCALAR = 313, - SCALE = 314, - SEQUENCE = 315, - SHADING = 316, - SWITCH = 317, - SWITCHCONDITION = 318, - TABLE = 319, - TABLE_V = 320, - TAG = 321, - TANGENT = 322, - TEXLIST = 323, - TEXTURE = 324, - TLENGTHS = 325, - TRANSFORM = 326, - TRANSLATE = 327, - TREF = 328, - TRIANGLEFAN = 329, - TRIANGLESTRIP = 330, - TRIM = 331, - TXT = 332, - UKNOTS = 333, - UV = 334, - AUX = 335, - VKNOTS = 336, - VERTEX = 337, - VERTEXANIM = 338, - VERTEXPOOL = 339, - VERTEXREF = 340, - XFMANIM = 341, - XFMSANIM = 342, - START_EGG = 343, - START_GROUP_BODY = 344, - START_TEXTURE_BODY = 345, - START_PRIMITIVE_BODY = 346 - }; + enum yytokentype + { + EGG_NUMBER = 258, + EGG_ULONG = 259, + EGG_STRING = 260, + ANIMPRELOAD = 261, + BEZIERCURVE = 262, + BFACE = 263, + BILLBOARD = 264, + BILLBOARDCENTER = 265, + BINORMAL = 266, + BUNDLE = 267, + CLOSED = 268, + COLLIDE = 269, + COMMENT = 270, + COMPONENT = 271, + COORDSYSTEM = 272, + CV = 273, + DART = 274, + DNORMAL = 275, + DRGBA = 276, + DUV = 277, + DXYZ = 278, + DCS = 279, + DISTANCE = 280, + DTREF = 281, + DYNAMICVERTEXPOOL = 282, + EXTERNAL_FILE = 283, + GROUP = 284, + DEFAULTPOSE = 285, + JOINT = 286, + KNOTS = 287, + INCLUDE = 288, + INSTANCE = 289, + LINE = 290, + LOOP = 291, + MATERIAL = 292, + MATRIX3 = 293, + MATRIX4 = 294, + MODEL = 295, + MREF = 296, + NORMAL = 297, + NURBSCURVE = 298, + NURBSSURFACE = 299, + OBJECTTYPE = 300, + ORDER = 301, + OUTTANGENT = 302, + PATCH = 303, + POINTLIGHT = 304, + POLYGON = 305, + REF = 306, + RGBA = 307, + ROTATE = 308, + ROTX = 309, + ROTY = 310, + ROTZ = 311, + SANIM = 312, + SCALAR = 313, + SCALE = 314, + SEQUENCE = 315, + SHADING = 316, + SWITCH = 317, + SWITCHCONDITION = 318, + TABLE = 319, + TABLE_V = 320, + TAG = 321, + TANGENT = 322, + TEXLIST = 323, + TEXTURE = 324, + TLENGTHS = 325, + TRANSFORM = 326, + TRANSLATE = 327, + TREF = 328, + TRIANGLEFAN = 329, + TRIANGLESTRIP = 330, + TRIM = 331, + TXT = 332, + UKNOTS = 333, + UV = 334, + AUX = 335, + VKNOTS = 336, + VERTEX = 337, + VERTEXANIM = 338, + VERTEXPOOL = 339, + VERTEXREF = 340, + XFMANIM = 341, + XFMSANIM = 342, + START_EGG = 343, + START_GROUP_BODY = 344, + START_TEXTURE_BODY = 345, + START_PRIMITIVE_BODY = 346 + }; #endif /* Tokens. */ #define EGG_NUMBER 258 @@ -443,21 +450,16 @@ egg_cleanup_parser() { #define START_TEXTURE_BODY 345 #define START_PRIMITIVE_BODY 346 +/* Value type. */ +extern YYSTYPE eggyylval; -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +int eggyyparse (void); -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -#endif +#endif /* !YY_EGGYY_BUILT_TMP_PARSER_YXX_H_INCLUDED */ -/* Copy the second part of user declarations. */ - - -/* Line 264 of yacc.c */ -#line 457 "y.tab.c" #ifdef short # undef short @@ -471,23 +473,20 @@ typedef unsigned char yytype_uint8; #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; -#elif (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -typedef signed char yytype_int8; #else -typedef short int yytype_int8; +typedef signed char yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else -typedef unsigned short int yytype_uint16; +typedef unsigned short yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else -typedef short int yytype_int16; +typedef short yytype_int16; #endif #ifndef YYSIZE_T @@ -495,12 +494,11 @@ typedef short int yytype_int16; # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t -# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# elif ! defined YYSIZE_T # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else -# define YYSIZE_T unsigned int +# define YYSIZE_T unsigned # endif #endif @@ -510,38 +508,58 @@ typedef short int yytype_int16; # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ -# define YY_(msgid) msgid +# define YY_(Msgid) Msgid # endif #endif +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) +# define YYUSE(E) ((void) (E)) #else -# define YYUSE(e) /* empty */ +# define YYUSE(E) /* empty */ #endif -/* Identity function, used to suppress warnings about constant conditions. */ -#ifndef lint -# define YYID(n) (n) +#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") #else -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static int -YYID (int yyi) -#else -static int -YYID (yyi) - int yyi; +# define YY_INITIAL_VALUE(Value) Value #endif -{ - return yyi; -} +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + #if ! defined yyoverflow || YYERROR_VERBOSE @@ -560,11 +578,11 @@ YYID (yyi) # define alloca _alloca # else # define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 # endif # endif # endif @@ -572,8 +590,8 @@ YYID (yyi) # endif # ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely @@ -587,25 +605,23 @@ YYID (yyi) # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif -# if (defined __cplusplus && ! defined _STDLIB_H \ +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) + && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc -# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free -# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif @@ -615,7 +631,7 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc @@ -633,64 +649,70 @@ union yyalloc ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif +# define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) #endif +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + /* YYFINAL -- State number of the termination state. */ #define YYFINAL 14 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 1536 +#define YYLAST 1388 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 94 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 127 /* YYNRULES -- Number of rules. */ -#define YYNRULES 277 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 763 +#define YYNRULES 278 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 765 -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 346 -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) +#define YYTRANSLATE(YYX) \ + ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -731,200 +753,41 @@ static const yytype_uint8 yytranslate[] = }; #if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const yytype_uint16 yyprhs[] = -{ - 0, 0, 3, 6, 9, 12, 15, 17, 20, 22, - 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, - 44, 46, 48, 50, 52, 54, 56, 58, 63, 69, - 70, 78, 80, 87, 90, 91, 98, 100, 107, 113, - 120, 121, 128, 130, 133, 134, 140, 141, 148, 150, - 153, 157, 162, 163, 171, 172, 180, 186, 192, 201, - 210, 213, 217, 225, 233, 241, 250, 258, 267, 268, - 273, 277, 286, 295, 300, 310, 320, 321, 328, 329, - 336, 337, 344, 346, 353, 359, 367, 375, 381, 387, - 393, 399, 405, 411, 417, 424, 430, 433, 436, 439, - 442, 448, 451, 453, 455, 458, 459, 465, 466, 472, - 474, 477, 480, 483, 486, 489, 492, 495, 498, 501, - 504, 507, 510, 516, 523, 528, 533, 538, 543, 551, - 557, 564, 569, 574, 576, 586, 591, 593, 610, 620, - 622, 629, 634, 646, 659, 660, 667, 668, 675, 676, - 683, 684, 691, 692, 699, 700, 707, 708, 715, 716, - 723, 725, 731, 737, 739, 740, 748, 754, 760, 766, - 769, 775, 781, 787, 794, 796, 802, 808, 814, 817, - 823, 829, 835, 841, 847, 853, 856, 862, 869, 871, - 877, 883, 889, 892, 898, 904, 910, 916, 922, 929, - 931, 933, 935, 939, 948, 957, 962, 972, 982, 984, - 993, 996, 998, 1000, 1002, 1008, 1010, 1013, 1015, 1017, - 1018, 1025, 1026, 1033, 1035, 1038, 1041, 1044, 1047, 1050, - 1051, 1058, 1060, 1067, 1073, 1074, 1081, 1083, 1090, 1096, - 1097, 1104, 1106, 1113, 1116, 1117, 1124, 1126, 1133, 1135, - 1138, 1140, 1143, 1145, 1147, 1149, 1151, 1153, 1155, 1157, - 1159, 1161, 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, - 1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yytype_int16 yyrhs[] = -{ - 95, 0, -1, 88, 96, -1, 89, 126, -1, 90, - 102, -1, 91, 169, -1, 220, -1, 96, 97, -1, - 98, -1, 99, -1, 100, -1, 103, -1, 106, -1, - 107, -1, 120, -1, 122, -1, 124, -1, 152, -1, - 154, -1, 156, -1, 158, -1, 160, -1, 162, -1, - 164, -1, 166, -1, 187, -1, 201, -1, 17, 92, - 212, 93, -1, 15, 211, 92, 215, 93, -1, -1, - 69, 210, 92, 212, 101, 102, 93, -1, 220, -1, - 102, 58, 210, 92, 218, 93, -1, 102, 129, -1, - -1, 37, 210, 92, 104, 105, 93, -1, 220, -1, - 105, 58, 210, 92, 218, 93, -1, 28, 211, 92, - 212, 93, -1, 214, 28, 211, 92, 212, 93, -1, - -1, 84, 210, 108, 92, 109, 93, -1, 220, -1, - 109, 110, -1, -1, 82, 111, 92, 113, 93, -1, - -1, 82, 219, 112, 92, 113, 93, -1, 217, -1, - 217, 217, -1, 217, 217, 217, -1, 217, 217, 217, - 217, -1, -1, 113, 79, 211, 92, 114, 116, 93, - -1, -1, 113, 80, 210, 92, 115, 117, 93, -1, - 113, 42, 92, 118, 93, -1, 113, 52, 92, 119, - 93, -1, 113, 23, 214, 92, 217, 217, 217, 93, - -1, 113, 23, 92, 214, 217, 217, 217, 93, -1, - 217, 217, -1, 217, 217, 217, -1, 116, 67, 92, - 217, 217, 217, 93, -1, 116, 11, 92, 217, 217, - 217, 93, -1, 116, 22, 214, 92, 217, 217, 93, - -1, 116, 22, 214, 92, 217, 217, 217, 93, -1, - 116, 22, 92, 214, 217, 217, 93, -1, 116, 22, - 92, 214, 217, 217, 217, 93, -1, -1, 217, 217, - 217, 217, -1, 217, 217, 217, -1, 118, 20, 214, - 92, 217, 217, 217, 93, -1, 118, 20, 92, 214, - 217, 217, 217, 93, -1, 217, 217, 217, 217, -1, - 119, 21, 214, 92, 217, 217, 217, 217, 93, -1, - 119, 21, 92, 214, 217, 217, 217, 217, 93, -1, - -1, 29, 211, 121, 92, 126, 93, -1, -1, 31, - 211, 123, 92, 126, 93, -1, -1, 34, 211, 125, - 92, 126, 93, -1, 220, -1, 126, 58, 210, 92, - 218, 93, -1, 126, 9, 92, 214, 93, -1, 126, - 10, 92, 217, 217, 217, 93, -1, 126, 14, 211, - 92, 127, 128, 93, -1, 126, 24, 92, 219, 93, - -1, 126, 24, 92, 5, 93, -1, 126, 19, 92, - 219, 93, -1, 126, 19, 92, 5, 93, -1, 126, - 62, 92, 219, 93, -1, 126, 45, 92, 212, 93, - -1, 126, 40, 92, 219, 93, -1, 126, 66, 211, - 92, 215, 93, -1, 126, 68, 92, 219, 93, -1, - 126, 129, -1, 126, 131, -1, 126, 148, -1, 126, - 150, -1, 126, 51, 92, 209, 93, -1, 126, 97, - -1, 214, -1, 220, -1, 128, 214, -1, -1, 71, - 130, 92, 133, 93, -1, -1, 30, 132, 92, 133, - 93, -1, 220, -1, 133, 134, -1, 133, 135, -1, - 133, 136, -1, 133, 137, -1, 133, 138, -1, 133, - 139, -1, 133, 140, -1, 133, 141, -1, 133, 142, - -1, 133, 143, -1, 133, 144, -1, 133, 146, -1, - 72, 92, 217, 217, 93, -1, 72, 92, 217, 217, - 217, 93, -1, 53, 92, 217, 93, -1, 54, 92, - 217, 93, -1, 55, 92, 217, 93, -1, 56, 92, - 217, 93, -1, 53, 92, 217, 217, 217, 217, 93, - -1, 59, 92, 217, 217, 93, -1, 59, 92, 217, - 217, 217, 93, -1, 59, 92, 217, 93, -1, 38, - 92, 145, 93, -1, 220, -1, 217, 217, 217, 217, - 217, 217, 217, 217, 217, -1, 39, 92, 147, 93, - -1, 220, -1, 217, 217, 217, 217, 217, 217, 217, - 217, 217, 217, 217, 217, 217, 217, 217, 217, -1, - 85, 92, 204, 149, 51, 92, 208, 93, 93, -1, - 220, -1, 149, 58, 210, 92, 218, 93, -1, 63, - 92, 151, 93, -1, 25, 92, 217, 217, 82, 92, - 217, 217, 217, 93, 93, -1, 25, 92, 217, 217, - 217, 82, 92, 217, 217, 217, 93, 93, -1, -1, - 50, 211, 153, 92, 169, 93, -1, -1, 74, 211, - 155, 92, 169, 93, -1, -1, 75, 211, 157, 92, - 169, 93, -1, -1, 48, 211, 159, 92, 169, 93, - -1, -1, 49, 211, 161, 92, 169, 93, -1, -1, - 35, 211, 163, 92, 169, 93, -1, -1, 44, 211, - 165, 92, 171, 93, -1, -1, 43, 211, 167, 92, - 172, 93, -1, 220, -1, 168, 42, 92, 176, 93, - -1, 168, 52, 92, 177, 93, -1, 220, -1, -1, - 169, 16, 219, 92, 170, 168, 93, -1, 169, 73, - 92, 173, 93, -1, 169, 69, 92, 174, 93, -1, - 169, 41, 92, 175, 93, -1, 169, 179, -1, 169, - 42, 92, 176, 93, -1, 169, 52, 92, 177, 93, - -1, 169, 8, 92, 178, 93, -1, 169, 58, 210, - 92, 218, 93, -1, 220, -1, 171, 73, 92, 173, - 93, -1, 171, 69, 92, 174, 93, -1, 171, 41, - 92, 175, 93, -1, 171, 179, -1, 171, 42, 92, - 176, 93, -1, 171, 52, 92, 177, 93, -1, 171, - 8, 92, 178, 93, -1, 171, 46, 92, 180, 93, - -1, 171, 78, 92, 181, 93, -1, 171, 81, 92, - 182, 93, -1, 171, 166, -1, 171, 76, 92, 183, - 93, -1, 171, 58, 210, 92, 218, 93, -1, 220, - -1, 172, 73, 92, 173, 93, -1, 172, 69, 92, - 174, 93, -1, 172, 41, 92, 175, 93, -1, 172, - 179, -1, 172, 42, 92, 176, 93, -1, 172, 52, - 92, 177, 93, -1, 172, 8, 92, 178, 93, -1, - 172, 46, 92, 185, 93, -1, 172, 32, 92, 186, - 93, -1, 172, 58, 210, 92, 218, 93, -1, 206, - -1, 210, -1, 207, -1, 217, 217, 217, -1, 176, - 20, 214, 92, 217, 217, 217, 93, -1, 176, 20, - 92, 214, 217, 217, 217, 93, -1, 217, 217, 217, - 217, -1, 177, 21, 214, 92, 217, 217, 217, 217, - 93, -1, 177, 21, 92, 214, 217, 217, 217, 217, - 93, -1, 219, -1, 85, 92, 204, 51, 92, 208, - 93, 93, -1, 219, 219, -1, 205, -1, 205, -1, - 220, -1, 183, 36, 92, 184, 93, -1, 220, -1, - 184, 166, -1, 219, -1, 205, -1, -1, 64, 211, - 188, 92, 191, 93, -1, -1, 12, 211, 190, 92, - 191, 93, -1, 220, -1, 191, 187, -1, 191, 189, - -1, 191, 192, -1, 191, 195, -1, 191, 198, -1, - -1, 57, 211, 193, 92, 194, 93, -1, 220, -1, - 194, 58, 210, 92, 218, 93, -1, 194, 65, 92, - 205, 93, -1, -1, 86, 211, 196, 92, 197, 93, - -1, 220, -1, 197, 58, 210, 92, 218, 93, -1, - 197, 65, 92, 205, 93, -1, -1, 87, 211, 199, - 92, 200, 93, -1, 220, -1, 200, 58, 210, 92, - 218, 93, -1, 200, 192, -1, -1, 6, 211, 202, - 92, 203, 93, -1, 220, -1, 203, 58, 210, 92, - 218, 93, -1, 220, -1, 204, 219, -1, 220, -1, - 205, 217, -1, 210, -1, 210, -1, 210, -1, 210, - -1, 220, -1, 214, -1, 213, -1, 220, -1, 214, - -1, 220, -1, 214, -1, 3, -1, 4, -1, 5, - -1, 220, -1, 216, -1, 214, -1, 216, 214, -1, - 3, -1, 4, -1, 3, -1, 4, -1, 5, -1, - 3, -1, 4, -1, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 234, 234, 235, 236, 237, 248, 249, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 294, 317, 332, - 331, 359, 360, 706, 718, 717, 744, 745, 840, 847, - 868, 867, 907, 908, 920, 919, 931, 930, 976, 980, - 984, 988, 993, 992, 1008, 1007, 1022, 1023, 1024, 1032, - 1051, 1055, 1059, 1067, 1075, 1083, 1091, 1099, 1116, 1117, - 1131, 1135, 1143, 1161, 1165, 1173, 1192, 1191, 1217, 1216, - 1238, 1237, 1262, 1263, 1408, 1420, 1425, 1432, 1438, 1451, - 1458, 1471, 1477, 1483, 1489, 1494, 1500, 1501, 1502, 1503, - 1504, 1513, 1527, 1557, 1558, 1581, 1580, 1597, 1596, 1617, - 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626, 1627, - 1628, 1629, 1633, 1640, 1647, 1654, 1661, 1668, 1675, 1682, - 1689, 1696, 1703, 1707, 1708, 1720, 1724, 1725, 1747, 1780, - 1784, 1809, 1821, 1826, 1844, 1843, 1863, 1862, 1882, 1881, - 1901, 1900, 1920, 1919, 1939, 1938, 1958, 1957, 1977, 1976, - 1996, 1997, 1998, 2009, 2011, 2010, 2031, 2032, 2033, 2034, - 2035, 2036, 2037, 2038, 2113, 2114, 2115, 2116, 2117, 2118, - 2119, 2120, 2121, 2122, 2123, 2124, 2130, 2131, 2197, 2198, - 2199, 2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2278, - 2295, 2335, 2352, 2356, 2364, 2382, 2386, 2394, 2412, 2428, - 2459, 2477, 2497, 2517, 2522, 2533, 2539, 2558, 2574, 2596, - 2595, 2619, 2618, 2639, 2640, 2644, 2648, 2652, 2656, 2672, - 2671, 2692, 2693, 2705, 2720, 2719, 2740, 2741, 2758, 2773, - 2772, 2793, 2794, 2809, 2825, 2824, 2845, 2846, 2870, 2874, - 2888, 2892, 2906, 2927, 2948, 2973, 2994, 2999, 3011, 3023, - 3028, 3039, 3043, 3057, 3061, 3065, 3078, 3082, 3098, 3102, - 3116, 3117, 3132, 3138, 3144, 3161, 3169, 3175 + 0, 239, 239, 240, 241, 242, 253, 254, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 287, 288, 299, 322, 337, + 336, 364, 365, 720, 732, 731, 758, 759, 880, 887, + 908, 907, 947, 948, 960, 959, 971, 970, 1016, 1020, + 1024, 1028, 1033, 1032, 1048, 1047, 1062, 1063, 1064, 1072, + 1091, 1095, 1099, 1107, 1115, 1123, 1131, 1139, 1147, 1164, + 1165, 1179, 1183, 1191, 1209, 1213, 1221, 1240, 1239, 1265, + 1264, 1286, 1285, 1310, 1311, 1459, 1471, 1476, 1483, 1489, + 1502, 1509, 1522, 1528, 1534, 1540, 1545, 1551, 1552, 1553, + 1554, 1555, 1564, 1578, 1608, 1609, 1632, 1631, 1648, 1647, + 1668, 1669, 1670, 1671, 1672, 1673, 1674, 1675, 1676, 1677, + 1678, 1679, 1680, 1684, 1691, 1698, 1705, 1712, 1719, 1726, + 1733, 1740, 1747, 1754, 1758, 1759, 1771, 1775, 1776, 1798, + 1831, 1835, 1860, 1872, 1877, 1895, 1894, 1914, 1913, 1933, + 1932, 1952, 1951, 1971, 1970, 1990, 1989, 2009, 2008, 2028, + 2027, 2047, 2048, 2049, 2060, 2062, 2061, 2082, 2083, 2084, + 2085, 2086, 2087, 2088, 2089, 2164, 2165, 2166, 2167, 2168, + 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2181, 2182, 2248, + 2249, 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257, 2258, + 2329, 2346, 2386, 2403, 2407, 2415, 2433, 2437, 2445, 2463, + 2479, 2510, 2528, 2548, 2568, 2573, 2584, 2590, 2609, 2625, + 2647, 2646, 2670, 2669, 2690, 2691, 2695, 2699, 2703, 2707, + 2723, 2722, 2743, 2744, 2756, 2771, 2770, 2791, 2792, 2809, + 2824, 2823, 2844, 2845, 2860, 2876, 2875, 2896, 2897, 2921, + 2925, 2939, 2943, 2957, 2978, 2999, 3024, 3045, 3050, 3062, + 3074, 3079, 3090, 3094, 3108, 3112, 3116, 3129, 3133, 3149, + 3153, 3167, 3168, 3183, 3189, 3195, 3212, 3220, 3226 }; #endif -#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +#if YYDEBUG || YYERROR_VERBOSE || 0 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = @@ -972,13 +835,13 @@ static const char *const yytname[] = "texture_name", "material_name", "vertex_pool_name", "group_name", "required_name", "optional_name", "required_string", "optional_string", "string", "repeated_string", "repeated_string_body", "real", - "real_or_string", "integer", "empty", 0 + "real_or_string", "integer", "empty", YY_NULLPTR }; #endif # ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, @@ -994,157 +857,202 @@ static const yytype_uint16 yytoknum[] = }; # endif -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = +#define YYPACT_NINF -430 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-430))) + +#define YYTABLE_NINF -1 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = { - 0, 94, 95, 95, 95, 95, 96, 96, 97, 97, - 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97, 97, 98, 99, 101, - 100, 102, 102, 102, 104, 103, 105, 105, 106, 106, - 108, 107, 109, 109, 111, 110, 112, 110, 113, 113, - 113, 113, 114, 113, 115, 113, 113, 113, 113, 113, - 116, 116, 116, 116, 116, 116, 116, 116, 117, 117, - 118, 118, 118, 119, 119, 119, 121, 120, 123, 122, - 125, 124, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 127, 128, 128, 130, 129, 132, 131, 133, - 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, - 133, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 145, 146, 147, 147, 148, 149, - 149, 150, 151, 151, 153, 152, 155, 154, 157, 156, - 159, 158, 161, 160, 163, 162, 165, 164, 167, 166, - 168, 168, 168, 169, 170, 169, 169, 169, 169, 169, - 169, 169, 169, 169, 171, 171, 171, 171, 171, 171, - 171, 171, 171, 171, 171, 171, 171, 171, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 173, - 174, 175, 176, 176, 176, 177, 177, 177, 178, 179, - 180, 181, 182, 183, 183, 184, 184, 185, 186, 188, - 187, 190, 189, 191, 191, 191, 191, 191, 191, 193, - 192, 194, 194, 194, 196, 195, 197, 197, 197, 199, - 198, 200, 200, 200, 202, 201, 203, 203, 204, 204, - 205, 205, 206, 207, 208, 209, 210, 210, 211, 212, - 212, 213, 213, 214, 214, 214, 215, 215, 216, 216, - 217, 217, 218, 218, 218, 219, 219, 220 + 211, -430, -430, -430, -430, 14, 1060, -430, 1206, -430, + 141, -430, 495, -430, -430, -430, -430, -430, 329, 329, + -55, 329, 329, 329, 329, 329, 329, 329, 329, 329, + 329, 329, 329, 329, 329, 329, 329, -430, -430, -430, + -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, + -430, -430, -430, -430, -430, -430, -430, 70, 10, 22, + 329, 68, 114, -430, 119, 125, 134, 329, 150, 152, + 329, 164, -430, 169, -430, -430, -430, -430, -430, 329, + -430, 172, 185, 174, 175, 180, 329, 182, 191, 192, + -430, -430, -430, -430, -430, 203, 329, 215, -430, -430, + -430, -430, 220, -430, -430, -430, -430, -430, -430, -430, + -430, 226, -430, -430, -430, 329, 329, 255, 228, 347, + 374, 230, 185, 329, 329, 235, 185, 99, 236, 185, + 243, -430, 244, 185, -430, -430, 247, 329, 255, 255, + 249, 329, 329, -430, 253, 329, 57, -430, -430, 329, + 261, 273, 274, 279, -430, 283, 290, 300, 303, 313, + 323, 329, 326, 331, 333, 334, 184, -430, -430, 255, + 329, 188, 210, 251, 254, -430, 262, 287, 328, -430, + 385, 335, 337, 338, 329, 345, -430, 185, -430, 385, + 346, -430, -430, 348, -430, -430, 29, 255, 23, 255, + 385, 349, -430, 352, -430, -430, 131, -430, -430, 353, + 329, -430, -430, 356, -430, -430, -430, -430, -430, -430, + -430, -430, -430, -430, -430, -430, -430, -430, -430, 329, + -430, 255, -430, -430, -430, -430, -430, -430, 381, -430, + -430, -430, -430, -430, -430, -430, 361, -430, 255, -430, + 362, -430, 441, 170, -430, -430, 365, -430, -430, -430, + 69, -430, 255, 73, -430, 255, 366, -430, -430, 369, + 74, -430, -430, -430, -430, 789, 983, 1133, 221, 140, + -430, 145, -430, 167, -430, 288, 375, 435, 189, -430, + -430, 827, 864, 75, -430, 376, 378, 4, -430, 380, + 383, 386, 389, 391, 393, 396, 397, -430, -430, -430, + -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, + -430, 255, -430, -430, 398, 329, -430, 59, -430, 329, + 399, -430, 329, 400, 255, -430, 329, 329, -430, -430, + -430, -430, -430, 329, -430, 406, 407, 409, 414, 418, + 420, 329, 425, 426, -430, -430, 427, 429, 434, 437, + 438, 329, 439, 440, 443, 446, 447, -430, -430, -430, + -430, -430, -430, 329, 329, 329, 329, -430, -430, -430, + -430, -430, -430, 123, -430, -430, 185, -430, -430, -430, + -430, -430, -430, 255, 255, 255, 255, 255, 255, 255, + 255, 76, 329, 448, 449, 450, -430, 255, 255, 255, + 255, -430, 451, -430, 453, 454, 185, -430, 329, 255, + 185, 255, 456, 329, 329, 185, 329, 255, 185, 255, + 457, 329, 329, -430, -430, -430, -430, -430, -430, -430, + -430, 458, -430, 459, 255, -430, 461, 255, -430, 7, + 462, 463, 469, 44, 255, 471, 80, 472, 385, 255, + 255, 255, 255, 255, 255, 476, 385, 385, 477, 478, + 255, -430, 479, 32, 480, -430, 86, 385, 483, 485, + 488, 490, 43, 491, 185, 92, 385, 492, 493, 53, + -430, 494, 255, 497, 255, 499, 500, 501, 506, 255, + 508, -430, 255, -430, 255, -430, 255, -430, -430, -430, + -430, 47, 52, 255, 512, 513, 514, 55, 97, 255, + 255, 255, 255, -430, 515, 516, -430, -430, -430, -430, + -430, -430, -430, 518, -430, -430, -430, -430, -430, -430, + -430, -430, 519, -430, -430, 522, -430, -430, -430, -430, + -430, -430, -430, 263, 255, 255, 255, 255, 255, -430, + 523, -430, 524, 255, 255, -430, -430, -430, -430, 525, + 526, 255, 255, -430, -430, -430, -430, -430, 223, 157, + -430, 162, -430, 138, -430, 79, 528, 531, 329, 329, + -430, 255, 269, 255, 255, 533, -430, -430, 255, 255, + -430, -430, 536, 537, 61, -430, -430, 329, 532, -430, + 329, 540, -430, 329, -430, -430, 329, 541, 255, 255, + 542, 543, 255, -430, 255, 255, -430, 544, 255, -430, + -430, -430, -430, 546, -430, 547, -430, 548, 255, 255, + 83, 255, 100, 255, -430, -430, -430, 255, 255, 550, + 552, 385, 54, 385, 56, 385, 255, 255, 82, -430, + 255, 88, -430, 255, 255, 255, 255, 255, -430, 554, + 555, -430, 556, -430, 560, 255, 255, 329, 564, -430, + 329, 565, 255, 77, 255, 568, 255, 255, 255, -430, + -430, -430, -430, 569, 571, 255, 255, 255, 255, -430, + 566, 91, 573, -430, 255, -430, 255, -430, 255, -430, + -430, 255, 255, 255, 255, 255, 329, 580, 255, -430, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + -430, 255, 584, 587, 255, 255, 255, 255, 255, 255, + 255, -430, -430, 588, 589, 593, 58, 63, 66, 255, + -430, -430, -430, -430, 595, -430, 599, -430, 600, 255, + -430, -430, -430, 255, -430 }; -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 2, 2, 2, 2, 1, 2, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 4, 5, 0, - 7, 1, 6, 2, 0, 6, 1, 6, 5, 6, - 0, 6, 1, 2, 0, 5, 0, 6, 1, 2, - 3, 4, 0, 7, 0, 7, 5, 5, 8, 8, - 2, 3, 7, 7, 7, 8, 7, 8, 0, 4, - 3, 8, 8, 4, 9, 9, 0, 6, 0, 6, - 0, 6, 1, 6, 5, 7, 7, 5, 5, 5, - 5, 5, 5, 5, 6, 5, 2, 2, 2, 2, - 5, 2, 1, 1, 2, 0, 5, 0, 5, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 5, 6, 4, 4, 4, 4, 7, 5, - 6, 4, 4, 1, 9, 4, 1, 16, 9, 1, - 6, 4, 11, 12, 0, 6, 0, 6, 0, 6, - 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, - 1, 5, 5, 1, 0, 7, 5, 5, 5, 2, - 5, 5, 5, 6, 1, 5, 5, 5, 2, 5, - 5, 5, 5, 5, 5, 2, 5, 6, 1, 5, - 5, 5, 2, 5, 5, 5, 5, 5, 6, 1, - 1, 1, 3, 8, 8, 4, 9, 9, 1, 8, - 2, 1, 1, 1, 5, 1, 2, 1, 1, 0, - 6, 0, 6, 1, 2, 2, 2, 2, 2, 0, - 6, 1, 6, 5, 0, 6, 1, 6, 5, 0, - 6, 1, 6, 2, 0, 6, 1, 6, 1, 2, - 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 1, 1, 1, 1, 1, 1, 1, 0 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ static const yytype_uint16 yydefact[] = { - 0, 277, 277, 277, 277, 0, 2, 6, 3, 82, - 4, 31, 5, 163, 1, 263, 264, 265, 277, 277, - 0, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 7, 8, 9, + 0, 278, 278, 278, 278, 0, 2, 6, 3, 83, + 4, 31, 5, 164, 1, 264, 265, 266, 278, 278, + 0, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 278, 278, 278, 278, 278, 278, 278, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, - 277, 0, 0, 107, 0, 0, 0, 277, 0, 0, - 277, 0, 105, 0, 101, 96, 97, 98, 99, 277, - 33, 0, 0, 0, 0, 0, 277, 0, 0, 0, - 169, 244, 258, 262, 261, 0, 277, 0, 76, 78, - 80, 154, 0, 257, 256, 158, 156, 150, 152, 144, - 219, 0, 146, 148, 40, 277, 0, 0, 0, 0, - 0, 0, 0, 277, 277, 0, 0, 0, 0, 0, - 0, 277, 0, 0, 275, 276, 0, 277, 0, 0, - 0, 277, 277, 277, 0, 277, 0, 260, 259, 277, + 278, 0, 0, 108, 0, 0, 0, 278, 0, 0, + 278, 0, 106, 0, 102, 97, 98, 99, 100, 278, + 33, 0, 0, 0, 0, 0, 278, 0, 0, 0, + 170, 245, 259, 263, 262, 0, 278, 0, 77, 79, + 81, 155, 0, 258, 257, 159, 157, 151, 153, 145, + 220, 0, 147, 149, 40, 278, 0, 0, 0, 0, + 0, 0, 0, 278, 278, 0, 0, 0, 0, 0, + 0, 278, 0, 0, 276, 277, 0, 278, 0, 0, + 0, 278, 278, 278, 0, 278, 0, 261, 260, 278, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, - 0, 277, 0, 0, 0, 0, 0, 270, 271, 0, - 0, 0, 0, 0, 0, 277, 0, 0, 0, 255, - 0, 0, 0, 0, 277, 0, 277, 277, 248, 0, - 0, 208, 164, 0, 201, 253, 0, 0, 0, 0, - 0, 0, 200, 0, 199, 252, 0, 277, 268, 0, - 267, 266, 27, 0, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 29, 277, 277, 277, 277, - 84, 0, 277, 102, 90, 89, 88, 87, 0, 109, - 93, 92, 100, 272, 273, 274, 0, 91, 0, 141, - 0, 95, 0, 0, 249, 139, 0, 172, 277, 168, - 0, 170, 0, 0, 171, 0, 0, 167, 166, 0, - 0, 246, 28, 269, 38, 0, 0, 0, 0, 0, - 36, 0, 188, 0, 174, 0, 0, 0, 0, 223, - 277, 0, 0, 0, 42, 0, 0, 0, 103, 0, - 0, 0, 0, 0, 0, 0, 0, 108, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 83, 0, 94, 106, 0, 277, 32, 0, 160, 0, - 0, 202, 0, 0, 0, 173, 277, 277, 245, 77, - 79, 81, 155, 277, 35, 0, 0, 0, 0, 0, - 0, 277, 0, 0, 159, 192, 0, 0, 0, 0, - 0, 277, 0, 0, 0, 0, 0, 157, 185, 178, - 151, 153, 145, 277, 277, 277, 277, 220, 224, 225, - 226, 227, 228, 0, 147, 149, 44, 41, 43, 39, - 85, 86, 104, 277, 277, 0, 0, 0, 0, 0, - 0, 0, 277, 0, 0, 0, 165, 0, 0, 0, - 0, 205, 0, 254, 0, 0, 0, 277, 277, 0, - 0, 0, 0, 277, 277, 0, 277, 0, 0, 0, - 0, 277, 277, 277, 277, 277, 221, 229, 234, 239, - 30, 0, 46, 0, 0, 133, 0, 0, 136, 0, + 0, 278, 0, 0, 0, 0, 0, 271, 272, 0, + 0, 0, 0, 0, 0, 278, 0, 0, 0, 256, + 0, 0, 0, 0, 278, 0, 278, 278, 249, 0, + 0, 209, 165, 0, 202, 254, 0, 0, 0, 0, + 0, 0, 201, 0, 200, 253, 0, 278, 269, 0, + 268, 267, 27, 0, 278, 278, 278, 278, 278, 278, + 278, 278, 278, 278, 278, 29, 278, 278, 278, 278, + 85, 0, 278, 103, 91, 90, 89, 88, 0, 110, + 94, 93, 101, 273, 274, 275, 0, 92, 0, 142, + 0, 96, 0, 0, 250, 140, 0, 173, 278, 169, + 0, 171, 0, 0, 172, 0, 0, 168, 167, 0, + 0, 247, 28, 270, 38, 0, 0, 0, 0, 0, + 36, 0, 189, 0, 175, 0, 0, 0, 0, 224, + 278, 0, 0, 0, 42, 0, 0, 0, 104, 0, + 0, 0, 0, 0, 0, 0, 0, 109, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 84, 0, 95, 107, 0, 278, 32, 0, 161, 0, + 0, 203, 0, 0, 0, 174, 278, 278, 246, 78, + 80, 82, 156, 278, 35, 0, 0, 0, 0, 0, + 0, 278, 0, 0, 160, 193, 0, 0, 0, 0, + 0, 278, 0, 0, 0, 0, 0, 158, 186, 179, + 152, 154, 146, 278, 278, 278, 278, 221, 225, 226, + 227, 228, 229, 0, 148, 150, 44, 41, 43, 39, + 86, 87, 105, 278, 278, 0, 0, 0, 0, 0, + 0, 0, 278, 0, 0, 0, 166, 0, 0, 0, + 0, 206, 0, 255, 0, 0, 0, 278, 278, 0, + 0, 0, 0, 278, 278, 0, 278, 0, 0, 0, + 0, 278, 278, 278, 278, 278, 222, 230, 235, 240, + 30, 0, 46, 0, 0, 134, 0, 0, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 218, 250, 0, 0, 0, 217, 0, 0, 0, 0, + 219, 251, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 213, 0, 211, 0, 212, 0, 0, 0, 0, 0, - 0, 132, 0, 135, 0, 124, 0, 125, 126, 127, - 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 209, 0, 0, 195, 197, 251, 191, - 193, 196, 194, 0, 190, 189, 181, 177, 179, 182, - 210, 180, 0, 176, 175, 0, 186, 183, 184, 277, - 277, 277, 277, 0, 48, 0, 0, 0, 0, 129, - 0, 122, 0, 0, 0, 138, 140, 161, 162, 0, - 0, 0, 0, 247, 37, 198, 187, 277, 0, 0, - 231, 0, 236, 0, 241, 0, 0, 0, 277, 277, - 45, 49, 0, 0, 0, 0, 130, 123, 0, 0, - 204, 203, 0, 0, 0, 215, 222, 277, 0, 230, - 277, 0, 235, 277, 240, 243, 0, 0, 0, 0, - 0, 0, 50, 47, 0, 0, 128, 0, 0, 207, - 206, 214, 216, 0, 277, 0, 277, 0, 0, 0, + 214, 0, 212, 0, 213, 0, 0, 0, 0, 0, + 0, 133, 0, 136, 0, 125, 0, 126, 127, 128, + 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 210, 0, 0, 196, 198, 252, 192, + 194, 197, 195, 0, 191, 190, 182, 178, 180, 183, + 211, 181, 0, 177, 176, 0, 187, 184, 185, 278, + 278, 278, 278, 0, 48, 0, 0, 0, 0, 130, + 0, 123, 0, 0, 0, 139, 141, 162, 163, 0, + 0, 0, 0, 248, 37, 199, 188, 278, 0, 0, + 232, 0, 237, 0, 242, 0, 0, 0, 278, 278, + 45, 49, 0, 0, 0, 0, 131, 124, 0, 0, + 205, 204, 0, 0, 0, 216, 223, 278, 0, 231, + 278, 0, 236, 278, 241, 244, 0, 0, 0, 0, + 0, 0, 50, 47, 0, 0, 129, 0, 0, 208, + 207, 215, 217, 0, 278, 0, 278, 0, 0, 0, 0, 0, 0, 0, 52, 54, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, - 0, 0, 57, 0, 0, 68, 0, 0, 142, 0, - 0, 233, 0, 238, 0, 0, 0, 0, 0, 70, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, - 232, 237, 242, 0, 0, 0, 0, 0, 0, 73, - 0, 0, 0, 53, 60, 55, 0, 134, 0, 59, + 0, 0, 57, 0, 0, 69, 0, 0, 143, 0, + 0, 234, 0, 239, 0, 0, 0, 0, 0, 71, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, + 233, 238, 243, 0, 0, 0, 0, 0, 0, 74, + 0, 0, 0, 53, 60, 55, 0, 135, 0, 59, 58, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 72, 71, 0, 0, 0, 0, 0, 0, 0, - 75, 74, 63, 66, 0, 64, 0, 62, 0, 67, - 65, 0, 137 + 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 73, 72, 0, 0, 0, 0, 0, 0, 0, + 76, 75, 64, 67, 0, 65, 0, 62, 0, 0, + 68, 66, 63, 0, 138 }; -/* YYDEFGOTO[NTERM-NUM]. */ + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -430, -430, -430, 160, -430, -430, -430, -430, -106, -430, + -430, -430, -430, -430, -430, -430, -430, -430, -430, -242, + -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, + -430, -430, 193, -430, -430, -9, -430, -430, -430, 341, + -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, + -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, + -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, + -430, -430, -279, -430, -430, 137, -430, -430, -430, -200, + -184, -177, -296, -291, -297, -154, -430, -430, -430, -430, + -430, -430, -430, -285, -430, -430, -430, -76, -50, -430, + -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, + 408, -429, -430, -430, 213, -430, 252, 11, -96, -430, + -6, 359, -430, 3, -169, -14, 752 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 5, 6, 74, 38, 39, 40, 290, 10, 41, @@ -1162,431 +1070,297 @@ static const yytype_int16 yydefgoto[] = 103, 209, 210, 528, 246, 191, 104 }; -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -430 -static const yytype_int16 yypact[] = -{ - 245, -430, -430, -430, -430, 14, 794, -430, 1451, -430, - 168, -430, 535, -430, -430, -430, -430, -430, 271, 271, - -61, 271, 271, 271, 271, 271, 271, 271, 271, 271, - 271, 271, 271, 271, 271, 271, 271, -430, -430, -430, - -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, - -430, -430, -430, -430, -430, -430, -430, 9, -17, -12, - 271, 6, 10, -430, 12, 42, 46, 271, 74, 106, - 271, 125, -430, 155, -430, -430, -430, -430, -430, 271, - -430, 187, 228, 188, 190, 198, 271, 203, 204, 208, - -430, -430, -430, -430, -430, 209, 271, 219, -430, -430, - -430, -430, 223, -430, -430, -430, -430, -430, -430, -430, - -430, 227, -430, -430, -430, 271, 271, 255, 229, 342, - 345, 230, 228, 271, 271, 235, 228, 137, 236, 228, - 239, -430, 246, 228, -430, -430, 259, 271, 255, 255, - 261, 271, 271, -430, 267, 271, 57, -430, -430, 271, - 272, 273, 274, 279, -430, 281, 283, 284, 287, 288, - 289, 271, 290, 297, 298, 300, 127, -430, -430, 255, - 271, 224, 270, 302, 314, -430, 315, 322, 325, -430, - 353, 330, 301, 332, 271, 333, -430, 228, -430, 353, - 335, -430, -430, 338, -430, -430, 32, 255, 92, 255, - 353, 346, -430, 348, -430, -430, 128, -430, -430, 349, - 271, -430, -430, 352, -430, -430, -430, -430, -430, -430, - -430, -430, -430, -430, -430, -430, -430, -430, -430, 271, - -430, 255, -430, -430, -430, -430, -430, -430, 381, -430, - -430, -430, -430, -430, -430, -430, 356, -430, 255, -430, - 361, -430, 441, 164, -430, -430, 362, -430, -430, -430, - 69, -430, 255, 73, -430, 255, 365, -430, -430, 354, - 53, -430, -430, -430, -430, 975, 1184, 1378, 225, 70, - -430, 145, -430, 167, -430, 247, 336, 375, 95, -430, - -430, 435, 495, 134, -430, 366, 368, 44, -430, 377, - 380, 386, 389, 390, 391, 392, 393, -430, -430, -430, - -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, - -430, 255, -430, -430, 394, 271, -430, 37, -430, 271, - 396, -430, 271, 397, 255, -430, 271, 271, -430, -430, - -430, -430, -430, 271, -430, 398, 399, 400, 406, 407, - 409, 271, 414, 418, -430, -430, 420, 425, 426, 427, - 429, 271, 434, 437, 438, 439, 440, -430, -430, -430, - -430, -430, -430, 271, 271, 271, 271, -430, -430, -430, - -430, -430, -430, 153, -430, -430, 228, -430, -430, -430, - -430, -430, -430, 255, 255, 255, 255, 255, 255, 255, - 255, 66, 271, 443, 446, 447, -430, 255, 255, 255, - 255, -430, 448, -430, 450, 452, 228, -430, 271, 255, - 228, 255, 453, 271, 271, 228, 271, 255, 228, 255, - 454, 271, 271, -430, -430, -430, -430, -430, -430, -430, - -430, 456, -430, 457, 255, -430, 459, 255, -430, 4, - 461, 462, 463, 7, 255, 470, 257, 472, 353, 255, - 255, 255, 255, 255, 255, 476, 353, 353, 477, 478, - 255, -430, 479, 43, 480, -430, 97, 353, 485, 488, - 490, 491, 83, 492, 228, 102, 353, 493, 496, 8, - -430, 497, 255, 498, 255, 471, 500, 503, 506, 255, - 508, -430, 255, -430, 255, -430, 255, -430, -430, -430, - -430, 47, 52, 255, 511, 512, 513, 96, 103, 255, - 255, 255, 255, -430, 514, 516, -430, -430, -430, -430, - -430, -430, -430, 518, -430, -430, -430, -430, -430, -430, - -430, -430, 519, -430, -430, 521, -430, -430, -430, -430, - -430, -430, -430, 250, 255, 255, 255, 255, 255, -430, - 522, -430, 523, 255, 255, -430, -430, -430, -430, 524, - 525, 255, 255, -430, -430, -430, -430, -430, 142, 179, - -430, 191, -430, 100, -430, 79, 527, 531, 271, 271, - -430, 255, 262, 255, 255, 533, -430, -430, 255, 255, - -430, -430, 536, 537, 76, -430, -430, 271, 532, -430, - 271, 540, -430, 271, -430, -430, 271, 541, 255, 255, - 542, 543, 255, -430, 255, 255, -430, 544, 255, -430, - -430, -430, -430, 546, -430, 547, -430, 548, 255, 255, - 101, 255, 108, 255, -430, -430, -430, 255, 255, 550, - 552, 353, 54, 353, 56, 353, 255, 255, 82, -430, - 255, 88, -430, 255, 255, 255, 255, 255, -430, 554, - 555, -430, 556, -430, 560, 255, 255, 271, 562, -430, - 271, 564, 255, 77, 255, 565, 255, 255, 255, -430, - -430, -430, -430, 568, 569, 255, 255, 255, 255, -430, - 572, 91, 573, -430, 255, -430, 255, -430, 255, -430, - -430, 255, 255, 255, 255, 255, 271, 580, 255, -430, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - -430, 255, 582, 583, 255, 255, 255, 255, 255, 255, - 255, -430, -430, 584, 587, 588, 58, 63, 589, 255, - -430, -430, -430, -430, 590, -430, 591, -430, 255, -430, - -430, 255, -430 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -430, -430, -430, 178, -430, -430, -430, -430, 64, -430, - -430, -430, -430, -430, -430, -430, -430, -430, -430, -117, - -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, - -430, -430, 146, -430, -430, -9, -430, -430, -430, 341, - -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, - -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, - -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, - -430, -430, -279, -430, -430, 86, -430, -430, -430, -310, - -263, -165, -292, -179, -204, -19, -430, -430, -430, -430, - -430, -430, -430, -285, -430, -430, -430, -16, -43, -430, - -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, - 530, -429, -430, -430, 147, -430, 760, 11, -96, -430, - -6, 430, -430, 3, -180, -14, 744 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -1 + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint16 yytable[] = { - 57, 80, 57, 378, 368, 492, 494, 167, 168, 256, + 57, 80, 57, 378, 368, 492, 494, 15, 16, 17, 167, 168, 93, 93, 14, 93, 93, 93, 93, 93, - 266, 93, 93, 93, 93, 93, 93, 177, 93, 93, - 95, 96, 97, 98, 99, 100, 101, 115, 105, 106, - 107, 108, 109, 110, 545, 112, 113, 15, 16, 17, + 256, 93, 93, 93, 93, 93, 93, 177, 93, 93, + 95, 266, 97, 98, 99, 100, 101, 96, 105, 106, + 107, 108, 109, 110, 263, 112, 113, 167, 168, 260, 167, 168, 260, 213, 93, 167, 168, 167, 168, 167, 168, 167, 168, 260, 93, 225, 167, 168, 136, 167, - 168, 118, 15, 16, 17, 116, 15, 16, 17, 404, - 117, 128, 15, 16, 17, 15, 16, 17, 700, 405, - 147, 15, 16, 17, 15, 16, 17, 505, 119, 701, - 510, 546, 120, 260, 122, 172, 174, 373, 176, 93, - 166, 337, 181, 263, 479, 185, 260, 147, 263, 27, - 169, 658, 488, 263, 263, 261, 165, 473, 343, 661, - 406, 134, 135, 295, 123, 482, 530, 391, 124, 208, - 559, 197, 199, 147, 702, 561, 338, 671, 455, 673, - 212, 753, 374, 345, 373, 147, 755, 374, 613, 32, - 478, 329, 182, 344, 233, 332, 126, 517, 487, 631, - 703, 616, 231, 254, 677, 356, 538, 346, 208, 269, - 680, 375, 376, 716, 37, 264, 347, 348, 377, 567, - 532, 349, 254, 614, 659, 541, 568, 350, 127, 374, - 262, 662, 265, 351, 273, 652, 32, 654, 357, 358, - 27, 79, 468, 359, 352, 324, 386, 129, 353, 360, - 230, 480, 325, 147, 72, 361, 79, 387, 375, 376, - 89, 134, 135, 81, 296, 606, 362, 607, 354, 72, - 363, 82, 476, 364, 608, 365, 440, 131, 366, 610, - 485, 321, 89, 472, 330, 81, 611, 333, 167, 168, - 367, 481, 355, 82, 369, 331, 83, 84, 334, 57, - 57, 57, 609, 585, 15, 16, 17, 85, 516, 133, - 137, 518, 138, 86, 612, 585, 524, 525, 83, 84, - 139, 392, 586, 378, 87, 141, 142, 533, 88, 85, - 143, 145, 587, 278, 586, 86, 542, 285, 286, 287, - 89, 149, 291, 292, 587, 154, 87, 234, 342, 161, - 88, 170, 175, 407, 401, 632, 409, 180, 184, 588, - 589, 186, 89, 1, 2, 3, 4, 411, 189, 514, - 370, 588, 589, 590, 81, 134, 135, 171, 134, 135, - 173, 192, 82, 200, 383, 623, 243, 244, 245, 207, - 275, 276, 277, 235, 214, 215, 216, 93, 93, 93, - 93, 217, 442, 219, 80, 220, 221, 83, 84, 222, - 223, 224, 226, 81, 436, 437, 438, 439, 85, 227, - 228, 82, 229, 248, 86, 236, 444, 447, 449, 450, - 451, 452, 453, 454, 456, 87, 475, 237, 240, 88, - 461, 462, 463, 464, 484, 241, 83, 84, 242, 299, - 300, 89, 197, 247, 199, 249, 251, 85, 257, 371, - 197, 259, 199, 86, 301, 302, 303, 304, 592, 267, - 305, 268, 272, 81, 87, 274, 336, 502, 88, 320, - 504, 82, 506, 306, 322, 326, 511, 512, 335, 389, - 89, 390, 197, 199, 519, 520, 521, 522, 372, 393, - 540, 670, 394, 672, 307, 674, 83, 84, 395, 299, - 300, 396, 397, 398, 399, 400, 402, 85, 408, 410, - 416, 417, 418, 86, 301, 302, 303, 304, 419, 420, - 305, 421, 554, 81, 87, 556, 423, 557, 88, 558, - 424, 82, 425, 306, 560, 562, 563, 426, 427, 428, - 89, 429, 569, 570, 571, 572, 431, 252, 384, 432, - 433, 434, 435, 578, 323, 458, 83, 84, 459, 460, - 615, 465, 466, 81, 467, 477, 486, 85, 499, 457, - 501, 82, 503, 86, 507, 508, 509, 591, 554, 593, - 594, 595, 513, 549, 87, 515, 598, 599, 88, 523, - 526, 527, 529, 531, 602, 603, 83, 84, 534, 617, - 89, 535, 93, 536, 537, 539, 543, 85, 385, 544, - 547, 548, 550, 86, 622, 551, 624, 625, 552, 620, - 555, 627, 628, 564, 87, 565, 566, 573, 88, 574, - 638, 575, 576, 577, 250, 596, 597, 600, 601, 618, - 89, 641, 643, 619, 634, 646, 626, 647, 648, 629, + 168, 118, 15, 16, 17, 260, 15, 16, 17, 167, + 168, 128, 15, 16, 17, 15, 16, 17, 700, 545, + 147, 15, 16, 17, 15, 16, 17, 391, 115, 701, + 505, 404, 116, 658, 27, 172, 174, 263, 176, 93, + 166, 405, 181, 263, 117, 185, 264, 147, 263, 468, + 169, 661, 261, 473, 182, 530, 165, 355, 480, 369, + 476, 482, 337, 295, 134, 135, 538, 510, 485, 208, + 559, 197, 199, 147, 702, 561, 546, 671, 567, 673, + 212, 753, 406, 345, 631, 147, 755, 386, 455, 757, + 119, 329, 514, 517, 233, 332, 37, 338, 387, 518, + 703, 616, 231, 254, 677, 356, 659, 346, 208, 532, + 680, 79, 269, 716, 383, 541, 347, 348, 134, 135, + 568, 349, 254, 662, 72, 374, 613, 350, 343, 79, + 262, 373, 265, 351, 273, 652, 120, 654, 357, 358, + 27, 122, 72, 359, 352, 607, 440, 123, 353, 360, + 610, 324, 608, 147, 479, 361, 124, 611, 325, 81, + 89, 614, 488, 344, 296, 373, 362, 82, 354, 478, + 363, 472, 126, 364, 127, 365, 374, 487, 366, 481, + 609, 321, 89, 32, 330, 612, 129, 333, 167, 168, + 367, 131, 83, 84, 133, 331, 137, 138, 334, 57, + 57, 57, 139, 85, 141, 375, 376, 230, 102, 86, + 374, 234, 377, 142, 143, 111, 585, 32, 114, 516, + 87, 392, 585, 378, 88, 145, 81, 524, 525, 1, + 2, 3, 4, 235, 82, 586, 89, 149, 533, 375, + 376, 586, 154, 592, 342, 587, 606, 542, 161, 125, + 170, 587, 175, 407, 401, 632, 409, 180, 184, 83, + 84, 132, 15, 16, 17, 186, 189, 411, 140, 192, + 85, 200, 588, 589, 236, 207, 86, 237, 588, 589, + 134, 135, 171, 214, 278, 240, 590, 87, 285, 286, + 287, 88, 623, 291, 292, 215, 216, 93, 93, 93, + 93, 217, 442, 89, 80, 219, 179, 134, 135, 173, + 241, 370, 220, 81, 436, 437, 438, 439, 243, 244, + 245, 82, 221, 202, 205, 222, 444, 447, 449, 450, + 451, 452, 453, 454, 456, 223, 475, 275, 276, 277, + 461, 462, 463, 464, 484, 224, 83, 84, 226, 299, + 300, 242, 197, 227, 199, 228, 229, 85, 247, 248, + 197, 249, 199, 86, 301, 302, 303, 304, 251, 257, + 305, 259, 267, 81, 87, 268, 272, 502, 88, 274, + 504, 82, 506, 306, 320, 322, 511, 512, 326, 335, + 89, 336, 197, 199, 519, 520, 521, 522, 371, 389, + 540, 390, 393, 578, 307, 394, 83, 84, 395, 299, + 300, 396, 670, 397, 672, 398, 674, 85, 399, 400, + 402, 408, 410, 86, 301, 302, 303, 304, 416, 417, + 305, 418, 554, 81, 87, 556, 419, 557, 88, 558, + 420, 82, 421, 306, 560, 562, 563, 423, 424, 425, + 89, 426, 569, 570, 571, 572, 427, 252, 372, 428, + 429, 431, 432, 615, 323, 433, 83, 84, 434, 435, + 458, 459, 460, 250, 465, 466, 467, 85, 477, 486, + 499, 206, 501, 86, 503, 507, 508, 591, 554, 593, + 594, 595, 509, 513, 87, 515, 598, 599, 88, 523, + 526, 527, 529, 531, 602, 603, 534, 403, 535, 617, + 89, 536, 93, 537, 539, 543, 544, 547, 413, 414, + 548, 549, 550, 551, 622, 415, 624, 625, 552, 620, + 555, 627, 628, 422, 564, 0, 565, 566, 573, 574, + 638, 575, 576, 430, 577, 457, 596, 597, 600, 601, + 618, 641, 643, 619, 634, 646, 626, 647, 648, 629, 630, 650, 636, 639, 644, 645, 0, 649, 651, 653, 655, 656, 657, 668, 660, 669, 663, 689, 690, 691, - 666, 667, 678, 692, 696, 681, 698, 0, 705, 675, - 676, 709, 710, 679, 715, 718, 682, 684, 686, 687, - 688, 695, 728, 206, 697, 741, 742, 750, 693, 694, - 751, 752, 757, 759, 760, 699, 0, 704, 0, 706, - 707, 708, 0, 0, 0, 717, 0, 0, 711, 712, + 666, 667, 678, 692, 413, 681, 696, 698, 715, 675, + 676, 705, 709, 679, 710, 718, 682, 684, 686, 687, + 688, 695, 728, 0, 697, 202, 205, 741, 693, 694, + 742, 750, 751, 202, 205, 699, 752, 704, 760, 706, + 707, 708, 761, 762, 0, 717, 0, 0, 711, 712, 713, 714, 0, 0, 0, 0, 0, 719, 0, 720, 727, 721, 0, 0, 722, 723, 724, 725, 726, 0, 0, 729, 0, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 0, 740, 0, 0, 743, 744, 745, - 746, 747, 748, 749, 0, 7, 9, 11, 13, 754, - 756, 0, 758, 0, 0, 0, 0, 0, 0, 0, - 0, 761, 94, 94, 762, 94, 94, 94, 94, 94, - 0, 94, 94, 94, 94, 94, 94, 0, 94, 94, - 0, 0, 0, 0, 0, 0, 102, 0, 0, 0, - 0, 0, 0, 111, 0, 0, 114, 15, 16, 17, - 18, 0, 0, 0, 94, 0, 0, 0, 0, 19, - 0, 20, 0, 0, 94, 0, 0, 0, 0, 0, - 0, 0, 21, 22, 0, 23, 0, 125, 24, 25, - 0, 26, 0, 0, 0, 0, 0, 27, 28, 132, - 148, 0, 29, 30, 31, 0, 140, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 94, - 0, 0, 0, 33, 0, 0, 0, 148, 34, 35, - 0, 0, 0, 0, 0, 188, 0, 0, 36, 0, - 0, 0, 0, 0, 179, 0, 0, 188, 0, 211, - 0, 0, 0, 148, 0, 0, 0, 0, 0, 0, - 0, 202, 205, 0, 0, 148, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, - 0, 0, 0, 0, 0, 0, 0, 0, 211, 0, - 239, 255, 0, 0, 0, 0, 0, 0, 0, 0, + 746, 747, 748, 749, 0, 0, 0, 0, 0, 754, + 756, 758, 759, 7, 9, 11, 13, 0, 0, 0, + 0, 0, 763, 0, 0, 0, 764, 0, 0, 0, + 94, 94, 0, 94, 94, 94, 94, 94, 0, 94, + 94, 94, 94, 94, 94, 0, 94, 94, 0, 0, + 0, 0, 15, 16, 17, 18, 0, 0, 58, 59, + 0, 0, 0, 60, 19, 0, 20, 0, 61, 0, + 0, 0, 94, 62, 0, 0, 0, 21, 22, 63, + 23, 0, 94, 24, 25, 0, 26, 0, 0, 64, + 0, 0, 27, 28, 65, 81, 0, 29, 30, 31, + 66, 621, 0, 82, 0, 0, 0, 67, 148, 0, + 0, 68, 69, 32, 0, 70, 0, 71, 33, 633, + 72, 0, 635, 34, 35, 637, 0, 94, 83, 84, + 0, 0, 81, 36, 73, 148, 0, 0, 0, 85, + 82, 0, 339, 188, 0, 86, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 188, 87, 211, 0, 0, + 88, 148, 0, 0, 0, 83, 84, 0, 0, 0, + 0, 0, 89, 148, 0, 0, 85, 0, 0, 0, + 384, 0, 86, 0, 0, 0, 0, 239, 0, 0, + 0, 0, 0, 87, 0, 0, 211, 88, 239, 255, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, + 0, 0, 0, 0, 0, 0, 0, 385, 0, 271, + 0, 0, 0, 0, 0, 0, 9, 9, 9, 13, + 280, 282, 284, 13, 13, 13, 289, 0, 13, 13, + 294, 148, 0, 0, 298, 0, 15, 16, 17, 18, + 0, 0, 58, 59, 0, 0, 0, 60, 19, 0, + 20, 0, 61, 0, 0, 0, 0, 62, 0, 0, + 328, 21, 22, 63, 23, 0, 0, 24, 25, 0, + 26, 0, 0, 64, 0, 0, 27, 28, 65, 0, + 0, 29, 30, 31, 66, 0, 0, 0, 0, 0, + 0, 67, 11, 0, 0, 68, 69, 32, 0, 70, + 0, 71, 33, 0, 72, 0, 0, 34, 35, 0, + 0, 0, 0, 15, 16, 17, 18, 36, 73, 0, + 0, 0, 0, 0, 0, 19, 340, 20, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, + 0, 23, 0, 0, 24, 25, 0, 26, 0, 0, + 0, 0, 0, 27, 28, 0, 0, 0, 29, 30, + 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32, 94, 94, 94, 94, 33, + 0, 0, 0, 0, 34, 35, 15, 16, 17, 18, + 0, 0, 58, 59, 36, 445, 448, 60, 19, 0, + 20, 0, 61, 0, 0, 0, 0, 62, 0, 0, + 0, 21, 22, 63, 23, 0, 0, 24, 25, 471, + 26, 0, 0, 64, 0, 0, 27, 28, 65, 0, + 0, 29, 30, 31, 66, 490, 471, 471, 0, 0, + 0, 67, 0, 0, 0, 68, 69, 32, 0, 70, + 0, 71, 33, 0, 72, 0, 0, 34, 35, 15, + 16, 17, 18, 0, 0, 58, 59, 36, 73, 0, + 60, 19, 0, 20, 0, 61, 341, 0, 0, 0, + 62, 0, 0, 0, 21, 22, 63, 23, 0, 0, + 24, 25, 0, 26, 0, 0, 64, 0, 0, 27, + 28, 65, 0, 0, 29, 30, 31, 66, 0, 0, + 0, 0, 0, 0, 67, 0, 0, 0, 68, 69, + 32, 0, 70, 0, 71, 33, 0, 72, 0, 0, + 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, + 36, 73, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 289, 580, 582, 584, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 271, 0, 0, 0, 0, 0, 0, 9, 9, - 9, 13, 280, 282, 284, 13, 13, 13, 289, 0, - 13, 13, 294, 148, 0, 0, 298, 0, 15, 16, - 17, 18, 0, 0, 58, 59, 0, 0, 0, 60, - 19, 0, 20, 0, 61, 0, 0, 0, 0, 62, - 0, 0, 328, 21, 22, 63, 23, 0, 0, 24, - 25, 0, 26, 0, 0, 64, 0, 0, 27, 28, - 65, 0, 0, 29, 30, 31, 66, 0, 0, 0, - 0, 0, 0, 67, 11, 0, 0, 68, 69, 32, - 0, 70, 0, 71, 33, 0, 72, 0, 0, 34, - 35, 0, 0, 0, 0, 0, 0, 0, 0, 36, - 73, 0, 0, 0, 0, 0, 0, 0, 339, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 605, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 403, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 413, 414, 0, 0, - 0, 0, 0, 415, 0, 0, 0, 0, 0, 0, - 0, 422, 0, 0, 0, 0, 0, 94, 94, 94, - 94, 430, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 445, 448, 0, + 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 471, 413, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 490, 471, 471, - 0, 0, 0, 202, 205, 0, 0, 15, 16, 17, - 18, 202, 205, 58, 59, 0, 0, 0, 60, 19, - 0, 20, 0, 61, 0, 0, 0, 0, 62, 0, - 0, 0, 21, 22, 63, 23, 0, 0, 24, 25, - 0, 26, 0, 0, 64, 0, 0, 27, 28, 65, - 0, 0, 29, 30, 31, 66, 0, 0, 0, 0, - 0, 0, 67, 0, 0, 0, 68, 69, 32, 0, - 70, 0, 71, 33, 0, 72, 0, 0, 34, 35, - 0, 0, 0, 0, 0, 0, 0, 0, 36, 73, - 0, 0, 0, 0, 0, 0, 0, 340, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 289, 580, 582, 584, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 605, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 621, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 633, 0, 0, - 635, 0, 0, 637, 0, 0, 0, 0, 471, 0, - 471, 15, 16, 17, 18, 0, 0, 58, 59, 0, - 0, 0, 60, 19, 0, 20, 0, 61, 0, 0, - 0, 0, 62, 0, 0, 0, 21, 22, 63, 23, - 0, 0, 24, 25, 0, 26, 0, 0, 64, 0, - 0, 27, 28, 65, 0, 0, 29, 30, 31, 66, - 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, - 68, 69, 32, 0, 70, 0, 71, 33, 0, 72, - 0, 0, 34, 35, 15, 16, 17, 18, 0, 0, - 58, 59, 36, 73, 0, 60, 19, 0, 20, 0, - 61, 341, 0, 0, 0, 62, 0, 0, 0, 21, - 22, 63, 23, 0, 0, 24, 25, 0, 26, 0, - 0, 64, 0, 0, 27, 28, 65, 0, 0, 29, - 30, 31, 66, 0, 0, 0, 0, 0, 0, 67, - 0, 0, 0, 68, 69, 32, 0, 70, 0, 71, - 33, 0, 72, 0, 0, 34, 35, 0, 0, 0, - 0, 0, 0, 0, 0, 36, 73 + 0, 0, 0, 0, 0, 0, 471, 0, 471 }; static const yytype_int16 yycheck[] = { - 6, 10, 8, 288, 283, 434, 435, 3, 4, 189, + 6, 10, 8, 288, 283, 434, 435, 3, 4, 5, 3, 4, 18, 19, 0, 21, 22, 23, 24, 25, - 200, 27, 28, 29, 30, 31, 32, 123, 34, 35, - 19, 92, 21, 22, 23, 24, 25, 28, 27, 28, - 29, 30, 31, 32, 36, 34, 35, 3, 4, 5, + 189, 27, 28, 29, 30, 31, 32, 123, 34, 35, + 19, 200, 21, 22, 23, 24, 25, 92, 27, 28, + 29, 30, 31, 32, 21, 34, 35, 3, 4, 20, 3, 4, 20, 149, 60, 3, 4, 3, 4, 3, 4, 3, 4, 20, 70, 161, 3, 4, 82, 3, - 4, 60, 3, 4, 5, 92, 3, 4, 5, 42, - 92, 70, 3, 4, 5, 3, 4, 5, 11, 52, - 96, 3, 4, 5, 3, 4, 5, 93, 92, 22, - 93, 93, 92, 20, 92, 119, 120, 12, 122, 115, - 116, 58, 126, 21, 424, 129, 20, 123, 21, 43, - 117, 20, 432, 21, 21, 93, 115, 419, 58, 21, - 93, 3, 4, 229, 92, 427, 93, 93, 92, 145, - 93, 138, 139, 149, 67, 93, 93, 93, 82, 93, - 93, 93, 57, 8, 12, 161, 93, 57, 58, 64, - 423, 92, 25, 93, 170, 92, 92, 459, 431, 93, - 93, 92, 169, 187, 92, 8, 93, 32, 184, 51, - 92, 86, 87, 92, 6, 93, 41, 42, 93, 93, - 93, 46, 206, 93, 93, 93, 93, 52, 92, 57, - 197, 93, 199, 58, 210, 634, 64, 636, 41, 42, - 43, 58, 416, 46, 69, 51, 82, 92, 73, 52, - 93, 425, 58, 229, 71, 58, 58, 93, 86, 87, - 85, 3, 4, 8, 231, 93, 69, 58, 93, 71, - 73, 16, 421, 76, 65, 78, 93, 92, 81, 58, - 429, 248, 85, 418, 260, 8, 65, 263, 3, 4, - 93, 426, 281, 16, 283, 262, 41, 42, 265, 275, - 276, 277, 93, 23, 3, 4, 5, 52, 458, 92, - 92, 460, 92, 58, 93, 23, 466, 467, 41, 42, - 92, 297, 42, 578, 69, 92, 92, 477, 73, 52, - 92, 92, 52, 217, 42, 58, 486, 221, 222, 223, - 85, 92, 226, 227, 52, 92, 69, 93, 93, 92, - 73, 92, 92, 329, 321, 604, 332, 92, 92, 79, - 80, 92, 85, 88, 89, 90, 91, 334, 92, 82, - 93, 79, 80, 93, 8, 3, 4, 5, 3, 4, - 5, 92, 16, 92, 290, 93, 3, 4, 5, 92, - 214, 215, 216, 93, 92, 92, 92, 373, 374, 375, - 376, 92, 386, 92, 383, 92, 92, 41, 42, 92, - 92, 92, 92, 8, 373, 374, 375, 376, 52, 92, - 92, 16, 92, 92, 58, 93, 393, 394, 395, 396, - 397, 398, 399, 400, 401, 69, 420, 93, 93, 73, - 407, 408, 409, 410, 428, 93, 41, 42, 93, 38, - 39, 85, 419, 93, 421, 93, 93, 52, 93, 93, - 427, 93, 429, 58, 53, 54, 55, 56, 555, 93, - 59, 93, 93, 8, 69, 93, 92, 444, 73, 93, + 4, 60, 3, 4, 5, 20, 3, 4, 5, 3, + 4, 70, 3, 4, 5, 3, 4, 5, 11, 36, + 96, 3, 4, 5, 3, 4, 5, 93, 28, 22, + 93, 42, 92, 20, 43, 119, 120, 21, 122, 115, + 116, 52, 126, 21, 92, 129, 93, 123, 21, 416, + 117, 21, 93, 419, 25, 93, 115, 281, 425, 283, + 421, 427, 58, 229, 3, 4, 93, 93, 429, 145, + 93, 138, 139, 149, 67, 93, 93, 93, 93, 93, + 93, 93, 93, 8, 93, 161, 93, 82, 82, 93, + 92, 92, 82, 459, 170, 92, 6, 93, 93, 460, + 93, 92, 169, 187, 92, 8, 93, 32, 184, 93, + 92, 58, 51, 92, 290, 93, 41, 42, 3, 4, + 93, 46, 206, 93, 71, 57, 58, 52, 58, 58, + 197, 12, 199, 58, 210, 634, 92, 636, 41, 42, + 43, 92, 71, 46, 69, 58, 93, 92, 73, 52, + 58, 51, 65, 229, 424, 58, 92, 65, 58, 8, + 85, 93, 432, 93, 231, 12, 69, 16, 93, 423, + 73, 418, 92, 76, 92, 78, 57, 431, 81, 426, + 93, 248, 85, 64, 260, 93, 92, 263, 3, 4, + 93, 92, 41, 42, 92, 262, 92, 92, 265, 275, + 276, 277, 92, 52, 92, 86, 87, 93, 26, 58, + 57, 93, 93, 92, 92, 33, 23, 64, 36, 458, + 69, 297, 23, 578, 73, 92, 8, 466, 467, 88, + 89, 90, 91, 93, 16, 42, 85, 92, 477, 86, + 87, 42, 92, 555, 93, 52, 93, 486, 92, 67, + 92, 52, 92, 329, 321, 604, 332, 92, 92, 41, + 42, 79, 3, 4, 5, 92, 92, 334, 86, 92, + 52, 92, 79, 80, 93, 92, 58, 93, 79, 80, + 3, 4, 5, 92, 217, 93, 93, 69, 221, 222, + 223, 73, 93, 226, 227, 92, 92, 373, 374, 375, + 376, 92, 386, 85, 383, 92, 124, 3, 4, 5, + 93, 93, 92, 8, 373, 374, 375, 376, 3, 4, + 5, 16, 92, 141, 142, 92, 393, 394, 395, 396, + 397, 398, 399, 400, 401, 92, 420, 214, 215, 216, + 407, 408, 409, 410, 428, 92, 41, 42, 92, 38, + 39, 93, 419, 92, 421, 92, 92, 52, 93, 92, + 427, 93, 429, 58, 53, 54, 55, 56, 93, 93, + 59, 93, 93, 8, 69, 93, 93, 444, 73, 93, 447, 16, 449, 72, 93, 93, 453, 454, 93, 93, - 85, 93, 459, 460, 461, 462, 463, 464, 93, 92, - 484, 651, 92, 653, 93, 655, 41, 42, 92, 38, - 39, 92, 92, 92, 92, 92, 92, 52, 92, 92, + 85, 92, 459, 460, 461, 462, 463, 464, 93, 93, + 484, 93, 92, 549, 93, 92, 41, 42, 92, 38, + 39, 92, 651, 92, 653, 92, 655, 52, 92, 92, 92, 92, 92, 58, 53, 54, 55, 56, 92, 92, 59, 92, 499, 8, 69, 502, 92, 504, 73, 506, 92, 16, 92, 72, 511, 512, 513, 92, 92, 92, 85, 92, 519, 520, 521, 522, 92, 186, 93, 92, - 92, 92, 92, 549, 93, 92, 41, 42, 92, 92, - 583, 93, 92, 8, 92, 92, 92, 52, 92, 402, - 93, 16, 93, 58, 93, 93, 93, 554, 555, 556, - 557, 558, 92, 92, 69, 93, 563, 564, 73, 93, - 93, 93, 93, 93, 571, 572, 41, 42, 93, 585, - 85, 93, 588, 93, 93, 93, 93, 52, 93, 93, - 93, 93, 92, 58, 591, 92, 593, 594, 92, 588, - 92, 598, 599, 92, 69, 93, 93, 93, 73, 93, - 616, 93, 93, 92, 184, 93, 93, 93, 93, 92, - 85, 618, 619, 92, 92, 622, 93, 624, 625, 93, + 92, 92, 92, 583, 93, 92, 41, 42, 92, 92, + 92, 92, 92, 184, 93, 92, 92, 52, 92, 92, + 92, 143, 93, 58, 93, 93, 93, 554, 555, 556, + 557, 558, 93, 92, 69, 93, 563, 564, 73, 93, + 93, 93, 93, 93, 571, 572, 93, 325, 93, 585, + 85, 93, 588, 93, 93, 93, 93, 93, 336, 337, + 93, 92, 92, 92, 591, 343, 593, 594, 92, 588, + 92, 598, 599, 351, 92, -1, 93, 93, 93, 93, + 616, 93, 93, 361, 92, 402, 93, 93, 93, 93, + 92, 618, 619, 92, 92, 622, 93, 624, 625, 93, 93, 628, 92, 92, 92, 92, -1, 93, 92, 92, 92, 638, 639, 93, 641, 93, 643, 93, 93, 93, - 647, 648, 658, 93, 92, 661, 92, -1, 93, 656, - 657, 93, 93, 660, 92, 92, 663, 664, 665, 666, - 667, 677, 92, 143, 680, 93, 93, 93, 675, 676, - 93, 93, 93, 93, 93, 682, -1, 684, -1, 686, - 687, 688, -1, -1, -1, 701, -1, -1, 695, 696, + 647, 648, 658, 93, 402, 661, 92, 92, 92, 656, + 657, 93, 93, 660, 93, 92, 663, 664, 665, 666, + 667, 677, 92, -1, 680, 423, 424, 93, 675, 676, + 93, 93, 93, 431, 432, 682, 93, 684, 93, 686, + 687, 688, 93, 93, -1, 701, -1, -1, 695, 696, 697, 698, -1, -1, -1, -1, -1, 704, -1, 706, 716, 708, -1, -1, 711, 712, 713, 714, 715, -1, -1, 718, -1, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, -1, 731, -1, -1, 734, 735, 736, - 737, 738, 739, 740, -1, 1, 2, 3, 4, 746, - 747, -1, 749, -1, -1, -1, -1, -1, -1, -1, - -1, 758, 18, 19, 761, 21, 22, 23, 24, 25, - -1, 27, 28, 29, 30, 31, 32, -1, 34, 35, - -1, -1, -1, -1, -1, -1, 26, -1, -1, -1, - -1, -1, -1, 33, -1, -1, 36, 3, 4, 5, - 6, -1, -1, -1, 60, -1, -1, -1, -1, 15, - -1, 17, -1, -1, 70, -1, -1, -1, -1, -1, - -1, -1, 28, 29, -1, 31, -1, 67, 34, 35, - -1, 37, -1, -1, -1, -1, -1, 43, 44, 79, - 96, -1, 48, 49, 50, -1, 86, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 64, 115, - -1, -1, -1, 69, -1, -1, -1, 123, 74, 75, - -1, -1, -1, -1, -1, 131, -1, -1, 84, -1, - -1, -1, -1, -1, 124, -1, -1, 143, -1, 145, - -1, -1, -1, 149, -1, -1, -1, -1, -1, -1, - -1, 141, 142, -1, -1, 161, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 175, - -1, -1, -1, -1, -1, -1, -1, -1, 184, -1, - 186, 187, -1, -1, -1, -1, -1, -1, -1, -1, + 737, 738, 739, 740, -1, -1, -1, -1, -1, 746, + 747, 748, 749, 1, 2, 3, 4, -1, -1, -1, + -1, -1, 759, -1, -1, -1, 763, -1, -1, -1, + 18, 19, -1, 21, 22, 23, 24, 25, -1, 27, + 28, 29, 30, 31, 32, -1, 34, 35, -1, -1, + -1, -1, 3, 4, 5, 6, -1, -1, 9, 10, + -1, -1, -1, 14, 15, -1, 17, -1, 19, -1, + -1, -1, 60, 24, -1, -1, -1, 28, 29, 30, + 31, -1, 70, 34, 35, -1, 37, -1, -1, 40, + -1, -1, 43, 44, 45, 8, -1, 48, 49, 50, + 51, 589, -1, 16, -1, -1, -1, 58, 96, -1, + -1, 62, 63, 64, -1, 66, -1, 68, 69, 607, + 71, -1, 610, 74, 75, 613, -1, 115, 41, 42, + -1, -1, 8, 84, 85, 123, -1, -1, -1, 52, + 16, -1, 93, 131, -1, 58, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 143, 69, 145, -1, -1, + 73, 149, -1, -1, -1, 41, 42, -1, -1, -1, + -1, -1, 85, 161, -1, -1, 52, -1, -1, -1, + 93, -1, 58, -1, -1, -1, -1, 175, -1, -1, + -1, -1, -1, 69, -1, -1, 184, 73, 186, 187, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 85, + -1, -1, -1, -1, -1, -1, -1, 93, -1, 207, + -1, -1, -1, -1, -1, -1, 214, 215, 216, 217, + 218, 219, 220, 221, 222, 223, 224, -1, 226, 227, + 228, 229, -1, -1, 232, -1, 3, 4, 5, 6, + -1, -1, 9, 10, -1, -1, -1, 14, 15, -1, + 17, -1, 19, -1, -1, -1, -1, 24, -1, -1, + 258, 28, 29, 30, 31, -1, -1, 34, 35, -1, + 37, -1, -1, 40, -1, -1, 43, 44, 45, -1, + -1, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, 58, 290, -1, -1, 62, 63, 64, -1, 66, + -1, 68, 69, -1, 71, -1, -1, 74, 75, -1, + -1, -1, -1, 3, 4, 5, 6, 84, 85, -1, + -1, -1, -1, -1, -1, 15, 93, 17, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 28, 29, + -1, 31, -1, -1, 34, 35, -1, 37, -1, -1, + -1, -1, -1, 43, 44, -1, -1, -1, 48, 49, + 50, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 64, 373, 374, 375, 376, 69, + -1, -1, -1, -1, 74, 75, 3, 4, 5, 6, + -1, -1, 9, 10, 84, 393, 394, 14, 15, -1, + 17, -1, 19, -1, -1, -1, -1, 24, -1, -1, + -1, 28, 29, 30, 31, -1, -1, 34, 35, 417, + 37, -1, -1, 40, -1, -1, 43, 44, 45, -1, + -1, 48, 49, 50, 51, 433, 434, 435, -1, -1, + -1, 58, -1, -1, -1, 62, 63, 64, -1, 66, + -1, 68, 69, -1, 71, -1, -1, 74, 75, 3, + 4, 5, 6, -1, -1, 9, 10, 84, 85, -1, + 14, 15, -1, 17, -1, 19, 93, -1, -1, -1, + 24, -1, -1, -1, 28, 29, 30, 31, -1, -1, + 34, 35, -1, 37, -1, -1, 40, -1, -1, 43, + 44, 45, -1, -1, 48, 49, 50, 51, -1, -1, + -1, -1, -1, -1, 58, -1, -1, -1, 62, 63, + 64, -1, 66, -1, 68, 69, -1, 71, -1, -1, + 74, 75, -1, -1, -1, -1, -1, -1, -1, -1, + 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 549, 550, 551, 552, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 207, -1, -1, -1, -1, -1, -1, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, -1, - 226, 227, 228, 229, -1, -1, 232, -1, 3, 4, - 5, 6, -1, -1, 9, 10, -1, -1, -1, 14, - 15, -1, 17, -1, 19, -1, -1, -1, -1, 24, - -1, -1, 258, 28, 29, 30, 31, -1, -1, 34, - 35, -1, 37, -1, -1, 40, -1, -1, 43, 44, - 45, -1, -1, 48, 49, 50, 51, -1, -1, -1, - -1, -1, -1, 58, 290, -1, -1, 62, 63, 64, - -1, 66, -1, 68, 69, -1, 71, -1, -1, 74, - 75, -1, -1, -1, -1, -1, -1, -1, -1, 84, - 85, -1, -1, -1, -1, -1, -1, -1, 93, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 577, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 325, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 336, 337, -1, -1, - -1, -1, -1, 343, -1, -1, -1, -1, -1, -1, - -1, 351, -1, -1, -1, -1, -1, 373, 374, 375, - 376, 361, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 393, 394, -1, + 588, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 417, 402, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 433, 434, 435, - -1, -1, -1, 423, 424, -1, -1, 3, 4, 5, - 6, 431, 432, 9, 10, -1, -1, -1, 14, 15, - -1, 17, -1, 19, -1, -1, -1, -1, 24, -1, - -1, -1, 28, 29, 30, 31, -1, -1, 34, 35, - -1, 37, -1, -1, 40, -1, -1, 43, 44, 45, - -1, -1, 48, 49, 50, 51, -1, -1, -1, -1, - -1, -1, 58, -1, -1, -1, 62, 63, 64, -1, - 66, -1, 68, 69, -1, 71, -1, -1, 74, 75, - -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, - -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 549, 550, 551, 552, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 577, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 588, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 589, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 607, -1, -1, - 610, -1, -1, 613, -1, -1, -1, -1, 634, -1, - 636, 3, 4, 5, 6, -1, -1, 9, 10, -1, - -1, -1, 14, 15, -1, 17, -1, 19, -1, -1, - -1, -1, 24, -1, -1, -1, 28, 29, 30, 31, - -1, -1, 34, 35, -1, 37, -1, -1, 40, -1, - -1, 43, 44, 45, -1, -1, 48, 49, 50, 51, - -1, -1, -1, -1, -1, -1, 58, -1, -1, -1, - 62, 63, 64, -1, 66, -1, 68, 69, -1, 71, - -1, -1, 74, 75, 3, 4, 5, 6, -1, -1, - 9, 10, 84, 85, -1, 14, 15, -1, 17, -1, - 19, 93, -1, -1, -1, 24, -1, -1, -1, 28, - 29, 30, 31, -1, -1, 34, 35, -1, 37, -1, - -1, 40, -1, -1, 43, 44, 45, -1, -1, 48, - 49, 50, 51, -1, -1, -1, -1, -1, -1, 58, - -1, -1, -1, 62, 63, 64, -1, 66, -1, 68, - 69, -1, 71, -1, -1, 74, 75, -1, -1, -1, - -1, -1, -1, -1, -1, 84, 85 + -1, -1, -1, -1, -1, -1, 634, -1, 636 }; -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 88, 89, 90, 91, 95, 96, 220, 126, 220, @@ -1664,108 +1438,111 @@ static const yytype_uint8 yystos[] = 217, 217, 217, 217, 217, 217, 217, 214, 92, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 93, 93, 217, 217, 217, 217, 217, 217, 217, - 93, 93, 93, 93, 217, 93, 217, 93, 217, 93, - 93, 217, 217 + 93, 93, 93, 93, 217, 93, 217, 93, 217, 217, + 93, 93, 93, 217, 217 }; -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 94, 95, 95, 95, 95, 96, 96, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 98, 99, 101, + 100, 102, 102, 102, 104, 103, 105, 105, 106, 106, + 108, 107, 109, 109, 111, 110, 112, 110, 113, 113, + 113, 113, 114, 113, 115, 113, 113, 113, 113, 113, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 117, + 117, 118, 118, 118, 119, 119, 119, 121, 120, 123, + 122, 125, 124, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 127, 128, 128, 130, 129, 132, 131, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 145, 146, 147, 147, 148, + 149, 149, 150, 151, 151, 153, 152, 155, 154, 157, + 156, 159, 158, 161, 160, 163, 162, 165, 164, 167, + 166, 168, 168, 168, 169, 170, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 171, 171, 171, 171, 171, + 171, 171, 171, 171, 171, 171, 171, 171, 171, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 173, 174, 175, 176, 176, 176, 177, 177, 177, 178, + 179, 180, 181, 182, 183, 183, 184, 184, 185, 186, + 188, 187, 190, 189, 191, 191, 191, 191, 191, 191, + 193, 192, 194, 194, 194, 196, 195, 197, 197, 197, + 199, 198, 200, 200, 200, 202, 201, 203, 203, 204, + 204, 205, 205, 206, 207, 208, 209, 210, 210, 211, + 212, 212, 213, 213, 214, 214, 214, 215, 215, 216, + 216, 217, 217, 218, 218, 218, 219, 219, 220 +}; -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 2, 2, 2, 1, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4, 5, 0, + 7, 1, 6, 2, 0, 6, 1, 6, 5, 6, + 0, 6, 1, 2, 0, 5, 0, 6, 1, 2, + 3, 4, 0, 7, 0, 7, 5, 5, 8, 8, + 2, 3, 7, 8, 7, 7, 8, 7, 8, 0, + 4, 3, 8, 8, 4, 9, 9, 0, 6, 0, + 6, 0, 6, 1, 6, 5, 7, 7, 5, 5, + 5, 5, 5, 5, 5, 6, 5, 2, 2, 2, + 2, 5, 2, 1, 1, 2, 0, 5, 0, 5, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 5, 6, 4, 4, 4, 4, 7, + 5, 6, 4, 4, 1, 9, 4, 1, 16, 9, + 1, 6, 4, 11, 12, 0, 6, 0, 6, 0, + 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, + 6, 1, 5, 5, 1, 0, 7, 5, 5, 5, + 2, 5, 5, 5, 6, 1, 5, 5, 5, 2, + 5, 5, 5, 5, 5, 5, 2, 5, 6, 1, + 5, 5, 5, 2, 5, 5, 5, 5, 5, 6, + 1, 1, 1, 3, 8, 8, 4, 9, 9, 1, + 8, 2, 1, 1, 1, 5, 1, 2, 1, 1, + 0, 6, 0, 6, 1, 2, 2, 2, 2, 2, + 0, 6, 1, 6, 5, 0, 6, 1, 6, 5, + 0, 6, 1, 6, 2, 0, 6, 1, 6, 1, + 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 1, 1, 1, 0 +}; -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. However, - YYFAIL appears to be in use. Nevertheless, it is formally deprecated - in Bison 2.4.2's NEWS entry, where a plan to phase it out is - discussed. */ +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab -#define YYFAIL goto yyerrlab -#if defined YYFAIL - /* This is here to suppress warnings from the GCC cpp's - -Wunused-macros. Normally we don't worry about that warning, but - some users do, and we want to make it easy for users to remove - YYFAIL uses, which will produce warnings from Bison 2.5. */ -#endif #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK (1); \ - goto yybackup; \ - } \ - else \ - { \ +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ yyerror (YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (YYID (0)) + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (YYID (0)) -#endif - - -/* YY_LOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ - -#ifndef YY_LOCATION_PRINT -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL -# define YY_LOCATION_PRINT(File, Loc) \ - fprintf (File, "%d.%d-%d.%d", \ - (Loc).first_line, (Loc).first_column, \ - (Loc).last_line, (Loc).last_column) -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) -#else -# define YYLEX yylex () -#endif /* Enable debugging if requested. */ #if YYDEBUG @@ -1775,80 +1552,61 @@ while (YYID (0)) # define YYFPRINTF fprintf # endif -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (YYID (0)) +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (YYID (0)) - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*-----------------------------------. +| Print this symbol's value on YYO. | +`-----------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep) { + FILE *yyoutput = yyo; + YYUSE (yyoutput); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# else - YYUSE (yyoutput); + YYPRINT (yyo, yytoknum[yytype], *yyvaluep); # endif - switch (yytype) - { - default: - break; - } + YYUSE (yytype); } -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ +/*---------------------------. +| Print this symbol on YYO. | +`---------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif +yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep) { - if (yytype < YYNTOKENS) - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + YYFPRINTF (yyo, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); - yy_symbol_value_print (yyoutput, yytype, yyvaluep); - YYFPRINTF (yyoutput, ")"); + yy_symbol_value_print (yyo, yytype, yyvaluep); + YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. @@ -1856,16 +1614,8 @@ yy_symbol_print (yyoutput, yytype, yyvaluep) | TOP (included). | `------------------------------------------------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) -#else -static void -yy_stack_print (yybottom, yytop) - yytype_int16 *yybottom; - yytype_int16 *yytop; -#endif { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) @@ -1876,49 +1626,42 @@ yy_stack_print (yybottom, yytop) YYFPRINTF (stderr, "\n"); } -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (YYID (0)) +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void -yy_reduce_print (YYSTYPE *yyvsp, int yyrule) -#else -static void -yy_reduce_print (yyvsp, yyrule) - YYSTYPE *yyvsp; - int yyrule; -#endif +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule) { + unsigned long yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; - unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); + yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], - &(yyvsp[(yyi + 1) - (yynrhs)]) - ); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); YYFPRINTF (stderr, "\n"); } } -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyvsp, Rule); \ -} while (YYID (0)) +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule); \ +} while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ @@ -1932,7 +1675,7 @@ int yydebug; /* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH +#ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif @@ -1947,7 +1690,6 @@ int yydebug; # define YYMAXDEPTH 10000 #endif - #if YYERROR_VERBOSE @@ -1956,15 +1698,8 @@ int yydebug; # define yystrlen strlen # else /* Return the length of YYSTR. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) -#else -static YYSIZE_T -yystrlen (yystr) - const char *yystr; -#endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) @@ -1980,16 +1715,8 @@ yystrlen (yystr) # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) -#else -static char * -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -#endif { char *yyd = yydest; const char *yys = yysrc; @@ -2019,192 +1746,192 @@ yytnamerr (char *yyres, const char *yystr) char const *yyp = yystr; for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); - return yystpcpy (yyres, yystr) - yyres; + return (YYSIZE_T) (yystpcpy (yyres, yystr) - yyres); } # endif -/* Copy into YYRESULT an error message about the unexpected token - YYCHAR while in state YYSTATE. Return the number of bytes copied, - including the terminating null byte. If YYRESULT is null, do not - copy anything; just return the number of bytes that would be - copied. As a special case, return 0 if an ordinary "syntax error" - message will do. Return YYSIZE_MAXIMUM if overflow occurs during - size calculation. */ -static YYSIZE_T -yysyntax_error (char *yyresult, int yystate, int yychar) +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) { - int yyn = yypact[yystate]; + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; - if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) - return 0; - else + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) { - int yytype = YYTRANSLATE (yychar); - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - int yysize_overflow = 0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - int yyx; + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; -# if 0 - /* This is so xgettext sees the translatable formats that are - constructed on the fly. */ - YY_("syntax error, unexpected %s"); - YY_("syntax error, unexpected %s, expecting %s"); - YY_("syntax error, unexpected %s, expecting %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); -# endif - char *yyfmt; - char const *yyf; - static char const yyunexpected[] = "syntax error, unexpected %s"; - static char const yyexpecting[] = ", expecting %s"; - static char const yyor[] = " or %s"; - char yyformat[sizeof yyunexpected - + sizeof yyexpecting - 1 - + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) - * (sizeof yyor - 1))]; - char const *yyprefix = yyexpecting; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 1; - - yyarg[0] = yytname[yytype]; - yyfmt = yystpcpy (yyformat, yyunexpected); - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - yyformat[sizeof yyunexpected - 1] = '\0'; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - yyfmt = yystpcpy (yyfmt, yyprefix); - yyprefix = yyor; - } - - yyf = YY_(yyformat); - yysize1 = yysize + yystrlen (yyf); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - - if (yysize_overflow) - return YYSIZE_MAXIMUM; - - if (yyresult) - { - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - char *yyp = yyresult; - int yyi = 0; - while ((*yyp = *yyf) != '\0') - { - if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyf += 2; - } - else - { - yyp++; - yyf++; - } - } - } - return yysize; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: /* Avoid compiler warnings. */ + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; } #endif /* YYERROR_VERBOSE */ - /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yymsg, yytype, yyvaluep) - const char *yymsg; - int yytype; - YYSTYPE *yyvaluep; -#endif { YYUSE (yyvaluep); - if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - switch (yytype) - { - - default: - break; - } + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END } -/* Prevent warnings from -Wmissing-prototypes. */ -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ + /* The lookahead symbol. */ @@ -2212,49 +1939,26 @@ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; - /* Number of syntax errors so far. */ int yynerrs; +/*----------. +| yyparse. | +`----------*/ -/*-------------------------. -| yyparse or yypush_parse. | -`-------------------------*/ - -#ifdef YYPARSE_PARAM -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void *YYPARSE_PARAM) -#else -int -yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -#endif -#else /* ! YYPARSE_PARAM */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) int yyparse (void) -#else -int -yyparse () - -#endif -#endif { - - int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: - `yyss': related to states. - `yyvs': related to semantic values. + 'yyss': related to states. + 'yyvs': related to semantic values. - Refer to the stacks thru separate pointers, to allow yyoverflow + Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ @@ -2272,7 +1976,7 @@ yyparse () int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ - int yytoken; + int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; @@ -2290,9 +1994,8 @@ yyparse () Keep to zero when no symbol should be popped. */ int yylen = 0; - yytoken = 0; - yyss = yyssa; - yyvs = yyvsa; + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); @@ -2301,14 +2004,6 @@ yyparse () yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - yyssp = yyss; - yyvsp = yyvs; - goto yysetstate; /*------------------------------------------------------------. @@ -2320,32 +2015,31 @@ yyparse () yyssp++; yysetstate: - *yyssp = yystate; + *yyssp = (yytype_int16) yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; + YYSIZE_T yysize = (YYSIZE_T) (yyssp - yyss + 1); #ifdef yyoverflow { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + yyss = yyss1; + yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE @@ -2353,22 +2047,22 @@ yyparse () # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; + goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; + yystacksize = YYMAXDEPTH; { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ @@ -2377,10 +2071,10 @@ yyparse () yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); + (unsigned long) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) - YYABORT; + YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); @@ -2400,7 +2094,7 @@ yybackup: /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) + if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ @@ -2409,7 +2103,7 @@ yybackup: if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; + yychar = yylex (); } if (yychar <= YYEOF) @@ -2431,8 +2125,8 @@ yybackup: yyn = yytable[yyn]; if (yyn <= 0) { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; + if (yytable_value_is_error (yyn)) + goto yyerrlab; yyn = -yyn; goto yyreduce; } @@ -2449,7 +2143,9 @@ yybackup: yychar = YYEMPTY; yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; @@ -2472,7 +2168,7 @@ yyreduce: yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. + '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison @@ -2486,21 +2182,18 @@ yyreduce: switch (yyn) { case 7: - -/* Line 1464 of yacc.c */ -#line 250 "parser.yxx" +#line 255 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { assert(!egg_stack.empty()); - DCAST(EggData, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[(2) - (2)]._egg))); + DCAST(EggData, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } +#line 2191 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 27: - -/* Line 1464 of yacc.c */ -#line 295 "parser.yxx" +#line 300 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - string strval = (yyvsp[(3) - (4)]._string); + string strval = (yyvsp[-1]._string); EggCoordinateSystem *cs = new EggCoordinateSystem; CoordinateSystem f = parse_coordinate_system_string(strval); @@ -2511,24 +2204,22 @@ yyreduce: } (yyval._egg) = cs; } +#line 2208 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 28: - -/* Line 1464 of yacc.c */ -#line 318 "parser.yxx" +#line 323 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._egg) = new EggComment((yyvsp[(2) - (5)]._string), (yyvsp[(4) - (5)]._string)); + (yyval._egg) = new EggComment((yyvsp[-3]._string), (yyvsp[-1]._string)); } +#line 2216 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 29: - -/* Line 1464 of yacc.c */ -#line 332 "parser.yxx" +#line 337 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - string tref_name = (yyvsp[(2) - (4)]._string); - Filename filename = (yyvsp[(4) - (4)]._string); + string tref_name = (yyvsp[-2]._string); + Filename filename = (yyvsp[0]._string); EggTexture *texture = new EggTexture(tref_name, filename); if (textures.find(tref_name) != textures.end()) { @@ -2538,27 +2229,25 @@ yyreduce: egg_stack.push_back(texture); } +#line 2233 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 30: - -/* Line 1464 of yacc.c */ -#line 345 "parser.yxx" +#line 350 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); } +#line 2242 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 32: - -/* Line 1464 of yacc.c */ -#line 361 "parser.yxx" +#line 366 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggTexture *texture = DCAST(EggTexture, egg_stack.back()); - string name = (yyvsp[(3) - (6)]._string); - double value = (yyvsp[(5) - (6)]._number); - string strval = (yyvsp[(5) - (6)]._string); + string name = (yyvsp[-3]._string); + double value = (yyvsp[-1]._number); + string strval = (yyvsp[-1]._string); if (cmp_nocase_uh(name, "type") == 0) { EggTexture::TextureType tt = EggTexture::string_texture_type(strval); @@ -2851,7 +2540,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "depth_write") == 0) { - EggRenderMode::DepthWriteMode m = + EggRenderMode::DepthWriteMode m = EggRenderMode::string_depth_write_mode(strval); if (m == EggRenderMode::DWM_unspecified) { eggyywarning("Unknown depth-write mode " + strval); @@ -2860,7 +2549,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "depth_test") == 0) { - EggRenderMode::DepthTestMode m = + EggRenderMode::DepthTestMode m = EggRenderMode::string_depth_test_mode(strval); if (m == EggRenderMode::DTM_unspecified) { eggyywarning("Unknown depth-test mode " + strval); @@ -2869,7 +2558,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "visibility") == 0) { - EggRenderMode::VisibilityMode m = + EggRenderMode::VisibilityMode m = EggRenderMode::string_visibility_mode(strval); if (m == EggRenderMode::VM_unspecified) { eggyywarning("Unknown visibility mode " + strval); @@ -2895,18 +2584,26 @@ yyreduce: } else if (cmp_nocase_uh(name, "read_mipmaps") == 0) { texture->set_read_mipmaps(((int)value) != 0); + } else if (cmp_nocase_uh(name, "min_lod") == 0) { + texture->set_min_lod(value); + + } else if (cmp_nocase_uh(name, "max_lod") == 0) { + texture->set_max_lod(value); + + } else if (cmp_nocase_uh(name, "lod_bias") == 0) { + texture->set_lod_bias(value); + } else { eggyywarning("Unsupported texture scalar: " + name); } } +#line 2601 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 34: - -/* Line 1464 of yacc.c */ -#line 718 "parser.yxx" +#line 732 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - string mref_name = (yyvsp[(2) - (3)]._string); + string mref_name = (yyvsp[-1]._string); EggMaterial *material = new EggMaterial(mref_name); if (materials.find(mref_name) != materials.end()) { @@ -2916,26 +2613,24 @@ yyreduce: egg_stack.push_back(material); } +#line 2617 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 35: - -/* Line 1464 of yacc.c */ -#line 730 "parser.yxx" +#line 744 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); } +#line 2626 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 37: - -/* Line 1464 of yacc.c */ -#line 746 "parser.yxx" +#line 760 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggMaterial *material = DCAST(EggMaterial, egg_stack.back()); - string name = (yyvsp[(3) - (6)]._string); - double value = (yyvsp[(5) - (6)]._number); + string name = (yyvsp[-3]._string); + double value = (yyvsp[-1]._number); if (cmp_nocase_uh(name, "baser") == 0) { LColor base = material->get_base(); @@ -3041,42 +2736,39 @@ yyreduce: eggyywarning("Unsupported material scalar: " + name); } } +#line 2740 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 38: - -/* Line 1464 of yacc.c */ -#line 841 "parser.yxx" +#line 881 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - string node_name = (yyvsp[(2) - (5)]._string); - Filename filename = (yyvsp[(4) - (5)]._string); + string node_name = (yyvsp[-3]._string); + Filename filename = (yyvsp[-1]._string); EggExternalReference *ref = new EggExternalReference(node_name, filename); (yyval._egg) = ref; } +#line 2751 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 39: - -/* Line 1464 of yacc.c */ -#line 848 "parser.yxx" +#line 888 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - if (cmp_nocase_uh((yyvsp[(1) - (6)]._string), "group") != 0) { + if (cmp_nocase_uh((yyvsp[-5]._string), "group") != 0) { eggyyerror("keyword 'group' expected"); } - string node_name = (yyvsp[(3) - (6)]._string); - Filename filename = (yyvsp[(5) - (6)]._string); + string node_name = (yyvsp[-3]._string); + Filename filename = (yyvsp[-1]._string); EggExternalReference *ref = new EggExternalReference(node_name, filename); (yyval._egg) = ref; } +#line 2765 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 40: - -/* Line 1464 of yacc.c */ -#line 868 "parser.yxx" +#line 908 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - string name = (yyvsp[(2) - (2)]._string); - EggVertexPool *pool = NULL; + string name = (yyvsp[0]._string); + EggVertexPool *pool = nullptr; VertexPools::const_iterator vpi = vertex_pools.find(name); if (vpi != vertex_pools.end()) { @@ -3097,45 +2789,41 @@ yyreduce: egg_stack.push_back(pool); } +#line 2793 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 41: - -/* Line 1464 of yacc.c */ -#line 892 "parser.yxx" +#line 932 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); } +#line 2802 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 44: - -/* Line 1464 of yacc.c */ -#line 920 "parser.yxx" +#line 960 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { egg_stack.push_back(new EggVertex); } +#line 2810 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 45: - -/* Line 1464 of yacc.c */ -#line 924 "parser.yxx" +#line 964 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { PT(EggVertex) vtx = DCAST(EggVertex, egg_stack.back()); egg_stack.pop_back(); DCAST(EggVertexPool, egg_stack.back())->add_vertex(vtx); } +#line 2821 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 46: - -/* Line 1464 of yacc.c */ -#line 931 "parser.yxx" +#line 971 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - vertex_index = (int)(yyvsp[(2) - (2)]._number); + vertex_index = (int)(yyvsp[0]._number); EggVertexPool *pool = DCAST(EggVertexPool, egg_stack.back()); if (vertex_index < 0) { @@ -3158,12 +2846,11 @@ yyreduce: egg_stack.push_back(new EggVertex); } +#line 2850 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 47: - -/* Line 1464 of yacc.c */ -#line 956 "parser.yxx" +#line 996 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { PT(EggVertex) vtx = DCAST(EggVertex, egg_stack.back()); egg_stack.pop_back(); @@ -3173,309 +2860,294 @@ yyreduce: pool->add_vertex(vtx, vertex_index); } } +#line 2864 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 48: - -/* Line 1464 of yacc.c */ -#line 977 "parser.yxx" +#line 1017 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggVertex, egg_stack.back())->set_pos((yyvsp[(1) - (1)]._number)); + DCAST(EggVertex, egg_stack.back())->set_pos((yyvsp[0]._number)); } +#line 2872 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 49: - -/* Line 1464 of yacc.c */ -#line 981 "parser.yxx" +#line 1021 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggVertex, egg_stack.back())->set_pos(LPoint2d((yyvsp[(1) - (2)]._number), (yyvsp[(2) - (2)]._number))); + DCAST(EggVertex, egg_stack.back())->set_pos(LPoint2d((yyvsp[-1]._number), (yyvsp[0]._number))); } +#line 2880 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 50: - -/* Line 1464 of yacc.c */ -#line 985 "parser.yxx" +#line 1025 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggVertex, egg_stack.back())->set_pos(LPoint3d((yyvsp[(1) - (3)]._number), (yyvsp[(2) - (3)]._number), (yyvsp[(3) - (3)]._number))); + DCAST(EggVertex, egg_stack.back())->set_pos(LPoint3d((yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } +#line 2888 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 51: - -/* Line 1464 of yacc.c */ -#line 989 "parser.yxx" +#line 1029 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggVertex, egg_stack.back())->set_pos(LPoint4d((yyvsp[(1) - (4)]._number), (yyvsp[(2) - (4)]._number), (yyvsp[(3) - (4)]._number), (yyvsp[(4) - (4)]._number))); + DCAST(EggVertex, egg_stack.back())->set_pos(LPoint4d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } +#line 2896 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 52: - -/* Line 1464 of yacc.c */ -#line 993 "parser.yxx" +#line 1033 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggVertex *vertex = DCAST(EggVertex, egg_stack.back()); - EggVertexUV *uv = new EggVertexUV((yyvsp[(3) - (4)]._string), LTexCoordd::zero()); + EggVertexUV *uv = new EggVertexUV((yyvsp[-1]._string), LTexCoordd::zero()); egg_stack.push_back(uv); - if (vertex->has_uv((yyvsp[(3) - (4)]._string))) { - eggyywarning("Ignoring repeated UV name " + (yyvsp[(3) - (4)]._string)); + if (vertex->has_uv((yyvsp[-1]._string))) { + eggyywarning("Ignoring repeated UV name " + (yyvsp[-1]._string)); } else { vertex->set_uv_obj(uv); } } +#line 2911 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 53: - -/* Line 1464 of yacc.c */ -#line 1004 "parser.yxx" +#line 1044 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { egg_stack.pop_back(); } +#line 2919 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 54: - -/* Line 1464 of yacc.c */ -#line 1008 "parser.yxx" +#line 1048 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggVertex *vertex = DCAST(EggVertex, egg_stack.back()); - EggVertexAux *aux = new EggVertexAux((yyvsp[(3) - (4)]._string), LVecBase4d::zero()); + EggVertexAux *aux = new EggVertexAux((yyvsp[-1]._string), LVecBase4d::zero()); egg_stack.push_back(aux); - if (vertex->has_aux((yyvsp[(3) - (4)]._string))) { - eggyywarning("Ignoring repeated Aux name " + (yyvsp[(3) - (4)]._string)); + if (vertex->has_aux((yyvsp[-1]._string))) { + eggyywarning("Ignoring repeated Aux name " + (yyvsp[-1]._string)); } else { vertex->set_aux_obj(aux); } } +#line 2934 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 55: - -/* Line 1464 of yacc.c */ -#line 1019 "parser.yxx" +#line 1059 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { egg_stack.pop_back(); } +#line 2942 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 58: - -/* Line 1464 of yacc.c */ -#line 1025 "parser.yxx" +#line 1065 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { bool inserted = DCAST(EggVertex, egg_stack.back())->_dxyzs. - insert(EggMorphVertex((yyvsp[(3) - (8)]._string), LVector3d((yyvsp[(5) - (8)]._number), (yyvsp[(6) - (8)]._number), (yyvsp[(7) - (8)]._number)))).second; + insert(EggMorphVertex((yyvsp[-5]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(3) - (8)]._string)); + eggyywarning("Ignoring repeated morph name " + (yyvsp[-5]._string)); } } +#line 2954 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 59: - -/* Line 1464 of yacc.c */ -#line 1033 "parser.yxx" +#line 1073 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { bool inserted = DCAST(EggVertex, egg_stack.back())->_dxyzs. - insert(EggMorphVertex((yyvsp[(4) - (8)]._string), LVector3d((yyvsp[(5) - (8)]._number), (yyvsp[(6) - (8)]._number), (yyvsp[(7) - (8)]._number)))).second; + insert(EggMorphVertex((yyvsp[-4]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(4) - (8)]._string)); + eggyywarning("Ignoring repeated morph name " + (yyvsp[-4]._string)); } } +#line 2966 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 60: - -/* Line 1464 of yacc.c */ -#line 1052 "parser.yxx" +#line 1092 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggVertexUV, egg_stack.back())->set_uv(LTexCoordd((yyvsp[(1) - (2)]._number), (yyvsp[(2) - (2)]._number))); + DCAST(EggVertexUV, egg_stack.back())->set_uv(LTexCoordd((yyvsp[-1]._number), (yyvsp[0]._number))); } +#line 2974 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 61: - -/* Line 1464 of yacc.c */ -#line 1056 "parser.yxx" +#line 1096 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggVertexUV, egg_stack.back())->set_uvw(LVecBase3d((yyvsp[(1) - (3)]._number), (yyvsp[(2) - (3)]._number), (yyvsp[(3) - (3)]._number))); + DCAST(EggVertexUV, egg_stack.back())->set_uvw(LVecBase3d((yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } +#line 2982 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 62: - -/* Line 1464 of yacc.c */ -#line 1060 "parser.yxx" +#line 1100 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { if (DCAST(EggVertexUV, egg_stack.back())->has_tangent()) { eggyywarning("Ignoring repeated tangent"); } else { - DCAST(EggVertexUV, egg_stack.back())->set_tangent(LNormald((yyvsp[(4) - (7)]._number), (yyvsp[(5) - (7)]._number), (yyvsp[(6) - (7)]._number))); + DCAST(EggVertexUV, egg_stack.back())->set_tangent(LNormald((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number))); } } +#line 2994 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 63: +#line 1108 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + if (DCAST(EggVertexUV, egg_stack.back())->has_tangent()) { + eggyywarning("Ignoring repeated tangent"); + } else { + DCAST(EggVertexUV, egg_stack.back())->set_tangent4(LVecBase4d((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number))); + } +} +#line 3006 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 1068 "parser.yxx" + case 64: +#line 1116 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { if (DCAST(EggVertexUV, egg_stack.back())->has_binormal()) { eggyywarning("Ignoring repeated binormal"); } else { - DCAST(EggVertexUV, egg_stack.back())->set_binormal(LNormald((yyvsp[(4) - (7)]._number), (yyvsp[(5) - (7)]._number), (yyvsp[(6) - (7)]._number))); - } -} - break; - - case 64: - -/* Line 1464 of yacc.c */ -#line 1076 "parser.yxx" - { - bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs. - insert(EggMorphTexCoord((yyvsp[(3) - (7)]._string), LVector3d((yyvsp[(5) - (7)]._number), (yyvsp[(6) - (7)]._number), 0.0))).second; - if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(3) - (7)]._string)); + DCAST(EggVertexUV, egg_stack.back())->set_binormal(LNormald((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number))); } } +#line 3018 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 65: - -/* Line 1464 of yacc.c */ -#line 1084 "parser.yxx" +#line 1124 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs. - insert(EggMorphTexCoord((yyvsp[(3) - (8)]._string), LVector3d((yyvsp[(5) - (8)]._number), (yyvsp[(6) - (8)]._number), (yyvsp[(7) - (8)]._number)))).second; + insert(EggMorphTexCoord((yyvsp[-4]._string), LVector3d((yyvsp[-2]._number), (yyvsp[-1]._number), 0.0))).second; if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(3) - (8)]._string)); + eggyywarning("Ignoring repeated morph name " + (yyvsp[-4]._string)); } } +#line 3030 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 66: - -/* Line 1464 of yacc.c */ -#line 1092 "parser.yxx" +#line 1132 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs. - insert(EggMorphTexCoord((yyvsp[(4) - (7)]._string), LVector3d((yyvsp[(5) - (7)]._number), (yyvsp[(6) - (7)]._number), 0.0))).second; + insert(EggMorphTexCoord((yyvsp[-5]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(4) - (7)]._string)); + eggyywarning("Ignoring repeated morph name " + (yyvsp[-5]._string)); } } +#line 3042 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 67: - -/* Line 1464 of yacc.c */ -#line 1100 "parser.yxx" +#line 1140 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs. - insert(EggMorphTexCoord((yyvsp[(4) - (8)]._string), LVector3d((yyvsp[(5) - (8)]._number), (yyvsp[(6) - (8)]._number), (yyvsp[(7) - (8)]._number)))).second; + insert(EggMorphTexCoord((yyvsp[-3]._string), LVector3d((yyvsp[-2]._number), (yyvsp[-1]._number), 0.0))).second; if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(4) - (8)]._string)); + eggyywarning("Ignoring repeated morph name " + (yyvsp[-3]._string)); } } +#line 3054 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 69: - -/* Line 1464 of yacc.c */ -#line 1118 "parser.yxx" + case 68: +#line 1148 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggVertexAux, egg_stack.back())->set_aux(LVecBase4d((yyvsp[(1) - (4)]._number), (yyvsp[(2) - (4)]._number), (yyvsp[(3) - (4)]._number), (yyvsp[(4) - (4)]._number))); + bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs. + insert(EggMorphTexCoord((yyvsp[-4]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; + if (!inserted) { + eggyywarning("Ignoring repeated morph name " + (yyvsp[-4]._string)); + } } +#line 3066 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 70: - -/* Line 1464 of yacc.c */ -#line 1132 "parser.yxx" +#line 1166 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggVertex, egg_stack.back())->set_normal(LNormald((yyvsp[(1) - (3)]._number), (yyvsp[(2) - (3)]._number), (yyvsp[(3) - (3)]._number))); + DCAST(EggVertexAux, egg_stack.back())->set_aux(LVecBase4d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } +#line 3074 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 71: - -/* Line 1464 of yacc.c */ -#line 1136 "parser.yxx" +#line 1180 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - bool inserted = DCAST(EggVertex, egg_stack.back())->_dnormals. - insert(EggMorphNormal((yyvsp[(3) - (8)]._string), LVector3d((yyvsp[(5) - (8)]._number), (yyvsp[(6) - (8)]._number), (yyvsp[(7) - (8)]._number)))).second; - if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(3) - (8)]._string)); - } + DCAST(EggVertex, egg_stack.back())->set_normal(LNormald((yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } +#line 3082 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 72: - -/* Line 1464 of yacc.c */ -#line 1144 "parser.yxx" +#line 1184 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { bool inserted = DCAST(EggVertex, egg_stack.back())->_dnormals. - insert(EggMorphNormal((yyvsp[(4) - (8)]._string), LVector3d((yyvsp[(5) - (8)]._number), (yyvsp[(6) - (8)]._number), (yyvsp[(7) - (8)]._number)))).second; + insert(EggMorphNormal((yyvsp[-5]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(4) - (8)]._string)); + eggyywarning("Ignoring repeated morph name " + (yyvsp[-5]._string)); } } +#line 3094 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 73: - -/* Line 1464 of yacc.c */ -#line 1162 "parser.yxx" +#line 1192 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggVertex, egg_stack.back())->set_color(LColor((yyvsp[(1) - (4)]._number), (yyvsp[(2) - (4)]._number), (yyvsp[(3) - (4)]._number), (yyvsp[(4) - (4)]._number))); + bool inserted = DCAST(EggVertex, egg_stack.back())->_dnormals. + insert(EggMorphNormal((yyvsp[-4]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; + if (!inserted) { + eggyywarning("Ignoring repeated morph name " + (yyvsp[-4]._string)); + } } +#line 3106 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 74: - -/* Line 1464 of yacc.c */ -#line 1166 "parser.yxx" +#line 1210 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - bool inserted = DCAST(EggVertex, egg_stack.back())->_drgbas. - insert(EggMorphColor((yyvsp[(3) - (9)]._string), LVector4((yyvsp[(5) - (9)]._number), (yyvsp[(6) - (9)]._number), (yyvsp[(7) - (9)]._number), (yyvsp[(8) - (9)]._number)))).second; - if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(3) - (9)]._string)); - } + DCAST(EggVertex, egg_stack.back())->set_color(LColor((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } +#line 3114 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 75: - -/* Line 1464 of yacc.c */ -#line 1174 "parser.yxx" +#line 1214 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { bool inserted = DCAST(EggVertex, egg_stack.back())->_drgbas. - insert(EggMorphColor((yyvsp[(4) - (9)]._string), LVector4((yyvsp[(5) - (9)]._number), (yyvsp[(6) - (9)]._number), (yyvsp[(7) - (9)]._number), (yyvsp[(8) - (9)]._number)))).second; + insert(EggMorphColor((yyvsp[-6]._string), LVector4((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(4) - (9)]._string)); + eggyywarning("Ignoring repeated morph name " + (yyvsp[-6]._string)); } } +#line 3126 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 76: - -/* Line 1464 of yacc.c */ -#line 1192 "parser.yxx" +#line 1222 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - EggGroup *group = new EggGroup((yyvsp[(2) - (2)]._string)); - egg_stack.push_back(group); + bool inserted = DCAST(EggVertex, egg_stack.back())->_drgbas. + insert(EggMorphColor((yyvsp[-5]._string), LVector4((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; + if (!inserted) { + eggyywarning("Ignoring repeated morph name " + (yyvsp[-5]._string)); + } } +#line 3138 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 77: +#line 1240 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggGroup *group = new EggGroup((yyvsp[0]._string)); + egg_stack.push_back(group); +} +#line 3147 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 1197 "parser.yxx" + case 78: +#line 1245 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); (yyval._egg) = group; @@ -3485,44 +3157,40 @@ yyreduce: } Thread::consider_yield(); } - break; - - case 78: - -/* Line 1464 of yacc.c */ -#line 1217 "parser.yxx" - { - EggGroup *group = new EggGroup((yyvsp[(2) - (2)]._string)); - group->set_group_type(EggGroup::GT_joint); - egg_stack.push_back(group); -} +#line 3161 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 79: +#line 1265 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggGroup *group = new EggGroup((yyvsp[0]._string)); + group->set_group_type(EggGroup::GT_joint); + egg_stack.push_back(group); +} +#line 3171 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 1223 "parser.yxx" + case 80: +#line 1271 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); } - break; - - case 80: - -/* Line 1464 of yacc.c */ -#line 1238 "parser.yxx" - { - EggGroup *group = new EggGroup((yyvsp[(2) - (2)]._string)); - group->set_group_type(EggGroup::GT_instance); - egg_stack.push_back(group); -} +#line 3180 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 81: +#line 1286 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggGroup *group = new EggGroup((yyvsp[0]._string)); + group->set_group_type(EggGroup::GT_instance); + egg_stack.push_back(group); +} +#line 3190 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 1244 "parser.yxx" + case 82: +#line 1292 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); (yyval._egg) = group; @@ -3531,18 +3199,17 @@ yyreduce: groups[group->get_name()] = group; } } +#line 3203 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 83: - -/* Line 1464 of yacc.c */ -#line 1264 "parser.yxx" + case 84: +#line 1312 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); - string name = (yyvsp[(3) - (6)]._string); - double value = (yyvsp[(5) - (6)]._number); - unsigned long ulong_value = (yyvsp[(5) - (6)]._ulong); - string strval = (yyvsp[(5) - (6)]._string); + string name = (yyvsp[-3]._string); + double value = (yyvsp[-1]._number); + unsigned long ulong_value = (yyvsp[-1]._ulong); + string strval = (yyvsp[-1]._string); if (cmp_nocase_uh(name, "fps") == 0) { group->set_switch_fps(value); @@ -3565,7 +3232,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "depth_write") == 0) { - EggRenderMode::DepthWriteMode m = + EggRenderMode::DepthWriteMode m = EggRenderMode::string_depth_write_mode(strval); if (m == EggRenderMode::DWM_unspecified) { eggyywarning("Unknown depth-write mode " + strval); @@ -3574,7 +3241,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "depth_test") == 0) { - EggRenderMode::DepthTestMode m = + EggRenderMode::DepthTestMode m = EggRenderMode::string_depth_test_mode(strval); if (m == EggRenderMode::DTM_unspecified) { eggyywarning("Unknown depth-test mode " + strval); @@ -3583,7 +3250,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "visibility") == 0) { - EggRenderMode::VisibilityMode m = + EggRenderMode::VisibilityMode m = EggRenderMode::string_visibility_mode(strval); if (m == EggRenderMode::VM_unspecified) { eggyywarning("Unknown visibility mode " + strval); @@ -3684,15 +3351,14 @@ yyreduce: eggyywarning("Unknown group scalar " + name); } } +#line 3355 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 84: - -/* Line 1464 of yacc.c */ -#line 1409 "parser.yxx" + case 85: +#line 1460 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); - string strval = (yyvsp[(4) - (5)]._string); + string strval = (yyvsp[-1]._string); EggGroup::BillboardType f = EggGroup::string_billboard_type(strval); if (f == EggGroup::BT_none) { @@ -3701,49 +3367,45 @@ yyreduce: group->set_billboard_type(f); } } - break; - - case 85: - -/* Line 1464 of yacc.c */ -#line 1421 "parser.yxx" - { - EggGroup *group = DCAST(EggGroup, egg_stack.back()); - group->set_billboard_center(LPoint3d((yyvsp[(4) - (7)]._number), (yyvsp[(5) - (7)]._number), (yyvsp[(6) - (7)]._number))); -} +#line 3371 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 86: - -/* Line 1464 of yacc.c */ -#line 1426 "parser.yxx" +#line 1472 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); - string name = (yyvsp[(3) - (7)]._string); - - group->set_collision_name(name); + group->set_billboard_center(LPoint3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number))); } +#line 3380 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 87: - -/* Line 1464 of yacc.c */ -#line 1433 "parser.yxx" +#line 1477 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); - int value = (int)(yyvsp[(4) - (5)]._number); - group->set_dcs_type(value!=0 ? EggGroup::DC_default : EggGroup::DC_none); + string name = (yyvsp[-4]._string); + + group->set_collision_name(name); } +#line 3391 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 88: +#line 1484 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggGroup *group = DCAST(EggGroup, egg_stack.back()); + int value = (int)(yyvsp[-1]._number); + group->set_dcs_type(value!=0 ? EggGroup::DC_default : EggGroup::DC_none); +} +#line 3401 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 1439 "parser.yxx" + case 89: +#line 1490 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { // The special flavor of DCS, with { sync } or { nosync }. EggGroup *group = DCAST(EggGroup, egg_stack.back()); - string strval = (yyvsp[(4) - (5)]._string); + string strval = (yyvsp[-1]._string); EggGroup::DCSType f = EggGroup::string_dcs_type(strval); if (f == EggGroup::DC_unspecified) { @@ -3752,28 +3414,26 @@ yyreduce: group->set_dcs_type(f); } } - break; - - case 89: - -/* Line 1464 of yacc.c */ -#line 1452 "parser.yxx" - { - // The traditional flavor of DART, with { 0 } or { 1 }. - EggGroup *group = DCAST(EggGroup, egg_stack.back()); - int value = (int)(yyvsp[(4) - (5)]._number); - group->set_dart_type(value!=0 ? EggGroup::DT_default : EggGroup::DT_none); -} +#line 3418 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 90: +#line 1503 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + // The traditional flavor of DART, with { 0 } or { 1 }. + EggGroup *group = DCAST(EggGroup, egg_stack.back()); + int value = (int)(yyvsp[-1]._number); + group->set_dart_type(value!=0 ? EggGroup::DT_default : EggGroup::DT_none); +} +#line 3429 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 1459 "parser.yxx" + case 91: +#line 1510 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { // The special flavor of DART, with { sync } or { nosync }. EggGroup *group = DCAST(EggGroup, egg_stack.back()); - string strval = (yyvsp[(4) - (5)]._string); + string strval = (yyvsp[-1]._string); EggGroup::DartType f = EggGroup::string_dart_type(strval); if (f == EggGroup::DT_none) { @@ -3782,92 +3442,84 @@ yyreduce: group->set_dart_type(f); } } - break; - - case 91: - -/* Line 1464 of yacc.c */ -#line 1472 "parser.yxx" - { - EggGroup *group = DCAST(EggGroup, egg_stack.back()); - int value = (int)(yyvsp[(4) - (5)]._number); - group->set_switch_flag(value!=0); -} +#line 3446 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 92: - -/* Line 1464 of yacc.c */ -#line 1478 "parser.yxx" +#line 1523 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); - string type = (yyvsp[(4) - (5)]._string); - group->add_object_type(type); + int value = (int)(yyvsp[-1]._number); + group->set_switch_flag(value!=0); } +#line 3456 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 93: - -/* Line 1464 of yacc.c */ -#line 1484 "parser.yxx" +#line 1529 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); - int value = (int)(yyvsp[(4) - (5)]._number); - group->set_model_flag(value!=0); + string type = (yyvsp[-1]._string); + group->add_object_type(type); } +#line 3466 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 94: - -/* Line 1464 of yacc.c */ -#line 1490 "parser.yxx" +#line 1535 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); - group->set_tag((yyvsp[(3) - (6)]._string), (yyvsp[(5) - (6)]._string)); + int value = (int)(yyvsp[-1]._number); + group->set_model_flag(value!=0); } +#line 3476 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 95: - -/* Line 1464 of yacc.c */ -#line 1495 "parser.yxx" +#line 1541 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); - int value = (int)(yyvsp[(4) - (5)]._number); - group->set_texlist_flag(value!=0); + group->set_tag((yyvsp[-3]._string), (yyvsp[-1]._string)); } +#line 3485 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 100: + case 96: +#line 1546 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggGroup *group = DCAST(EggGroup, egg_stack.back()); + int value = (int)(yyvsp[-1]._number); + group->set_texlist_flag(value!=0); +} +#line 3495 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 1505 "parser.yxx" + case 101: +#line 1556 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); if (group->get_group_type() != EggGroup::GT_instance) { eggyyerror(" valid only within "); - } else if ((yyvsp[(4) - (5)]._egg) != (EggObject *)NULL) { - group->add_group_ref(DCAST(EggGroup, (yyvsp[(4) - (5)]._egg))); + } else if ((yyvsp[-1]._egg) != nullptr) { + group->add_group_ref(DCAST(EggGroup, (yyvsp[-1]._egg))); } } - break; - - case 101: - -/* Line 1464 of yacc.c */ -#line 1514 "parser.yxx" - { - DCAST(EggGroup, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[(2) - (2)]._egg))); -} +#line 3508 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 102: +#line 1565 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + DCAST(EggGroup, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); +} +#line 3516 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 1528 "parser.yxx" + case 103: +#line 1579 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); - string strval = (yyvsp[(1) - (1)]._string); + string strval = (yyvsp[0]._string); EggGroup::CollisionSolidType f = EggGroup::string_cs_type(strval); if (f == EggGroup::CST_none) { @@ -3884,15 +3536,14 @@ yyreduce: } } } +#line 3540 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 104: - -/* Line 1464 of yacc.c */ -#line 1559 "parser.yxx" + case 105: +#line 1610 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); - string strval = (yyvsp[(2) - (2)]._string); + string strval = (yyvsp[0]._string); EggGroup::CollideFlags f = EggGroup::string_collide_flags(strval); if (f == EggGroup::CF_none) { @@ -3901,22 +3552,20 @@ yyreduce: group->set_collide_flags(group->get_collide_flags() | f); } } +#line 3556 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 105: - -/* Line 1464 of yacc.c */ -#line 1581 "parser.yxx" + case 106: +#line 1632 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { egg_top_transform = egg_stack.back()->as_transform(); egg_top_transform->clear_transform(); } +#line 3565 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 107: - -/* Line 1464 of yacc.c */ -#line 1597 "parser.yxx" + case 108: +#line 1648 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); if (group->get_group_type() != EggGroup::GT_joint) { @@ -3925,140 +3574,127 @@ yyreduce: egg_top_transform = &group->modify_default_pose(); egg_top_transform->clear_transform(); } - break; - - case 122: - -/* Line 1464 of yacc.c */ -#line 1634 "parser.yxx" - { - egg_top_transform->add_translate2d(LVector2d((yyvsp[(3) - (5)]._number), (yyvsp[(4) - (5)]._number))); -} +#line 3578 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 123: - -/* Line 1464 of yacc.c */ -#line 1641 "parser.yxx" +#line 1685 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_top_transform->add_translate3d(LVector3d((yyvsp[(3) - (6)]._number), (yyvsp[(4) - (6)]._number), (yyvsp[(5) - (6)]._number))); + egg_top_transform->add_translate2d(LVector2d((yyvsp[-2]._number), (yyvsp[-1]._number))); } +#line 3586 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 124: - -/* Line 1464 of yacc.c */ -#line 1648 "parser.yxx" +#line 1692 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_top_transform->add_rotate2d((yyvsp[(3) - (4)]._number)); + egg_top_transform->add_translate3d(LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number))); } +#line 3594 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 125: - -/* Line 1464 of yacc.c */ -#line 1655 "parser.yxx" +#line 1699 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_top_transform->add_rotx((yyvsp[(3) - (4)]._number)); + egg_top_transform->add_rotate2d((yyvsp[-1]._number)); } +#line 3602 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 126: - -/* Line 1464 of yacc.c */ -#line 1662 "parser.yxx" +#line 1706 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_top_transform->add_roty((yyvsp[(3) - (4)]._number)); + egg_top_transform->add_rotx((yyvsp[-1]._number)); } +#line 3610 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 127: - -/* Line 1464 of yacc.c */ -#line 1669 "parser.yxx" +#line 1713 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_top_transform->add_rotz((yyvsp[(3) - (4)]._number)); + egg_top_transform->add_roty((yyvsp[-1]._number)); } +#line 3618 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 128: - -/* Line 1464 of yacc.c */ -#line 1676 "parser.yxx" +#line 1720 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_top_transform->add_rotate3d((yyvsp[(3) - (7)]._number), LVector3d((yyvsp[(4) - (7)]._number), (yyvsp[(5) - (7)]._number), (yyvsp[(6) - (7)]._number))); + egg_top_transform->add_rotz((yyvsp[-1]._number)); } +#line 3626 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 129: - -/* Line 1464 of yacc.c */ -#line 1683 "parser.yxx" +#line 1727 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_top_transform->add_scale2d(LVecBase2d((yyvsp[(3) - (5)]._number), (yyvsp[(4) - (5)]._number))); + egg_top_transform->add_rotate3d((yyvsp[-4]._number), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number))); } +#line 3634 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 130: - -/* Line 1464 of yacc.c */ -#line 1690 "parser.yxx" +#line 1734 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_top_transform->add_scale3d(LVecBase3d((yyvsp[(3) - (6)]._number), (yyvsp[(4) - (6)]._number), (yyvsp[(5) - (6)]._number))); + egg_top_transform->add_scale2d(LVecBase2d((yyvsp[-2]._number), (yyvsp[-1]._number))); } +#line 3642 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 131: - -/* Line 1464 of yacc.c */ -#line 1697 "parser.yxx" +#line 1741 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_top_transform->add_uniform_scale((yyvsp[(3) - (4)]._number)); + egg_top_transform->add_scale3d(LVecBase3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number))); } +#line 3650 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 134: + case 132: +#line 1748 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + egg_top_transform->add_uniform_scale((yyvsp[-1]._number)); +} +#line 3658 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 1711 "parser.yxx" + case 135: +#line 1762 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { egg_top_transform->add_matrix3 - (LMatrix3d((yyvsp[(1) - (9)]._number), (yyvsp[(2) - (9)]._number), (yyvsp[(3) - (9)]._number), - (yyvsp[(4) - (9)]._number), (yyvsp[(5) - (9)]._number), (yyvsp[(6) - (9)]._number), - (yyvsp[(7) - (9)]._number), (yyvsp[(8) - (9)]._number), (yyvsp[(9) - (9)]._number))); -} - break; - - case 137: - -/* Line 1464 of yacc.c */ -#line 1729 "parser.yxx" - { - egg_top_transform->add_matrix4 - (LMatrix4d((yyvsp[(1) - (16)]._number), (yyvsp[(2) - (16)]._number), (yyvsp[(3) - (16)]._number), (yyvsp[(4) - (16)]._number), - (yyvsp[(5) - (16)]._number), (yyvsp[(6) - (16)]._number), (yyvsp[(7) - (16)]._number), (yyvsp[(8) - (16)]._number), - (yyvsp[(9) - (16)]._number), (yyvsp[(10) - (16)]._number), (yyvsp[(11) - (16)]._number), (yyvsp[(12) - (16)]._number), - (yyvsp[(13) - (16)]._number), (yyvsp[(14) - (16)]._number), (yyvsp[(15) - (16)]._number), (yyvsp[(16) - (16)]._number))); + (LMatrix3d((yyvsp[-8]._number), (yyvsp[-7]._number), (yyvsp[-6]._number), + (yyvsp[-5]._number), (yyvsp[-4]._number), (yyvsp[-3]._number), + (yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } +#line 3669 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 138: - -/* Line 1464 of yacc.c */ -#line 1748 "parser.yxx" +#line 1780 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - if ((yyvsp[(7) - (9)]._egg) != (EggVertexPool *)NULL) { - EggVertexPool *pool = DCAST(EggVertexPool, (yyvsp[(7) - (9)]._egg)); + egg_top_transform->add_matrix4 + (LMatrix4d((yyvsp[-15]._number), (yyvsp[-14]._number), (yyvsp[-13]._number), (yyvsp[-12]._number), + (yyvsp[-11]._number), (yyvsp[-10]._number), (yyvsp[-9]._number), (yyvsp[-8]._number), + (yyvsp[-7]._number), (yyvsp[-6]._number), (yyvsp[-5]._number), (yyvsp[-4]._number), + (yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); +} +#line 3681 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; + + case 139: +#line 1799 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + if ((yyvsp[-2]._egg) != nullptr) { + EggVertexPool *pool = DCAST(EggVertexPool, (yyvsp[-2]._egg)); EggGroup *group = DCAST(EggGroup, egg_stack.back()); - PTA_double nums = (yyvsp[(3) - (9)]._number_list); - double membership = (yyvsp[(4) - (9)]._number); + PTA_double nums = (yyvsp[-6]._number_list); + double membership = (yyvsp[-5]._number); for (int i = 0; i < (int)nums.size(); i++) { int index = (int)nums[i]; EggVertex *vertex = pool->get_forward_vertex(index); - if (vertex == NULL) { + if (vertex == nullptr) { ostringstream errmsg; - errmsg << "No vertex " << index << " in pool " << pool->get_name() + errmsg << "No vertex " << index << " in pool " << pool->get_name() << std::ends; eggyyerror(errmsg); } else { @@ -4067,26 +3703,24 @@ yyreduce: } } } - break; - - case 139: - -/* Line 1464 of yacc.c */ -#line 1781 "parser.yxx" - { - (yyval._number) = 1.0; -} +#line 3707 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 140: - -/* Line 1464 of yacc.c */ -#line 1785 "parser.yxx" +#line 1832 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - string name = (yyvsp[(3) - (6)]._string); - double value = (yyvsp[(5) - (6)]._number); - double result = (yyvsp[(1) - (6)]._number); - + (yyval._number) = 1.0; +} +#line 3715 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; + + case 141: +#line 1836 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + string name = (yyvsp[-3]._string); + double value = (yyvsp[-1]._number); + double result = (yyvsp[-5]._number); + if (cmp_nocase_uh(name, "membership") == 0) { result = value; } else { @@ -4095,190 +3729,171 @@ yyreduce: (yyval._number) = result; } - break; - - case 142: - -/* Line 1464 of yacc.c */ -#line 1822 "parser.yxx" - { - EggGroup *group = DCAST(EggGroup, egg_stack.back()); - group->set_lod(EggSwitchConditionDistance((yyvsp[(3) - (11)]._number), (yyvsp[(4) - (11)]._number), LPoint3d((yyvsp[(7) - (11)]._number), (yyvsp[(8) - (11)]._number), (yyvsp[(9) - (11)]._number)))); -} +#line 3733 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 143: - -/* Line 1464 of yacc.c */ -#line 1827 "parser.yxx" +#line 1873 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggGroup *group = DCAST(EggGroup, egg_stack.back()); - group->set_lod(EggSwitchConditionDistance((yyvsp[(3) - (12)]._number), (yyvsp[(4) - (12)]._number), LPoint3d((yyvsp[(8) - (12)]._number), (yyvsp[(9) - (12)]._number), (yyvsp[(10) - (12)]._number)), (yyvsp[(5) - (12)]._number))); + group->set_lod(EggSwitchConditionDistance((yyvsp[-8]._number), (yyvsp[-7]._number), LPoint3d((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number)))); } +#line 3742 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 144: - -/* Line 1464 of yacc.c */ -#line 1844 "parser.yxx" +#line 1878 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_stack.push_back(new EggPolygon((yyvsp[(2) - (2)]._string))); + EggGroup *group = DCAST(EggGroup, egg_stack.back()); + group->set_lod(EggSwitchConditionDistance((yyvsp[-9]._number), (yyvsp[-8]._number), LPoint3d((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number)), (yyvsp[-7]._number))); } +#line 3751 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 145: - -/* Line 1464 of yacc.c */ -#line 1848 "parser.yxx" +#line 1895 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._egg) = egg_stack.back(); - egg_stack.pop_back(); + egg_stack.push_back(new EggPolygon((yyvsp[0]._string))); } +#line 3759 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 146: - -/* Line 1464 of yacc.c */ -#line 1863 "parser.yxx" +#line 1899 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_stack.push_back(new EggTriangleFan((yyvsp[(2) - (2)]._string))); + (yyval._egg) = egg_stack.back(); + egg_stack.pop_back(); } +#line 3768 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 147: - -/* Line 1464 of yacc.c */ -#line 1867 "parser.yxx" +#line 1914 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._egg) = egg_stack.back(); - egg_stack.pop_back(); + egg_stack.push_back(new EggTriangleFan((yyvsp[0]._string))); } +#line 3776 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 148: - -/* Line 1464 of yacc.c */ -#line 1882 "parser.yxx" +#line 1918 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_stack.push_back(new EggTriangleStrip((yyvsp[(2) - (2)]._string))); + (yyval._egg) = egg_stack.back(); + egg_stack.pop_back(); } +#line 3785 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 149: - -/* Line 1464 of yacc.c */ -#line 1886 "parser.yxx" +#line 1933 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._egg) = egg_stack.back(); - egg_stack.pop_back(); + egg_stack.push_back(new EggTriangleStrip((yyvsp[0]._string))); } +#line 3793 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 150: - -/* Line 1464 of yacc.c */ -#line 1901 "parser.yxx" +#line 1937 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_stack.push_back(new EggPatch((yyvsp[(2) - (2)]._string))); + (yyval._egg) = egg_stack.back(); + egg_stack.pop_back(); } +#line 3802 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 151: - -/* Line 1464 of yacc.c */ -#line 1905 "parser.yxx" +#line 1952 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._egg) = egg_stack.back(); - egg_stack.pop_back(); + egg_stack.push_back(new EggPatch((yyvsp[0]._string))); } +#line 3810 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 152: - -/* Line 1464 of yacc.c */ -#line 1920 "parser.yxx" +#line 1956 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_stack.push_back(new EggPoint((yyvsp[(2) - (2)]._string))); + (yyval._egg) = egg_stack.back(); + egg_stack.pop_back(); } +#line 3819 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 153: - -/* Line 1464 of yacc.c */ -#line 1924 "parser.yxx" +#line 1971 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._egg) = egg_stack.back(); - egg_stack.pop_back(); + egg_stack.push_back(new EggPoint((yyvsp[0]._string))); } +#line 3827 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 154: - -/* Line 1464 of yacc.c */ -#line 1939 "parser.yxx" +#line 1975 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_stack.push_back(new EggLine((yyvsp[(2) - (2)]._string))); + (yyval._egg) = egg_stack.back(); + egg_stack.pop_back(); } +#line 3836 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 155: - -/* Line 1464 of yacc.c */ -#line 1943 "parser.yxx" +#line 1990 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._egg) = egg_stack.back(); - egg_stack.pop_back(); + egg_stack.push_back(new EggLine((yyvsp[0]._string))); } +#line 3844 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 156: - -/* Line 1464 of yacc.c */ -#line 1958 "parser.yxx" +#line 1994 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - egg_stack.push_back(new EggNurbsSurface((yyvsp[(2) - (2)]._string))); + (yyval._egg) = egg_stack.back(); + egg_stack.pop_back(); } +#line 3853 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 157: - -/* Line 1464 of yacc.c */ -#line 1962 "parser.yxx" +#line 2009 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._egg) = egg_stack.back(); - egg_stack.pop_back(); + egg_stack.push_back(new EggNurbsSurface((yyvsp[0]._string))); } +#line 3861 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 158: - -/* Line 1464 of yacc.c */ -#line 1977 "parser.yxx" - { - egg_stack.push_back(new EggNurbsCurve((yyvsp[(2) - (2)]._string))); -} - break; - - case 159: - -/* Line 1464 of yacc.c */ -#line 1981 "parser.yxx" +#line 2013 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); } +#line 3870 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 164: + case 159: +#line 2028 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + egg_stack.push_back(new EggNurbsCurve((yyvsp[0]._string))); +} +#line 3878 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 2011 "parser.yxx" + case 160: +#line 2032 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + (yyval._egg) = egg_stack.back(); + egg_stack.pop_back(); +} +#line 3887 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; + + case 165: +#line 2062 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { if (!egg_stack.back()->is_of_type(EggCompositePrimitive::get_class_type())) { eggyyerror("Not a composite primitive; components are not allowed here."); } else { PT(EggCompositePrimitive) comp = DCAST(EggCompositePrimitive, egg_stack.back()); - if ((yyvsp[(3) - (4)]._number) < 0 || (yyvsp[(3) - (4)]._number) >= comp->get_num_components()) { + if ((yyvsp[-1]._number) < 0 || (yyvsp[-1]._number) >= comp->get_num_components()) { eggyyerror("Invalid component number"); } } @@ -4286,30 +3901,28 @@ yyreduce: // the component attributes. egg_stack.push_back(new EggPolygon); } +#line 3905 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 165: - -/* Line 1464 of yacc.c */ -#line 2025 "parser.yxx" + case 166: +#line 2076 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { PT(EggPrimitive) prim = DCAST(EggPrimitive, egg_stack.back()); egg_stack.pop_back(); PT(EggCompositePrimitive) comp = DCAST(EggCompositePrimitive, egg_stack.back()); - comp->set_component((int)(yyvsp[(3) - (7)]._number), prim); + comp->set_component((int)(yyvsp[-4]._number), prim); } +#line 3916 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 173: - -/* Line 1464 of yacc.c */ -#line 2039 "parser.yxx" + case 174: +#line 2090 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back()); - string name = (yyvsp[(3) - (6)]._string); - double value = (yyvsp[(5) - (6)]._number); - string strval = (yyvsp[(5) - (6)]._string); - + string name = (yyvsp[-3]._string); + double value = (yyvsp[-1]._number); + string strval = (yyvsp[-1]._string); + if (cmp_nocase_uh(name, "alpha") == 0) { EggRenderMode::AlphaMode a = EggRenderMode::string_alpha_mode(strval); if (a == EggRenderMode::AM_unspecified) { @@ -4318,7 +3931,7 @@ yyreduce: primitive->set_alpha_mode(a); } } else if (cmp_nocase_uh(name, "depth_write") == 0) { - EggRenderMode::DepthWriteMode m = + EggRenderMode::DepthWriteMode m = EggRenderMode::string_depth_write_mode(strval); if (m == EggRenderMode::DWM_unspecified) { eggyywarning("Unknown depth-write mode " + strval); @@ -4327,7 +3940,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "depth_test") == 0) { - EggRenderMode::DepthTestMode m = + EggRenderMode::DepthTestMode m = EggRenderMode::string_depth_test_mode(strval); if (m == EggRenderMode::DTM_unspecified) { eggyywarning("Unknown depth-test mode " + strval); @@ -4336,7 +3949,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "visibility") == 0) { - EggRenderMode::VisibilityMode m = + EggRenderMode::VisibilityMode m = EggRenderMode::string_visibility_mode(strval); if (m == EggRenderMode::VM_unspecified) { eggyywarning("Unknown visibility mode " + strval); @@ -4368,29 +3981,27 @@ yyreduce: eggyywarning("Unknown scalar " + name); } } +#line 3985 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 185: - -/* Line 1464 of yacc.c */ -#line 2125 "parser.yxx" + case 186: +#line 2176 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - EggNurbsCurve *curve = DCAST(EggNurbsCurve, (yyvsp[(2) - (2)]._egg)); + EggNurbsCurve *curve = DCAST(EggNurbsCurve, (yyvsp[0]._egg)); EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); nurbs->_curves_on_surface.push_back(curve); } +#line 3995 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 187: - -/* Line 1464 of yacc.c */ -#line 2132 "parser.yxx" + case 188: +#line 2183 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggNurbsSurface *primitive = DCAST(EggNurbsSurface, egg_stack.back()); - string name = (yyvsp[(3) - (6)]._string); - double value = (yyvsp[(5) - (6)]._number); - string strval = (yyvsp[(5) - (6)]._string); - + string name = (yyvsp[-3]._string); + double value = (yyvsp[-1]._number); + string strval = (yyvsp[-1]._string); + if (cmp_nocase_uh(name, "alpha") == 0) { EggRenderMode::AlphaMode a = EggRenderMode::string_alpha_mode(strval); if (a == EggRenderMode::AM_unspecified) { @@ -4399,7 +4010,7 @@ yyreduce: primitive->set_alpha_mode(a); } } else if (cmp_nocase_uh(name, "depth_write") == 0) { - EggRenderMode::DepthWriteMode m = + EggRenderMode::DepthWriteMode m = EggRenderMode::string_depth_write_mode(strval); if (m == EggRenderMode::DWM_unspecified) { eggyywarning("Unknown depth-write mode " + strval); @@ -4408,7 +4019,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "depth_test") == 0) { - EggRenderMode::DepthTestMode m = + EggRenderMode::DepthTestMode m = EggRenderMode::string_depth_test_mode(strval); if (m == EggRenderMode::DTM_unspecified) { eggyywarning("Unknown depth-test mode " + strval); @@ -4417,7 +4028,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "visibility") == 0) { - EggRenderMode::VisibilityMode m = + EggRenderMode::VisibilityMode m = EggRenderMode::string_visibility_mode(strval); if (m == EggRenderMode::VM_unspecified) { eggyywarning("Unknown visibility mode " + strval); @@ -4439,18 +4050,17 @@ yyreduce: eggyywarning("Unknown scalar " + name); } } +#line 4054 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 198: - -/* Line 1464 of yacc.c */ -#line 2208 "parser.yxx" + case 199: +#line 2259 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggNurbsCurve *primitive = DCAST(EggNurbsCurve, egg_stack.back()); - string name = (yyvsp[(3) - (6)]._string); - double value = (yyvsp[(5) - (6)]._number); - string strval = (yyvsp[(5) - (6)]._string); - + string name = (yyvsp[-3]._string); + double value = (yyvsp[-1]._number); + string strval = (yyvsp[-1]._string); + if (cmp_nocase_uh(name, "alpha") == 0) { EggRenderMode::AlphaMode a = EggRenderMode::string_alpha_mode(strval); if (a == EggRenderMode::AM_unspecified) { @@ -4459,7 +4069,7 @@ yyreduce: primitive->set_alpha_mode(a); } } else if (cmp_nocase_uh(name, "depth_write") == 0) { - EggRenderMode::DepthWriteMode m = + EggRenderMode::DepthWriteMode m = EggRenderMode::string_depth_write_mode(strval); if (m == EggRenderMode::DWM_unspecified) { eggyywarning("Unknown depth-write mode " + strval); @@ -4468,7 +4078,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "depth_test") == 0) { - EggRenderMode::DepthTestMode m = + EggRenderMode::DepthTestMode m = EggRenderMode::string_depth_test_mode(strval); if (m == EggRenderMode::DTM_unspecified) { eggyywarning("Unknown depth-test mode " + strval); @@ -4477,7 +4087,7 @@ yyreduce: } } else if (cmp_nocase_uh(name, "visibility") == 0) { - EggRenderMode::VisibilityMode m = + EggRenderMode::VisibilityMode m = EggRenderMode::string_visibility_mode(strval); if (m == EggRenderMode::VM_unspecified) { eggyywarning("Unknown visibility mode " + strval); @@ -4500,34 +4110,32 @@ yyreduce: } else { primitive->set_curve_type(a); } - + } else { eggyywarning("Unknown scalar " + name); } } - break; - - case 199: - -/* Line 1464 of yacc.c */ -#line 2279 "parser.yxx" - { - if ((yyvsp[(1) - (1)]._egg) != (EggTexture *)NULL) { - EggTexture *texture = DCAST(EggTexture, (yyvsp[(1) - (1)]._egg)); - DCAST(EggPrimitive, egg_stack.back())->add_texture(texture); - } -} +#line 4119 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 200: - -/* Line 1464 of yacc.c */ -#line 2296 "parser.yxx" +#line 2330 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - EggTexture *texture = NULL; + if ((yyvsp[0]._egg) != nullptr) { + EggTexture *texture = DCAST(EggTexture, (yyvsp[0]._egg)); + DCAST(EggPrimitive, egg_stack.back())->add_texture(texture); + } +} +#line 4130 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; + + case 201: +#line 2347 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggTexture *texture = nullptr; // Defining a texture on-the-fly. - Filename filename = (yyvsp[(1) - (1)]._string); + Filename filename = (yyvsp[0]._string); string tref_name = filename.get_basename(); Textures::iterator vpi = textures.find(tref_name); @@ -4536,7 +4144,7 @@ yyreduce: texture = new EggTexture(tref_name, filename); textures[tref_name] = texture; - if (egg_top_node != NULL) { + if (egg_top_node != nullptr) { egg_top_node->add_child(texture); } @@ -4544,125 +4152,116 @@ yyreduce: // The texture already existed. Use it. texture = (*vpi).second; if (filename != texture->get_filename()) { - eggyywarning(string("Using previous path: ") + + eggyywarning(string("Using previous path: ") + texture->get_filename().get_fullpath()); } } - nassertr(texture != NULL, 0); + nassertr(texture != nullptr, 0); DCAST(EggPrimitive, egg_stack.back())->add_texture(texture); } - break; - - case 201: - -/* Line 1464 of yacc.c */ -#line 2336 "parser.yxx" - { - if ((yyvsp[(1) - (1)]._egg) != (EggMaterial *)NULL) { - EggMaterial *material = DCAST(EggMaterial, (yyvsp[(1) - (1)]._egg)); - DCAST(EggPrimitive, egg_stack.back())->set_material(material); - } -} +#line 4164 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 202: - -/* Line 1464 of yacc.c */ -#line 2353 "parser.yxx" +#line 2387 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggPrimitive, egg_stack.back())->set_normal(LNormald((yyvsp[(1) - (3)]._number), (yyvsp[(2) - (3)]._number), (yyvsp[(3) - (3)]._number))); + if ((yyvsp[0]._egg) != nullptr) { + EggMaterial *material = DCAST(EggMaterial, (yyvsp[0]._egg)); + DCAST(EggPrimitive, egg_stack.back())->set_material(material); + } } +#line 4175 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 203: - -/* Line 1464 of yacc.c */ -#line 2357 "parser.yxx" +#line 2404 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals. - insert(EggMorphNormal((yyvsp[(3) - (8)]._string), LVector3d((yyvsp[(5) - (8)]._number), (yyvsp[(6) - (8)]._number), (yyvsp[(7) - (8)]._number)))).second; - if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(3) - (8)]._string)); - } + DCAST(EggPrimitive, egg_stack.back())->set_normal(LNormald((yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } +#line 4183 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 204: - -/* Line 1464 of yacc.c */ -#line 2365 "parser.yxx" +#line 2408 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals. - insert(EggMorphNormal((yyvsp[(4) - (8)]._string), LVector3d((yyvsp[(5) - (8)]._number), (yyvsp[(6) - (8)]._number), (yyvsp[(7) - (8)]._number)))).second; + insert(EggMorphNormal((yyvsp[-5]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(4) - (8)]._string)); + eggyywarning("Ignoring repeated morph name " + (yyvsp[-5]._string)); } } +#line 4195 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 205: - -/* Line 1464 of yacc.c */ -#line 2383 "parser.yxx" +#line 2416 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggPrimitive, egg_stack.back())->set_color(LColor((yyvsp[(1) - (4)]._number), (yyvsp[(2) - (4)]._number), (yyvsp[(3) - (4)]._number), (yyvsp[(4) - (4)]._number))); + bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals. + insert(EggMorphNormal((yyvsp[-4]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; + if (!inserted) { + eggyywarning("Ignoring repeated morph name " + (yyvsp[-4]._string)); + } } +#line 4207 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 206: - -/* Line 1464 of yacc.c */ -#line 2387 "parser.yxx" +#line 2434 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas. - insert(EggMorphColor((yyvsp[(3) - (9)]._string), LVector4((yyvsp[(5) - (9)]._number), (yyvsp[(6) - (9)]._number), (yyvsp[(7) - (9)]._number), (yyvsp[(8) - (9)]._number)))).second; - if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(3) - (9)]._string)); - } + DCAST(EggPrimitive, egg_stack.back())->set_color(LColor((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } +#line 4215 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 207: - -/* Line 1464 of yacc.c */ -#line 2395 "parser.yxx" +#line 2438 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas. - insert(EggMorphColor((yyvsp[(4) - (9)]._string), LVector4((yyvsp[(5) - (9)]._number), (yyvsp[(6) - (9)]._number), (yyvsp[(7) - (9)]._number), (yyvsp[(8) - (9)]._number)))).second; + insert(EggMorphColor((yyvsp[-6]._string), LVector4((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; if (!inserted) { - eggyywarning("Ignoring repeated morph name " + (yyvsp[(4) - (9)]._string)); + eggyywarning("Ignoring repeated morph name " + (yyvsp[-6]._string)); } } +#line 4227 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 208: - -/* Line 1464 of yacc.c */ -#line 2413 "parser.yxx" +#line 2446 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back()); - int value = (int)(yyvsp[(1) - (1)]._number); - primitive->set_bface_flag(value!=0); + bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas. + insert(EggMorphColor((yyvsp[-5]._string), LVector4((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; + if (!inserted) { + eggyywarning("Ignoring repeated morph name " + (yyvsp[-5]._string)); + } } +#line 4239 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 209: - -/* Line 1464 of yacc.c */ -#line 2429 "parser.yxx" +#line 2464 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - if ((yyvsp[(6) - (8)]._egg) != (EggVertexPool *)NULL) { - EggVertexPool *pool = DCAST(EggVertexPool, (yyvsp[(6) - (8)]._egg)); + EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back()); + int value = (int)(yyvsp[0]._number); + primitive->set_bface_flag(value!=0); +} +#line 4249 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; + + case 210: +#line 2480 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + if ((yyvsp[-2]._egg) != nullptr) { + EggVertexPool *pool = DCAST(EggVertexPool, (yyvsp[-2]._egg)); EggPrimitive *prim = DCAST(EggPrimitive, egg_stack.back()); - PTA_double nums = (yyvsp[(3) - (8)]._number_list); + PTA_double nums = (yyvsp[-5]._number_list); for (int i = 0; i < (int)nums.size(); i++) { int index = (int)nums[i]; EggVertex *vertex = pool->get_forward_vertex(index); - if (vertex == NULL) { + if (vertex == nullptr) { ostringstream errmsg; - errmsg << "No vertex " << index << " in pool " << pool->get_name() + errmsg << "No vertex " << index << " in pool " << pool->get_name() << std::ends; eggyyerror(errmsg); } else { @@ -4671,227 +4270,207 @@ yyreduce: } } } - break; - - case 210: - -/* Line 1464 of yacc.c */ -#line 2460 "parser.yxx" - { - EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); - int u_order = (int)(yyvsp[(1) - (2)]._number); - int v_order = (int)(yyvsp[(2) - (2)]._number); - nurbs->set_u_order(u_order); - nurbs->set_v_order(v_order); -} +#line 4274 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 211: - -/* Line 1464 of yacc.c */ -#line 2478 "parser.yxx" +#line 2511 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); - PTA_double nums = (yyvsp[(1) - (1)]._number_list); + int u_order = (int)(yyvsp[-1]._number); + int v_order = (int)(yyvsp[0]._number); + nurbs->set_u_order(u_order); + nurbs->set_v_order(v_order); +} +#line 4286 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; + + case 212: +#line 2529 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); + PTA_double nums = (yyvsp[0]._number_list); nurbs->set_num_u_knots(nums.size()); for (int i = 0; i < (int)nums.size(); i++) { nurbs->set_u_knot(i, nums[i]); } } +#line 4300 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 212: - -/* Line 1464 of yacc.c */ -#line 2498 "parser.yxx" + case 213: +#line 2549 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); - PTA_double nums = (yyvsp[(1) - (1)]._number_list); + PTA_double nums = (yyvsp[0]._number_list); nurbs->set_num_v_knots(nums.size()); for (int i = 0; i < (int)nums.size(); i++) { nurbs->set_v_knot(i, nums[i]); } } +#line 4314 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 213: - -/* Line 1464 of yacc.c */ -#line 2518 "parser.yxx" + case 214: +#line 2569 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); nurbs->_trims.push_back(EggNurbsSurface::Trim()); } +#line 4323 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 215: - -/* Line 1464 of yacc.c */ -#line 2534 "parser.yxx" + case 216: +#line 2585 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); nassertr(!nurbs->_trims.empty(), 0); nurbs->_trims.back().push_back(EggNurbsSurface::Loop()); } +#line 4333 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 216: - -/* Line 1464 of yacc.c */ -#line 2540 "parser.yxx" + case 217: +#line 2591 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); nassertr(!nurbs->_trims.empty(), 0); nassertr(!nurbs->_trims.back().empty(), 0); - EggNurbsCurve *curve = DCAST(EggNurbsCurve, (yyvsp[(2) - (2)]._egg)); + EggNurbsCurve *curve = DCAST(EggNurbsCurve, (yyvsp[0]._egg)); nurbs->_trims.back().back().push_back(curve); } - break; - - case 217: - -/* Line 1464 of yacc.c */ -#line 2559 "parser.yxx" - { - EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back()); - int order = (int)(yyvsp[(1) - (1)]._number); - nurbs->set_order(order); -} +#line 4345 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 218: - -/* Line 1464 of yacc.c */ -#line 2575 "parser.yxx" +#line 2610 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back()); - PTA_double nums = (yyvsp[(1) - (1)]._number_list); + int order = (int)(yyvsp[0]._number); + nurbs->set_order(order); +} +#line 4355 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; + + case 219: +#line 2626 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back()); + PTA_double nums = (yyvsp[0]._number_list); nurbs->set_num_knots(nums.size()); for (int i = 0; i < (int)nums.size(); i++) { nurbs->set_knot(i, nums[i]); } } - break; - - case 219: - -/* Line 1464 of yacc.c */ -#line 2596 "parser.yxx" - { - EggTable *table = new EggTable((yyvsp[(2) - (2)]._string)); - table->set_table_type(EggTable::TT_table); - egg_stack.push_back(table); -} +#line 4369 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 220: +#line 2647 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggTable *table = new EggTable((yyvsp[0]._string)); + table->set_table_type(EggTable::TT_table); + egg_stack.push_back(table); +} +#line 4379 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 2602 "parser.yxx" + case 221: +#line 2653 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); Thread::consider_yield(); } - break; - - case 221: - -/* Line 1464 of yacc.c */ -#line 2619 "parser.yxx" - { - EggTable *table = new EggTable((yyvsp[(2) - (2)]._string)); - table->set_table_type(EggTable::TT_bundle); - egg_stack.push_back(table); -} +#line 4389 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 222: +#line 2670 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggTable *table = new EggTable((yyvsp[0]._string)); + table->set_table_type(EggTable::TT_bundle); + egg_stack.push_back(table); +} +#line 4399 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 2625 "parser.yxx" + case 223: +#line 2676 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); } - break; - - case 224: - -/* Line 1464 of yacc.c */ -#line 2641 "parser.yxx" - { - DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[(2) - (2)]._egg))); -} +#line 4408 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 225: - -/* Line 1464 of yacc.c */ -#line 2645 "parser.yxx" +#line 2692 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[(2) - (2)]._egg))); + DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } +#line 4416 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 226: - -/* Line 1464 of yacc.c */ -#line 2649 "parser.yxx" +#line 2696 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[(2) - (2)]._egg))); + DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } +#line 4424 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 227: - -/* Line 1464 of yacc.c */ -#line 2653 "parser.yxx" +#line 2700 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[(2) - (2)]._egg))); + DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } +#line 4432 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 228: - -/* Line 1464 of yacc.c */ -#line 2657 "parser.yxx" +#line 2704 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[(2) - (2)]._egg))); + DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } +#line 4440 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 229: - -/* Line 1464 of yacc.c */ -#line 2672 "parser.yxx" +#line 2708 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - EggSAnimData *anim_data = new EggSAnimData((yyvsp[(2) - (2)]._string)); - egg_stack.push_back(anim_data); + DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } +#line 4448 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 230: +#line 2723 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggSAnimData *anim_data = new EggSAnimData((yyvsp[0]._string)); + egg_stack.push_back(anim_data); +} +#line 4457 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 2677 "parser.yxx" + case 231: +#line 2728 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); } +#line 4466 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 232: - -/* Line 1464 of yacc.c */ -#line 2694 "parser.yxx" + case 233: +#line 2745 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggSAnimData *anim_data = DCAST(EggSAnimData, egg_stack.back()); - string name = (yyvsp[(3) - (6)]._string); - double value = (yyvsp[(5) - (6)]._number); + string name = (yyvsp[-3]._string); + double value = (yyvsp[-1]._number); if (cmp_nocase_uh(name, "fps") == 0) { anim_data->set_fps(value); @@ -4899,46 +4478,42 @@ yyreduce: eggyywarning("Unsupported S$Anim scalar: " + name); } } - break; - - case 233: - -/* Line 1464 of yacc.c */ -#line 2706 "parser.yxx" - { - DCAST(EggSAnimData, egg_stack.back())->set_data((yyvsp[(4) - (5)]._number_list)); -} +#line 4482 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 234: - -/* Line 1464 of yacc.c */ -#line 2720 "parser.yxx" +#line 2757 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - EggXfmAnimData *anim_data = new EggXfmAnimData((yyvsp[(2) - (2)]._string)); - egg_stack.push_back(anim_data); + DCAST(EggSAnimData, egg_stack.back())->set_data((yyvsp[-1]._number_list)); } +#line 4490 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 235: +#line 2771 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggXfmAnimData *anim_data = new EggXfmAnimData((yyvsp[0]._string)); + egg_stack.push_back(anim_data); +} +#line 4499 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 2725 "parser.yxx" + case 236: +#line 2776 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); } +#line 4508 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 237: - -/* Line 1464 of yacc.c */ -#line 2742 "parser.yxx" + case 238: +#line 2793 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggXfmAnimData *anim_data = DCAST(EggXfmAnimData, egg_stack.back()); - string name = (yyvsp[(3) - (6)]._string); - double value = (yyvsp[(5) - (6)]._number); - string strval = (yyvsp[(5) - (6)]._string); + string name = (yyvsp[-3]._string); + double value = (yyvsp[-1]._number); + string strval = (yyvsp[-1]._string); if (cmp_nocase_uh(name, "fps") == 0) { anim_data->set_fps(value); @@ -4950,46 +4525,42 @@ yyreduce: eggyywarning("Unsupported Xfm$Anim scalar: " + name); } } - break; - - case 238: - -/* Line 1464 of yacc.c */ -#line 2759 "parser.yxx" - { - DCAST(EggXfmAnimData, egg_stack.back())->set_data((yyvsp[(4) - (5)]._number_list)); -} +#line 4529 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 239: - -/* Line 1464 of yacc.c */ -#line 2773 "parser.yxx" +#line 2810 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - EggXfmSAnim *anim_group = new EggXfmSAnim((yyvsp[(2) - (2)]._string)); - egg_stack.push_back(anim_group); + DCAST(EggXfmAnimData, egg_stack.back())->set_data((yyvsp[-1]._number_list)); } +#line 4537 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 240: +#line 2824 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggXfmSAnim *anim_group = new EggXfmSAnim((yyvsp[0]._string)); + egg_stack.push_back(anim_group); +} +#line 4546 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 2778 "parser.yxx" + case 241: +#line 2829 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); } +#line 4555 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 242: - -/* Line 1464 of yacc.c */ -#line 2795 "parser.yxx" + case 243: +#line 2846 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggXfmSAnim *anim_group = DCAST(EggXfmSAnim, egg_stack.back()); - string name = (yyvsp[(3) - (6)]._string); - double value = (yyvsp[(5) - (6)]._number); - string strval = (yyvsp[(5) - (6)]._string); + string name = (yyvsp[-3]._string); + double value = (yyvsp[-1]._number); + string strval = (yyvsp[-1]._string); if (cmp_nocase_uh(name, "fps") == 0) { anim_group->set_fps(value); @@ -4999,45 +4570,41 @@ yyreduce: eggyywarning("Unsupported Xfm$Anim_S$ scalar: " + name); } } - break; - - case 243: - -/* Line 1464 of yacc.c */ -#line 2810 "parser.yxx" - { - DCAST(EggXfmSAnim, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[(2) - (2)]._egg))); -} +#line 4574 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 244: - -/* Line 1464 of yacc.c */ -#line 2825 "parser.yxx" +#line 2861 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - EggAnimPreload *anim_preload = new EggAnimPreload((yyvsp[(2) - (2)]._string)); - egg_stack.push_back(anim_preload); + DCAST(EggXfmSAnim, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } +#line 4582 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 245: +#line 2876 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + EggAnimPreload *anim_preload = new EggAnimPreload((yyvsp[0]._string)); + egg_stack.push_back(anim_preload); +} +#line 4591 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; -/* Line 1464 of yacc.c */ -#line 2830 "parser.yxx" + case 246: +#line 2881 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); } +#line 4600 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 247: - -/* Line 1464 of yacc.c */ -#line 2847 "parser.yxx" + case 248: +#line 2898 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { EggAnimPreload *anim_preload = DCAST(EggAnimPreload, egg_stack.back()); - string name = (yyvsp[(3) - (6)]._string); - double value = (yyvsp[(5) - (6)]._number); + string name = (yyvsp[-3]._string); + double value = (yyvsp[-1]._number); if (cmp_nocase_uh(name, "fps") == 0) { anim_preload->set_fps(value); @@ -5047,50 +4614,45 @@ yyreduce: eggyywarning("Unsupported AnimPreload scalar: " + name); } } - break; - - case 248: - -/* Line 1464 of yacc.c */ -#line 2871 "parser.yxx" - { - (yyval._number_list) = PTA_double::empty_array(0); -} +#line 4618 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 249: - -/* Line 1464 of yacc.c */ -#line 2875 "parser.yxx" - { - (yyval._number_list).push_back((double)(yyvsp[(2) - (2)]._number)); -} - break; - - case 250: - -/* Line 1464 of yacc.c */ -#line 2889 "parser.yxx" +#line 2922 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._number_list) = PTA_double::empty_array(0); } +#line 4626 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; + + case 250: +#line 2926 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + (yyval._number_list).push_back((double)(yyvsp[0]._number)); +} +#line 4634 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 251: - -/* Line 1464 of yacc.c */ -#line 2893 "parser.yxx" +#line 2940 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._number_list).push_back((yyvsp[(2) - (2)]._number)); + (yyval._number_list) = PTA_double::empty_array(0); } +#line 4642 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 252: - -/* Line 1464 of yacc.c */ -#line 2907 "parser.yxx" +#line 2944 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - string name = (yyvsp[(1) - (1)]._string); + (yyval._number_list).push_back((yyvsp[0]._number)); +} +#line 4650 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; + + case 253: +#line 2958 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + string name = (yyvsp[0]._string); Textures::iterator vpi = textures.find(name); if (vpi == textures.end()) { eggyyerror("Unknown texture " + name); @@ -5099,14 +4661,13 @@ yyreduce: (yyval._egg) = (*vpi).second; } } +#line 4665 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 253: - -/* Line 1464 of yacc.c */ -#line 2928 "parser.yxx" + case 254: +#line 2979 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - string name = (yyvsp[(1) - (1)]._string); + string name = (yyvsp[0]._string); Materials::iterator vpi = materials.find(name); if (vpi == materials.end()) { eggyyerror("Unknown material " + name); @@ -5115,14 +4676,13 @@ yyreduce: (yyval._egg) = (*vpi).second; } } +#line 4680 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 254: - -/* Line 1464 of yacc.c */ -#line 2949 "parser.yxx" + case 255: +#line 3000 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - string name = (yyvsp[(1) - (1)]._string); + string name = (yyvsp[0]._string); VertexPools::iterator vpi = vertex_pools.find(name); if (vpi == vertex_pools.end()) { // This will become a forward reference. @@ -5135,14 +4695,13 @@ yyreduce: (yyval._egg) = (*vpi).second; } } +#line 4699 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 255: - -/* Line 1464 of yacc.c */ -#line 2974 "parser.yxx" + case 256: +#line 3025 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - string name = (yyvsp[(1) - (1)]._string); + string name = (yyvsp[0]._string); Groups::iterator vpi = groups.find(name); if (vpi == groups.end()) { eggyyerror("Unknown group " + name); @@ -5151,161 +4710,156 @@ yyreduce: (yyval._egg) = (*vpi).second; } } +#line 4714 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 256: - -/* Line 1464 of yacc.c */ -#line 2995 "parser.yxx" + case 257: +#line 3046 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { eggyyerror("Name required."); (yyval._string) = ""; } +#line 4723 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 259: - -/* Line 1464 of yacc.c */ -#line 3024 "parser.yxx" + case 260: +#line 3075 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { eggyyerror("String required."); (yyval._string) = ""; } +#line 4732 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 261: - -/* Line 1464 of yacc.c */ -#line 3040 "parser.yxx" + case 262: +#line 3091 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { (yyval._string) = ""; } - break; - - case 263: - -/* Line 1464 of yacc.c */ -#line 3058 "parser.yxx" - { - (yyval._string) = (yyvsp[(1) - (1)]._string); -} +#line 4740 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 264: - -/* Line 1464 of yacc.c */ -#line 3062 "parser.yxx" +#line 3109 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._string) = (yyvsp[(1) - (1)]._string); + (yyval._string) = (yyvsp[0]._string); } +#line 4748 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 266: - -/* Line 1464 of yacc.c */ -#line 3079 "parser.yxx" + case 265: +#line 3113 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._string) = ""; + (yyval._string) = (yyvsp[0]._string); } +#line 4756 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 267: - -/* Line 1464 of yacc.c */ -#line 3083 "parser.yxx" +#line 3130 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._string) = (yyvsp[(1) - (1)]._string); + (yyval._string) = ""; } +#line 4764 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 268: - -/* Line 1464 of yacc.c */ -#line 3099 "parser.yxx" +#line 3134 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._string) = (yyvsp[(1) - (1)]._string); + (yyval._string) = (yyvsp[0]._string); } +#line 4772 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 269: - -/* Line 1464 of yacc.c */ -#line 3103 "parser.yxx" +#line 3150 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._string) = (yyvsp[(1) - (2)]._string) + "\n" + (yyvsp[(2) - (2)]._string); + (yyval._string) = (yyvsp[0]._string); } +#line 4780 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 271: - -/* Line 1464 of yacc.c */ -#line 3118 "parser.yxx" + case 270: +#line 3154 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._number) = (yyvsp[(1) - (1)]._ulong); + (yyval._string) = (yyvsp[-1]._string) + "\n" + (yyvsp[0]._string); } +#line 4788 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 272: - -/* Line 1464 of yacc.c */ -#line 3133 "parser.yxx" +#line 3169 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._number) = (yyvsp[(1) - (1)]._number); - (yyval._ulong) = (unsigned long)(yyvsp[(1) - (1)]._number); - (yyval._string) = (yyvsp[(1) - (1)]._string); + (yyval._number) = (yyvsp[0]._ulong); } +#line 4796 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 273: - -/* Line 1464 of yacc.c */ -#line 3139 "parser.yxx" +#line 3184 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._number) = (yyvsp[(1) - (1)]._ulong); - (yyval._ulong) = (yyvsp[(1) - (1)]._ulong); - (yyval._string) = (yyvsp[(1) - (1)]._string); + (yyval._number) = (yyvsp[0]._number); + (yyval._ulong) = (unsigned long)(yyvsp[0]._number); + (yyval._string) = (yyvsp[0]._string); } +#line 4806 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 274: - -/* Line 1464 of yacc.c */ -#line 3145 "parser.yxx" +#line 3190 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._number) = 0.0; - (yyval._ulong) = 0; - (yyval._string) = (yyvsp[(1) - (1)]._string); + (yyval._number) = (yyvsp[0]._ulong); + (yyval._ulong) = (yyvsp[0]._ulong); + (yyval._string) = (yyvsp[0]._string); } +#line 4816 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; case 275: - -/* Line 1464 of yacc.c */ -#line 3162 "parser.yxx" +#line 3196 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - int i = (int)(yyvsp[(1) - (1)]._number); - if ((double)i != (yyvsp[(1) - (1)]._number)) { + (yyval._number) = 0.0; + (yyval._ulong) = 0; + (yyval._string) = (yyvsp[0]._string); +} +#line 4826 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ + break; + + case 276: +#line 3213 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ + { + int i = (int)(yyvsp[0]._number); + if ((double)i != (yyvsp[0]._number)) { eggyywarning("Integer expected."); (yyval._number) = (double)i; } } +#line 4838 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - case 276: - -/* Line 1464 of yacc.c */ -#line 3170 "parser.yxx" + case 277: +#line 3221 "panda/src/egg/parser.yxx" /* yacc.c:1645 */ { - (yyval._number) = (yyvsp[(1) - (1)]._ulong); + (yyval._number) = (yyvsp[0]._ulong); } +#line 4846 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ break; - -/* Line 1464 of yacc.c */ -#line 5274 "y.tab.c" +#line 4850 "built/tmp/parser.yxx.c" /* yacc.c:1645 */ default: break; } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); @@ -5314,25 +4868,28 @@ yyreduce: *++yyvsp = yyval; - /* Now `shift' the result of the reduction. Determine what state + /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; + { + const int yylhs = yyr1[yyn] - YYNTOKENS; + const int yyi = yypgoto[yylhs] + *yyssp; + yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp + ? yytable[yyi] + : yydefgoto[yylhs]); + } goto yynewstate; -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { @@ -5340,37 +4897,36 @@ yyerrlab: #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) { - YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); - if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) - { - YYSIZE_T yyalloc = 2 * yysize; - if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) - yyalloc = YYSTACK_ALLOC_MAXIMUM; - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yyalloc); - if (yymsg) - yymsg_alloc = yyalloc; - else - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - } - } - - if (0 < yysize && yysize <= yymsg_alloc) - { - (void) yysyntax_error (yymsg, yystate, yychar); - yyerror (yymsg); - } - else - { - yyerror (YY_("syntax error")); - if (yysize != 0) - goto yyexhaustedlab; - } + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; } +# undef YYSYNTAX_ERROR #endif } @@ -5379,20 +4935,20 @@ yyerrlab: if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an - error, discard it. */ + error, discard it. */ if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } else - { - yydestruct ("Error: discarding", - yytoken, &yylval); - yychar = YYEMPTY; - } + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } } /* Else will try to reuse lookahead token after shifting the error @@ -5411,7 +4967,7 @@ yyerrorlab: if (/*CONSTCOND*/ 0) goto yyerrorlab; - /* Do not reclaim the symbols of the rule which action triggered + /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; @@ -5424,35 +4980,37 @@ yyerrorlab: | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ + yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) - YYABORT; + YYABORT; yydestruct ("Error: popping", - yystos[yystate], yyvsp); + yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ @@ -5476,7 +5034,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined(yyoverflow) || YYERROR_VERBOSE +#if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -5488,16 +5046,21 @@ yyexhaustedlab: yyreturn: if (yychar != YYEMPTY) - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - /* Do not reclaim the symbols of the rule which action triggered + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp); + yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow @@ -5508,9 +5071,5 @@ yyreturn: if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif - /* Make sure YYID is used. */ - return YYID (yyresult); + return yyresult; } - - - diff --git a/panda/src/egg/parser.h.prebuilt b/panda/src/egg/parser.h.prebuilt index ea5a85cea9..24f4dde7da 100644 --- a/panda/src/egg/parser.h.prebuilt +++ b/panda/src/egg/parser.h.prebuilt @@ -1,20 +1,19 @@ -/* A Bison parser, made by GNU Bison 2.4.2. */ +/* A Bison parser, made by GNU Bison 3.2.2. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc. -/* Skeleton interface for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2006, 2009-2010 Free Software - Foundation, Inc. - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -27,107 +26,118 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ +/* Undocumented macros, especially those whose name start with YY_, + are private implementation details. Do not rely on them. */ -/* Tokens. */ +#ifndef YY_EGGYY_BUILT_TMP_PARSER_YXX_H_INCLUDED +# define YY_EGGYY_BUILT_TMP_PARSER_YXX_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int eggyydebug; +#endif + +/* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - EGG_NUMBER = 258, - EGG_ULONG = 259, - EGG_STRING = 260, - ANIMPRELOAD = 261, - BEZIERCURVE = 262, - BFACE = 263, - BILLBOARD = 264, - BILLBOARDCENTER = 265, - BINORMAL = 266, - BUNDLE = 267, - CLOSED = 268, - COLLIDE = 269, - COMMENT = 270, - COMPONENT = 271, - COORDSYSTEM = 272, - CV = 273, - DART = 274, - DNORMAL = 275, - DRGBA = 276, - DUV = 277, - DXYZ = 278, - DCS = 279, - DISTANCE = 280, - DTREF = 281, - DYNAMICVERTEXPOOL = 282, - EXTERNAL_FILE = 283, - GROUP = 284, - DEFAULTPOSE = 285, - JOINT = 286, - KNOTS = 287, - INCLUDE = 288, - INSTANCE = 289, - LINE = 290, - LOOP = 291, - MATERIAL = 292, - MATRIX3 = 293, - MATRIX4 = 294, - MODEL = 295, - MREF = 296, - NORMAL = 297, - NURBSCURVE = 298, - NURBSSURFACE = 299, - OBJECTTYPE = 300, - ORDER = 301, - OUTTANGENT = 302, - PATCH = 303, - POINTLIGHT = 304, - POLYGON = 305, - REF = 306, - RGBA = 307, - ROTATE = 308, - ROTX = 309, - ROTY = 310, - ROTZ = 311, - SANIM = 312, - SCALAR = 313, - SCALE = 314, - SEQUENCE = 315, - SHADING = 316, - SWITCH = 317, - SWITCHCONDITION = 318, - TABLE = 319, - TABLE_V = 320, - TAG = 321, - TANGENT = 322, - TEXLIST = 323, - TEXTURE = 324, - TLENGTHS = 325, - TRANSFORM = 326, - TRANSLATE = 327, - TREF = 328, - TRIANGLEFAN = 329, - TRIANGLESTRIP = 330, - TRIM = 331, - TXT = 332, - UKNOTS = 333, - UV = 334, - AUX = 335, - VKNOTS = 336, - VERTEX = 337, - VERTEXANIM = 338, - VERTEXPOOL = 339, - VERTEXREF = 340, - XFMANIM = 341, - XFMSANIM = 342, - START_EGG = 343, - START_GROUP_BODY = 344, - START_TEXTURE_BODY = 345, - START_PRIMITIVE_BODY = 346 - }; + enum yytokentype + { + EGG_NUMBER = 258, + EGG_ULONG = 259, + EGG_STRING = 260, + ANIMPRELOAD = 261, + BEZIERCURVE = 262, + BFACE = 263, + BILLBOARD = 264, + BILLBOARDCENTER = 265, + BINORMAL = 266, + BUNDLE = 267, + CLOSED = 268, + COLLIDE = 269, + COMMENT = 270, + COMPONENT = 271, + COORDSYSTEM = 272, + CV = 273, + DART = 274, + DNORMAL = 275, + DRGBA = 276, + DUV = 277, + DXYZ = 278, + DCS = 279, + DISTANCE = 280, + DTREF = 281, + DYNAMICVERTEXPOOL = 282, + EXTERNAL_FILE = 283, + GROUP = 284, + DEFAULTPOSE = 285, + JOINT = 286, + KNOTS = 287, + INCLUDE = 288, + INSTANCE = 289, + LINE = 290, + LOOP = 291, + MATERIAL = 292, + MATRIX3 = 293, + MATRIX4 = 294, + MODEL = 295, + MREF = 296, + NORMAL = 297, + NURBSCURVE = 298, + NURBSSURFACE = 299, + OBJECTTYPE = 300, + ORDER = 301, + OUTTANGENT = 302, + PATCH = 303, + POINTLIGHT = 304, + POLYGON = 305, + REF = 306, + RGBA = 307, + ROTATE = 308, + ROTX = 309, + ROTY = 310, + ROTZ = 311, + SANIM = 312, + SCALAR = 313, + SCALE = 314, + SEQUENCE = 315, + SHADING = 316, + SWITCH = 317, + SWITCHCONDITION = 318, + TABLE = 319, + TABLE_V = 320, + TAG = 321, + TANGENT = 322, + TEXLIST = 323, + TEXTURE = 324, + TLENGTHS = 325, + TRANSFORM = 326, + TRANSLATE = 327, + TREF = 328, + TRIANGLEFAN = 329, + TRIANGLESTRIP = 330, + TRIM = 331, + TXT = 332, + UKNOTS = 333, + UV = 334, + AUX = 335, + VKNOTS = 336, + VERTEX = 337, + VERTEXANIM = 338, + VERTEXPOOL = 339, + VERTEXREF = 340, + XFMANIM = 341, + XFMSANIM = 342, + START_EGG = 343, + START_GROUP_BODY = 344, + START_TEXTURE_BODY = 345, + START_PRIMITIVE_BODY = 346 + }; #endif /* Tokens. */ #define EGG_NUMBER 258 @@ -220,15 +230,11 @@ #define START_TEXTURE_BODY 345 #define START_PRIMITIVE_BODY 346 +/* Value type. */ - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -#endif - extern YYSTYPE eggyylval; +int eggyyparse (void); +#endif /* !YY_EGGYY_BUILT_TMP_PARSER_YXX_H_INCLUDED */ From e1b86287ef5e46fc87b4ec7c95ab302b2d5dadbd Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 12 Feb 2019 00:32:48 +0100 Subject: [PATCH 089/144] readme: update FreeBSD package list --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a5cda4ee03..4283907f35 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ install the requisite packages using the system package manager. To install the recommended set of dependencies, you can use this command: ```bash -pkg install pkgconf png jpeg-turbo tiff freetype2 eigen squish openal opusfile libvorbis libX11 libGL ode bullet assimp openexr +pkg install pkgconf bison png jpeg-turbo tiff freetype2 harfbuzz eigen squish openal opusfile libvorbis libX11 mesa-libs ode bullet assimp openexr ``` You will also need to choose which version of Python you want to use. From 95f3e30d376a8c3c744cc20d68cbe8b8254db187 Mon Sep 17 00:00:00 2001 From: Brian Lach Date: Tue, 8 Jan 2019 18:49:13 -0500 Subject: [PATCH 090/144] ShaderAttrib: add set_shader_inputs() for C++ users Closes #521 --- panda/src/pgraph/shaderAttrib.cxx | 23 +++++++++++++++++++++++ panda/src/pgraph/shaderAttrib.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/panda/src/pgraph/shaderAttrib.cxx b/panda/src/pgraph/shaderAttrib.cxx index e519289b28..141cbc60c1 100644 --- a/panda/src/pgraph/shaderAttrib.cxx +++ b/panda/src/pgraph/shaderAttrib.cxx @@ -224,6 +224,29 @@ set_shader_input(ShaderInput &&input) const { return return_new(result); } +/** + * Returns a new ShaderAttrib with the given shader inputs set. This is a + * more efficient way to set multiple shader inputs than calling + * set_shader_input multiple times. + */ +CPT(RenderAttrib) ShaderAttrib:: +set_shader_inputs(const pvector &inputs) const { + ShaderAttrib *result = new ShaderAttrib(*this); + + size_t num_inputs = inputs.size(); + for (size_t i = 0; i < num_inputs; i++) { + const ShaderInput &input = inputs[i]; + Inputs::iterator itr = result->_inputs.find(input.get_name()); + if (itr == result->_inputs.end()) { + result->_inputs.insert(Inputs::value_type(input.get_name(), input)); + } else { + itr->second = input; + } + } + + return return_new(result); +} + /** * Sets the geometry instance count. Do not confuse this with instanceTo, * which is used for animation instancing, and has nothing to do with this. A diff --git a/panda/src/pgraph/shaderAttrib.h b/panda/src/pgraph/shaderAttrib.h index 6cd04c6d99..96c74c6b89 100644 --- a/panda/src/pgraph/shaderAttrib.h +++ b/panda/src/pgraph/shaderAttrib.h @@ -91,6 +91,8 @@ public: INLINE CPT(RenderAttrib) set_shader_input(CPT_InternalName id, const LMatrix3 &v, int priority=0) const; INLINE CPT(RenderAttrib) set_shader_input(CPT_InternalName id, double n1=0, double n2=0, double n3=0, double n4=1, int priority=0) const; + + CPT(RenderAttrib) set_shader_inputs(const pvector &inputs) const; PUBLISHED: EXTENSION(CPT(RenderAttrib) set_shader_input(CPT_InternalName, PyObject *, int priority=0) const); From 6640e5698d31cfc1c26320f8f22c9545b50cd8e3 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 12 Feb 2019 14:13:39 +0100 Subject: [PATCH 091/144] EventManager: various microoptimizations to Python event handling --- direct/src/showbase/EventManager.py | 80 +++++++++++++---------------- 1 file changed, 36 insertions(+), 44 deletions(-) diff --git a/direct/src/showbase/EventManager.py b/direct/src/showbase/EventManager.py index af8bd1c91a..319503b414 100644 --- a/direct/src/showbase/EventManager.py +++ b/direct/src/showbase/EventManager.py @@ -19,7 +19,7 @@ class EventManager: Create a C++ event queue and handler """ # Make a notify category for this class (unless there already is one) - if (EventManager.notify == None): + if EventManager.notify is None: EventManager.notify = directNotify.newCategory("EventManager") self.eventQueue = eventQueue @@ -37,8 +37,10 @@ class EventManager: processFunc = self.processEventPstats else: processFunc = self.processEvent - while (not self.eventQueue.isQueueEmpty()): - processFunc(self.eventQueue.dequeueEvent()) + isEmptyFunc = self.eventQueue.isQueueEmpty + dequeueFunc = self.eventQueue.dequeueEvent + while not isEmptyFunc(): + processFunc(dequeueFunc()) def eventLoopTask(self, task): """ @@ -78,13 +80,13 @@ class EventManager: # ******** Duplicate any changes in processEventPstats ********* # ************************************************************** # Get the event name - eventName = event.getName() + eventName = event.name if eventName: paramList = [] - for i in range(event.getNumParameters()): - eventParameter = event.getParameter(i) + for eventParameter in event.parameters: eventParameterData = self.parseEventParameter(eventParameter) paramList.append(eventParameterData) + # Do not print the new frame debug, it is too noisy! if (EventManager.notify.getDebug() and eventName != 'NewFrame'): EventManager.notify.debug('received C++ event named: ' + eventName + @@ -94,13 +96,12 @@ class EventManager: # ************************************************************** # Send the event, we used to send it with the event # name as a parameter, but now you can use extraArgs for that - if paramList: - messenger.send(eventName, paramList) - else: - messenger.send(eventName) + messenger.send(eventName, paramList) + # Also send the event down into C++ land - if self.eventHandler: - self.eventHandler.dispatchEvent(event) + handler = self.eventHandler + if handler: + handler.dispatchEvent(event) else: # An unnamed event from C++ is probably a bad thing @@ -115,13 +116,13 @@ class EventManager: # ******** Duplicate any changes in processEvent ********* # ******************************************************** # Get the event name - eventName = event.getName() + eventName = event.name if eventName: paramList = [] - for i in range(event.getNumParameters()): - eventParameter = event.getParameter(i) + for eventParameter in event.parameters: eventParameterData = self.parseEventParameter(eventParameter) paramList.append(eventParameterData) + # Do not print the new frame debug, it is too noisy! if (EventManager.notify.getDebug() and eventName != 'NewFrame'): EventManager.notify.debug('received C++ event named: ' + eventName + @@ -131,45 +132,36 @@ class EventManager: # ******************************************************** # ******** Duplicate any changes in processEvent ********* # ******************************************************** - if self._wantPstats: - name = eventName - hyphen = name.find('-') - if hyphen >= 0: - name = name[0:hyphen] - pstatCollector = PStatCollector('App:Show code:eventManager:' + name) - pstatCollector.start() - if self.eventHandler: - cppPstatCollector = PStatCollector( - 'App:Show code:eventManager:' + name + ':C++') - - if paramList: - messenger.send(eventName, paramList) - else: - messenger.send(eventName) - # Also send the event down into C++ land + name = eventName + hyphen = name.find('-') + if hyphen >= 0: + name = name[0:hyphen] + pstatCollector = PStatCollector('App:Show code:eventManager:' + name) + pstatCollector.start() if self.eventHandler: - if self._wantPstats: - cppPstatCollector.start() - self.eventHandler.dispatchEvent(event) - # ******************************************************** - # ******** Duplicate any changes in processEvent ********* - # ******************************************************** + cppPstatCollector = PStatCollector( + 'App:Show code:eventManager:' + name + ':C++') - if self._wantPstats: - if self.eventHandler: - cppPstatCollector.stop() - pstatCollector.stop() + messenger.send(eventName, paramList) + + # Also send the event down into C++ land + handler = self.eventHandler + if handler: + cppPstatCollector.start() + handler.dispatchEvent(event) + cppPstatCollector.stop() + + pstatCollector.stop() else: # An unnamed event from C++ is probably a bad thing EventManager.notify.warning('unnamed event in processEvent') - def restart(self): - if self.eventQueue == None: + if self.eventQueue is None: self.eventQueue = EventQueue.getGlobalEventQueue() - if self.eventHandler == None: + if self.eventHandler is None: if self.eventQueue == EventQueue.getGlobalEventQueue(): # If we are using the global event queue, then we also # want to use the global event handler. From 094458a8df965ad9369fac7214869f5ec153da16 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 12 Feb 2019 15:40:31 +0100 Subject: [PATCH 092/144] xfile: fix read from uninitialized memory (see #554) --- pandatool/src/xfile/xFile.cxx | 2 +- pandatool/src/xfile/xFileNode.I | 10 ++++++++++ pandatool/src/xfile/xFileNode.h | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/pandatool/src/xfile/xFile.cxx b/pandatool/src/xfile/xFile.cxx index c5534e0af1..3c0d7b3445 100644 --- a/pandatool/src/xfile/xFile.cxx +++ b/pandatool/src/xfile/xFile.cxx @@ -34,7 +34,7 @@ PT(XFile) XFile::_standard_templates; * */ XFile:: -XFile(bool keep_names) : XFileNode(this, "") { +XFile(bool keep_names) : XFileNode(this) { _major_version = 3; _minor_version = 2; _format_type = FT_text; diff --git a/pandatool/src/xfile/xFileNode.I b/pandatool/src/xfile/xFileNode.I index 6032a749e2..735c2dce3a 100644 --- a/pandatool/src/xfile/xFileNode.I +++ b/pandatool/src/xfile/xFileNode.I @@ -11,6 +11,16 @@ * @date 2004-10-03 */ +/** + * + */ +INLINE XFileNode:: +XFileNode(XFile *x_file) : + Namable(), + _x_file(x_file) +{ +} + /** * */ diff --git a/pandatool/src/xfile/xFileNode.h b/pandatool/src/xfile/xFileNode.h index a954b8f9fd..2cd9f6d3f6 100644 --- a/pandatool/src/xfile/xFileNode.h +++ b/pandatool/src/xfile/xFileNode.h @@ -38,6 +38,9 @@ class Filename; */ class XFileNode : public TypedObject, public Namable, virtual public ReferenceCount { +protected: + INLINE XFileNode(XFile *x_file); + public: XFileNode(XFile *x_file, const std::string &name); virtual ~XFileNode(); From 55ac585745a10c4feeb822d4109748374b83169c Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 12 Feb 2019 19:02:51 +0100 Subject: [PATCH 093/144] makewheel: exclude libdrm.so.2 which causes GLX context failure --- doc/ReleaseNotes | 1 + makepanda/makewheel.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index 108111071c..181b1eedab 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -4,6 +4,7 @@ This is a bugfix release intended to fix several issues in 1.10.0. * Fix crashes when gamepad is plugged in on 32-bit Windows * Fix deploy-ng error regarding 'exist_ok' on Python 2 +* Fix Linux install from pip not working with some mesa drivers * Fix compatibility issues with upcoming Python 3.8 * Fix regression with Audio3DManager.setSoundVelocityAuto() * Fix issues when awaiting loader.loadModel in Python 3.7 diff --git a/makepanda/makewheel.py b/makepanda/makewheel.py index 6dd2b32ef4..71f7ae945b 100644 --- a/makepanda/makewheel.py +++ b/makepanda/makewheel.py @@ -104,7 +104,7 @@ MANYLINUX_LIBS = [ # These are not mentioned in manylinux1 spec but should nonetheless always # be excluded. - "linux-vdso.so.1", "linux-gate.so.1", "ld-linux.so.2", + "linux-vdso.so.1", "linux-gate.so.1", "ld-linux.so.2", "libdrm.so.2", ] # Binaries to never scan for dependencies on non-Windows systems. From 2807d1d166a7088d1e678a9c813eccbd0f2bd30e Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 13 Feb 2019 15:42:20 +0100 Subject: [PATCH 094/144] samples: fix read from negative GeomVertexData row in fractal-plants --- samples/fractal-plants/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/fractal-plants/main.py b/samples/fractal-plants/main.py index fb16a5b1bc..7c0492af85 100755 --- a/samples/fractal-plants/main.py +++ b/samples/fractal-plants/main.py @@ -141,11 +141,14 @@ def drawBody(nodePath, vdata, pos, vecList, radius=1, keepDrawing=True, numVerti drawReWriter.addData1f(keepDrawing) currAngle += angleSlice + if startRow == 0: + return + drawReader = GeomVertexReader(vdata, "drawFlag") drawReader.setRow(startRow - numVertices) # we cant draw quads directly so we use Tristrips - if (startRow != 0) & (drawReader.getData1f() != False): + if drawReader.getData1i() != 0: lines = GeomTristrips(Geom.UHStatic) half = int(numVertices * 0.5) for i in range(numVertices): From b75982a610434ef50c7ccc00c7b9f77cc3bb4cfa Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 14 Feb 2019 19:17:13 +0100 Subject: [PATCH 095/144] interval: fix QuatInterval not normalizing the start quaternion --- direct/src/interval/cLerpNodePathInterval.I | 4 ++++ direct/src/interval/cLerpNodePathInterval.cxx | 4 ++-- doc/ReleaseNotes | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/direct/src/interval/cLerpNodePathInterval.I b/direct/src/interval/cLerpNodePathInterval.I index 03c90753cb..5d4337f9df 100644 --- a/direct/src/interval/cLerpNodePathInterval.I +++ b/direct/src/interval/cLerpNodePathInterval.I @@ -106,6 +106,8 @@ set_end_hpr(const LQuaternion &quat) { * if either set_end_quat() or set_end_hpr() is also called. This parameter * is optional; if unspecified, the value will be taken from the node's actual * rotation at the time the lerp is performed. + * + * The given quaternion needs to be normalized. */ INLINE void CLerpNodePathInterval:: set_start_quat(const LQuaternion &quat) { @@ -143,6 +145,8 @@ set_end_quat(const LVecBase3 &hpr) { * This replaces a previous call to set_end_hpr(). If neither set_end_quat() * nor set_end_hpr() is called, the node's rotation will not be affected by * the lerp. + * + * The given quaternion needs to be normalized. */ INLINE void CLerpNodePathInterval:: set_end_quat(const LQuaternion &quat) { diff --git a/direct/src/interval/cLerpNodePathInterval.cxx b/direct/src/interval/cLerpNodePathInterval.cxx index 2fbc8a7e75..97babae49e 100644 --- a/direct/src/interval/cLerpNodePathInterval.cxx +++ b/direct/src/interval/cLerpNodePathInterval.cxx @@ -174,14 +174,14 @@ priv_step(double t) { setup_slerp(); } else if ((_flags & F_bake_in_start) != 0) { - set_start_quat(transform->get_quat()); + set_start_quat(transform->get_norm_quat()); setup_slerp(); } else { if (_prev_d == 1.0) { _start_quat = _end_quat; } else { - LQuaternion prev_value = transform->get_quat(); + LQuaternion prev_value = transform->get_norm_quat(); _start_quat = (prev_value - _prev_d * _end_quat) / (1.0 - _prev_d); } setup_slerp(); diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index 181b1eedab..ba67ff8dc8 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -14,6 +14,7 @@ This is a bugfix release intended to fix several issues in 1.10.0. * Depth buffer now defaults to 24-bit on macOS (fixes flickering) * Fix no devices being detected on Windows with threading-model * Implement collision tests from Capsule and Box into InvSphere +* Fix odd behavior and occasional crash in QuatInterval * Fix SpriteAnim error in particle system * Fix ShaderGenerator error when using too many shadowing lights * Fix interrogate crash in Python 3 with optional wstring args From ff2fbe60efa6eff584441b3537cf195877748555 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 14 Feb 2019 21:42:14 +0100 Subject: [PATCH 096/144] pipeline: revert change causing shutdown crash with DEBUG_THREADS We actually need to leak this lock, because we need to call this at static destruction time, and we can't guarantee static destruction order. This reverts commit afed80e83a5c033f03497bcf38353794e662eedf. --- panda/src/pipeline/conditionVarDebug.cxx | 26 +++++++-------- panda/src/pipeline/mutexDebug.I | 42 ++++++++++++++++-------- panda/src/pipeline/mutexDebug.cxx | 16 ++++----- panda/src/pipeline/mutexDebug.h | 4 ++- 4 files changed, 52 insertions(+), 36 deletions(-) diff --git a/panda/src/pipeline/conditionVarDebug.cxx b/panda/src/pipeline/conditionVarDebug.cxx index 8485ad1272..c38bdc6d52 100644 --- a/panda/src/pipeline/conditionVarDebug.cxx +++ b/panda/src/pipeline/conditionVarDebug.cxx @@ -29,7 +29,7 @@ using std::ostringstream; ConditionVarDebug:: ConditionVarDebug(MutexDebug &mutex) : _mutex(mutex), - _impl(mutex._global_lock) + _impl(*mutex.get_global_lock()) { nassertv(!_mutex._allow_recursion); } @@ -60,7 +60,7 @@ ConditionVarDebug:: */ void ConditionVarDebug:: wait() { - _mutex._global_lock.lock(); + _mutex._global_lock->lock(); Thread *current_thread = Thread::get_current_thread(); @@ -69,7 +69,7 @@ wait() { ostr << *current_thread << " attempted to wait on " << *this << " without holding " << _mutex; nassert_raise(ostr.str()); - _mutex._global_lock.unlock(); + _mutex._global_lock->unlock(); return; } @@ -95,7 +95,7 @@ wait() { << *current_thread << " awake on " << *this << "\n"; } - _mutex._global_lock.unlock(); + _mutex._global_lock->unlock(); } /** @@ -108,7 +108,7 @@ wait() { */ void ConditionVarDebug:: wait(double timeout) { - _mutex._global_lock.lock(); + _mutex._global_lock->lock(); Thread *current_thread = Thread::get_current_thread(); @@ -117,7 +117,7 @@ wait(double timeout) { ostr << *current_thread << " attempted to wait on " << *this << " without holding " << _mutex; nassert_raise(ostr.str()); - _mutex._global_lock.unlock(); + _mutex._global_lock->unlock(); return; } @@ -144,7 +144,7 @@ wait(double timeout) { << *current_thread << " awake on " << *this << "\n"; } - _mutex._global_lock.unlock(); + _mutex._global_lock->unlock(); } /** @@ -158,7 +158,7 @@ wait(double timeout) { */ void ConditionVarDebug:: notify() { - _mutex._global_lock.lock(); + _mutex._global_lock->lock(); /* if (!_mutex.do_debug_is_locked()) { @@ -167,7 +167,7 @@ notify() { ostr << *current_thread << " attempted to notify " << *this << " without holding " << _mutex; nassert_raise(ostr.str()); - _mutex._global_lock.unlock(); + _mutex._global_lock->unlock(); return; } */ @@ -179,7 +179,7 @@ notify() { } _impl.notify(); - _mutex._global_lock.unlock(); + _mutex._global_lock->unlock(); } /** @@ -190,7 +190,7 @@ notify() { */ void ConditionVarDebug:: notify_all() { - _mutex._global_lock.lock(); + _mutex._global_lock->lock(); /* if (!_mutex.do_debug_is_locked()) { @@ -199,7 +199,7 @@ notify_all() { ostr << *current_thread << " attempted to notify " << *this << " without holding " << _mutex; nassert_raise(ostr.str()); - _mutex._global_lock.unlock(); + _mutex._global_lock->unlock(); return; } */ @@ -211,7 +211,7 @@ notify_all() { } _impl.notify_all(); - _mutex._global_lock.unlock(); + _mutex._global_lock->unlock(); } /** diff --git a/panda/src/pipeline/mutexDebug.I b/panda/src/pipeline/mutexDebug.I index 0995d78db0..ae3ce74967 100644 --- a/panda/src/pipeline/mutexDebug.I +++ b/panda/src/pipeline/mutexDebug.I @@ -18,9 +18,9 @@ INLINE void MutexDebug:: lock() { TAU_PROFILE("void MutexDebug::acquire()", " ", TAU_USER); - _global_lock.lock(); + _global_lock->lock(); ((MutexDebug *)this)->do_lock(Thread::get_current_thread()); - _global_lock.unlock(); + _global_lock->unlock(); } /** @@ -30,9 +30,9 @@ lock() { INLINE bool MutexDebug:: try_lock() { TAU_PROFILE("void MutexDebug::try_lock()", " ", TAU_USER); - _global_lock.lock(); + _global_lock->lock(); bool acquired = ((MutexDebug *)this)->do_try_lock(Thread::get_current_thread()); - _global_lock.unlock(); + _global_lock->unlock(); return acquired; } @@ -43,9 +43,9 @@ try_lock() { INLINE void MutexDebug:: unlock() { TAU_PROFILE("void MutexDebug::unlock()", " ", TAU_USER); - _global_lock.lock(); + _global_lock->lock(); ((MutexDebug *)this)->do_unlock(); - _global_lock.unlock(); + _global_lock->unlock(); } /** @@ -62,9 +62,9 @@ INLINE void MutexDebug:: acquire(Thread *current_thread) const { TAU_PROFILE("void MutexDebug::acquire(Thread *)", " ", TAU_USER); nassertv(current_thread == Thread::get_current_thread()); - _global_lock.lock(); + _global_lock->lock(); ((MutexDebug *)this)->do_lock(current_thread); - _global_lock.unlock(); + _global_lock->unlock(); } /** @@ -75,9 +75,9 @@ INLINE bool MutexDebug:: try_acquire(Thread *current_thread) const { TAU_PROFILE("void MutexDebug::try_acquire(Thread *)", " ", TAU_USER); nassertr(current_thread == Thread::get_current_thread(), false); - _global_lock.lock(); + _global_lock->lock(); bool acquired = ((MutexDebug *)this)->do_try_lock(current_thread); - _global_lock.unlock(); + _global_lock->unlock(); return acquired; } @@ -114,9 +114,9 @@ elevate_lock() const { INLINE void MutexDebug:: release() const { TAU_PROFILE("void MutexDebug::release()", " ", TAU_USER); - _global_lock.lock(); + _global_lock->lock(); ((MutexDebug *)this)->do_unlock(); - _global_lock.unlock(); + _global_lock->unlock(); } /** @@ -128,8 +128,22 @@ release() const { INLINE bool MutexDebug:: debug_is_locked() const { TAU_PROFILE("bool MutexDebug::debug_is_locked()", " ", TAU_USER); - _global_lock.lock(); + _global_lock->lock(); bool is_locked = do_debug_is_locked(); - _global_lock.unlock(); + _global_lock->unlock(); return is_locked; } + +/** + * Ensures the global MutexImpl pointer has been created, and returns its + * pointer. Since this method is called by the MutexDebug constructor, any + * other (non-static) methods of MutexDebug may simply assume that the pointer + * has already been created. + */ +INLINE MutexTrueImpl *MutexDebug:: +get_global_lock() { + if (_global_lock == nullptr) { + _global_lock = new MutexTrueImpl; + } + return _global_lock; +} diff --git a/panda/src/pipeline/mutexDebug.cxx b/panda/src/pipeline/mutexDebug.cxx index daa6f3a7ed..d1e0194e6f 100644 --- a/panda/src/pipeline/mutexDebug.cxx +++ b/panda/src/pipeline/mutexDebug.cxx @@ -21,7 +21,7 @@ using std::ostream; using std::ostringstream; int MutexDebug::_pstats_count = 0; -MutexTrueImpl MutexDebug::_global_lock; +MutexTrueImpl *MutexDebug::_global_lock; /** * @@ -34,7 +34,7 @@ MutexDebug(const std::string &name, bool allow_recursion, bool lightweight) : _locking_thread(nullptr), _lock_count(0), _deleted_name(nullptr), - _cvar_impl(_global_lock) + _cvar_impl(*get_global_lock()) { #ifndef SIMPLE_THREADS // If we're using real threads, there's no such thing as a lightweight @@ -87,12 +87,12 @@ output(ostream &out) const { */ void MutexDebug:: output_with_holder(ostream &out) const { - _global_lock.lock(); + _global_lock->lock(); output(out); if (_locking_thread != nullptr) { out << " (held by " << *_locking_thread << ")\n"; } - _global_lock.unlock(); + _global_lock->unlock(); } /** @@ -102,9 +102,9 @@ output_with_holder(ostream &out) const { */ void MutexDebug:: increment_pstats() { - _global_lock.lock(); + _global_lock->lock(); ++_pstats_count; - _global_lock.unlock(); + _global_lock->unlock(); } /** @@ -113,9 +113,9 @@ increment_pstats() { */ void MutexDebug:: decrement_pstats() { - _global_lock.lock(); + _global_lock->lock(); --_pstats_count; - _global_lock.unlock(); + _global_lock->unlock(); } /** diff --git a/panda/src/pipeline/mutexDebug.h b/panda/src/pipeline/mutexDebug.h index 775ff12966..298fd9f7ca 100644 --- a/panda/src/pipeline/mutexDebug.h +++ b/panda/src/pipeline/mutexDebug.h @@ -65,6 +65,8 @@ private: void report_deadlock(Thread *current_thread); private: + INLINE static MutexTrueImpl *get_global_lock(); + bool _allow_recursion; bool _lightweight; Thread *_locking_thread; @@ -78,7 +80,7 @@ private: ConditionVarImpl _cvar_impl; static int _pstats_count; - static MutexTrueImpl _global_lock; + static MutexTrueImpl *_global_lock; friend class ConditionVarDebug; }; From f97ba9000b9247ac0bca00d345a4a81eea1e91cd Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 14 Feb 2019 22:39:56 +0100 Subject: [PATCH 097/144] pipeline: don't use uninitialized value for main thread unique id See #554 --- panda/src/pipeline/threadPosixImpl.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/panda/src/pipeline/threadPosixImpl.cxx b/panda/src/pipeline/threadPosixImpl.cxx index 0d88c5ebe8..cdabf033c8 100644 --- a/panda/src/pipeline/threadPosixImpl.cxx +++ b/panda/src/pipeline/threadPosixImpl.cxx @@ -58,6 +58,7 @@ ThreadPosixImpl:: void ThreadPosixImpl:: setup_main_thread() { _status = S_running; + _thread = pthread_self(); } /** From 20f0a69c7511b82349d122a28c2fff3d05deba77 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 14 Feb 2019 22:40:46 +0100 Subject: [PATCH 098/144] pipeline: use decimal representation for unique thread ID on FreeBSD This matches the behaviour on Linux. --- panda/src/pipeline/threadPosixImpl.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/pipeline/threadPosixImpl.cxx b/panda/src/pipeline/threadPosixImpl.cxx index cdabf033c8..18e76cb8d2 100644 --- a/panda/src/pipeline/threadPosixImpl.cxx +++ b/panda/src/pipeline/threadPosixImpl.cxx @@ -181,7 +181,7 @@ join() { std::string ThreadPosixImpl:: get_unique_id() const { std::ostringstream strm; - strm << getpid() << "." << _thread; + strm << getpid() << "." << (uintptr_t)_thread; return strm.str(); } From c41c2219c46337fd97f10ab5c77e7fc290e2d668 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 14 Feb 2019 22:41:59 +0100 Subject: [PATCH 099/144] makewheel: add long description to METADATA file --- makepanda/makewheel.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/makepanda/makewheel.py b/makepanda/makewheel.py index 71f7ae945b..fea29bd17f 100644 --- a/makepanda/makewheel.py +++ b/makepanda/makewheel.py @@ -144,6 +144,32 @@ METADATA = { "classifiers": GetMetadataValue('classifiers'), } +DESCRIPTION = """ +The Panda3D free 3D game engine +=============================== + +Panda3D is a powerful 3D engine written in C++, with a complete set of Python +bindings. Unlike other engines, these bindings are automatically generated, +meaning that they are always up-to-date and complete: all functions of the +engine can be controlled from Python. All major Panda3D applications have been +written in Python, this is the intended way of using the engine. + +Panda3D now supports automatic shader generation, which now means you can use +normal maps, gloss maps, glow maps, HDR, cartoon shading, and the like without +having to write any shaders. + +Panda3D is a modern engine supporting advanced features such as shaders, +stencil, and render-to-texture. Panda3D is unusual in that it emphasizes a +short learning curve, rapid development, and extreme stability and robustness. +Panda3D is free software that runs under Windows, Linux, or macOS. + +The Panda3D team is very concerned with making the engine accessible to new +users. We provide a detailed manual, a complete API reference, and a large +collection of sample programs to help you get started. We have active forums, +with many helpful users, and the developers are regularly online to answer +questions. +""" + PANDA3D_TOOLS_INIT = """import os, sys import panda3d @@ -544,6 +570,8 @@ def makewheel(version, output_dir, platform=None): "Platform: {0}\n".format(platform), ] + ["Classifier: {0}\n".format(c) for c in METADATA['classifiers']]) + metadata += '\n' + DESCRIPTION.strip() + '\n' + # Zip it up and name it the right thing whl = WheelFile('panda3d', version, platform) whl.lib_path = [libs_dir] From 87e0ff29eb456e0b213f3454bd78ebcac8f22558 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 14 Feb 2019 22:56:49 +0100 Subject: [PATCH 100/144] readme: update version number of thirdparty packages downloads [skip ci] --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4283907f35..0c4757d577 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,8 @@ depending on whether you are on a 32-bit or 64-bit system, or you can [click here](https://github.com/rdb/panda3d-thirdparty) for instructions on building them from source. -https://www.panda3d.org/download/panda3d-1.10.0/panda3d-1.10.0-tools-win64.zip -https://www.panda3d.org/download/panda3d-1.10.0/panda3d-1.10.0-tools-win32.zip +https://www.panda3d.org/download/panda3d-1.10.1/panda3d-1.10.1-tools-win64.zip +https://www.panda3d.org/download/panda3d-1.10.1/panda3d-1.10.1-tools-win32.zip After acquiring these dependencies, you may simply build Panda3D from the command prompt using the following command. (Change `14.1` to `14` if you are @@ -133,7 +133,7 @@ macOS ----- On macOS, you will need to download a set of precompiled thirdparty packages in order to -compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.9.4/panda3d-1.9.4-tools-mac.tar.gz). +compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.1/panda3d-1.10.1-tools-mac.tar.gz). After placing the thirdparty directory inside the panda3d source directory, you may build Panda3D using a command like the following: From db8221a03dee2be6522c650dcf76d43347a9af87 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 14 Feb 2019 23:19:51 +0100 Subject: [PATCH 101/144] pgraph: remove pointless lock grab from RenderAttrib destructor --- panda/src/pgraph/renderAttrib.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 362419ff65..4abde672dd 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -45,8 +45,6 @@ RenderAttrib() { */ RenderAttrib:: ~RenderAttrib() { - LightReMutexHolder holder(*_attribs_lock); - // unref() should have cleared this. nassertv(_saved_entry == -1); } From 9bf37051ac6c39d13a11538e7d954685a2643610 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 17 Feb 2019 10:52:22 +0100 Subject: [PATCH 102/144] collide: fix _collider_sort not copied in CollisionNode copy ctor See #554 --- panda/src/collide/collisionNode.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/panda/src/collide/collisionNode.cxx b/panda/src/collide/collisionNode.cxx index ce037f917f..1196ba20c7 100644 --- a/panda/src/collide/collisionNode.cxx +++ b/panda/src/collide/collisionNode.cxx @@ -58,6 +58,7 @@ CollisionNode:: CollisionNode(const CollisionNode ©) : PandaNode(copy), _from_collide_mask(copy._from_collide_mask), + _collider_sort(copy._collider_sort), _solids(copy._solids) { } From ba3a826bff20035ad408dcbfdb095bc40fd8df85 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 17 Feb 2019 13:02:56 +0100 Subject: [PATCH 103/144] gobj: fix crash reading unaligned float4 column in GeomVertexReader Observed when calling flatten_strong() on model with vertex colors loaded via Assimp. --- panda/src/gobj/geomVertexColumn.cxx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/panda/src/gobj/geomVertexColumn.cxx b/panda/src/gobj/geomVertexColumn.cxx index d04b69a307..9e6c7bd188 100644 --- a/panda/src/gobj/geomVertexColumn.cxx +++ b/panda/src/gobj/geomVertexColumn.cxx @@ -258,7 +258,12 @@ make_packer() const { case 3: return new Packer_point_nativefloat_3; case 4: - return new Packer_point_nativefloat_4; + // Reader may assume 16-byte alignment. + if ((get_start() & 0xf) == 0) { + return new Packer_point_nativefloat_4; + } else { + return new Packer_point_float32_4; + } } } else { switch (get_num_components()) { @@ -309,7 +314,8 @@ make_packer() const { return new Packer_argb_packed; case NT_float32: - if (sizeof(float) == sizeof(PN_float32)) { + if (sizeof(float) == sizeof(PN_float32) && + (get_start() & 0xf) == 0) { // Use the native float type implementation for a tiny bit more // optimization. return new Packer_rgba_nativefloat_4; From 5e9c478b1a92f374ec6b03bbe9a0c23213313019 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 18 Feb 2019 12:50:28 +0100 Subject: [PATCH 104/144] Raise version number to 1.10.2 on release/1.10.x branch [skip ci] --- dtool/PandaVersion.pp | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dtool/PandaVersion.pp b/dtool/PandaVersion.pp index f504aab0cd..aaaa302239 100644 --- a/dtool/PandaVersion.pp +++ b/dtool/PandaVersion.pp @@ -7,7 +7,7 @@ // place to put this. // Use spaces to separate the major, minor, and sequence numbers here. -#define PANDA_VERSION 1 10 1 +#define PANDA_VERSION 1 10 2 // This variable will be defined to false in the CVS repository, but // scripts that generate source tarballs and/or binary releases for diff --git a/setup.cfg b/setup.cfg index a51084e2e8..09a266fc76 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = Panda3D -version = 1.10.1 +version = 1.10.2 url = https://www.panda3d.org/ description = Panda3D is a framework for 3D rendering and game development for Python and C++ programs. license = Modified BSD License From d5a4dcfd1dc7bd8db7566e8d58cb46d044a9c5d3 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 19 Feb 2019 11:50:29 +0100 Subject: [PATCH 105/144] Clarify framebuffer-software/hardware comment in Config.prc [skip ci] --- makepanda/config.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makepanda/config.in b/makepanda/config.in index 1317517339..e262da5bf0 100644 --- a/makepanda/config.in +++ b/makepanda/config.in @@ -31,7 +31,7 @@ fullscreen #f # The framebuffer-hardware flag forces it to use an accelerated driver. # The framebuffer-software flag forces it to use a software renderer. -# If you don't set either, it will use whatever's available. +# If you set both to false, it will use whatever's available. framebuffer-hardware #t framebuffer-software #f From c37a33baefeb691e8b826b00e7c3c95892a19fe9 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 19 Feb 2019 13:45:37 +0100 Subject: [PATCH 106/144] interrogate: don't export bindings for global operators linmath exports a global __mul__, which isn't really useful. --- dtool/src/interrogate/interfaceMakerPythonNative.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 5f351dbbc1..03c3352d13 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -7526,6 +7526,12 @@ is_remap_legal(FunctionRemap *remap) { } } + // Don't export global operators. + if (!remap->_has_this && + remap->_cppfunc->get_simple_name().compare(0, 9, "operator ") == 0) { + return false; + } + // ok all looks ok. return true; } From 2c91fdda1b6630b3b1166bf99f8ad3cb6bd6baa9 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 19 Feb 2019 13:46:38 +0100 Subject: [PATCH 107/144] interrogate: support in-place ops on properties (eg. light.color *= 2) --- .../interrogate/interfaceMakerPythonNative.cxx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 03c3352d13..e6c2186fc8 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -1860,6 +1860,12 @@ write_module_class(ostream &out, Object *obj) { } else { return_flags |= RF_pyobject; } + bool all_nonconst = true; + for (FunctionRemap *remap : def._remaps) { + if (remap->_const_method) { + all_nonconst = false; + } + } out << "//////////////////\n"; out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; @@ -1872,9 +1878,16 @@ write_module_class(ostream &out, Object *obj) { // This is for things like __sub__, which Python likes to call on // the wrong-type objects. out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **)&local_this);\n"; - out << " if (local_this == nullptr) {\n"; + if (all_nonconst) { + out << " if (local_this == nullptr || DtoolInstance_IS_CONST(self)) {\n"; + } else { + out << " if (local_this == nullptr) {\n"; + } out << " Py_INCREF(Py_NotImplemented);\n"; out << " return Py_NotImplemented;\n"; + } else if (all_nonconst) { + out << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; + out << " return nullptr;\n"; } else { out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; out << " return nullptr;\n"; @@ -1883,7 +1896,7 @@ write_module_class(ostream &out, Object *obj) { string expected_params; write_function_forset(out, def._remaps, 1, 1, expected_params, 2, true, true, - AT_single_arg, return_flags, false); + AT_single_arg, return_flags, false, !all_nonconst); if (rfi->second._wrapper_type != WT_one_param) { out << " Py_INCREF(Py_NotImplemented);\n"; From 9d42e25539ba846aff6713630559a45536b890f6 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 19 Feb 2019 20:12:06 +0100 Subject: [PATCH 108/144] pgraph: make ParamNodePath::get_value() return a copy See #554. --- panda/src/pgraph/paramNodePath.I | 2 +- panda/src/pgraph/paramNodePath.h | 2 +- panda/src/pgraph/shaderAttrib.cxx | 2 +- panda/src/pgraph/shaderAttrib.h | 2 +- panda/src/pgraph/shaderInput.cxx | 2 +- panda/src/pgraph/shaderInput.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/panda/src/pgraph/paramNodePath.I b/panda/src/pgraph/paramNodePath.I index 89d6a9e67b..354a2af7ec 100644 --- a/panda/src/pgraph/paramNodePath.I +++ b/panda/src/pgraph/paramNodePath.I @@ -40,7 +40,7 @@ get_value_type() const { /** * Retrieves the NodePath stored in the parameter. */ -INLINE const NodePath &ParamNodePath:: +INLINE NodePath ParamNodePath:: get_value() const { return _node_path; } diff --git a/panda/src/pgraph/paramNodePath.h b/panda/src/pgraph/paramNodePath.h index bd0967d5f8..daab53e41e 100644 --- a/panda/src/pgraph/paramNodePath.h +++ b/panda/src/pgraph/paramNodePath.h @@ -30,7 +30,7 @@ PUBLISHED: INLINE ParamNodePath(NodePath &&node_path) noexcept; INLINE virtual TypeHandle get_value_type() const; - INLINE const NodePath &get_value() const; + INLINE NodePath get_value() const; virtual void output(std::ostream &out) const; diff --git a/panda/src/pgraph/shaderAttrib.cxx b/panda/src/pgraph/shaderAttrib.cxx index 141cbc60c1..24b245b218 100644 --- a/panda/src/pgraph/shaderAttrib.cxx +++ b/panda/src/pgraph/shaderAttrib.cxx @@ -314,7 +314,7 @@ get_shader_input(const std::string &id) const { * Returns the ShaderInput as a nodepath. Assertion fails if there is none, * or if it is not a nodepath. */ -const NodePath &ShaderAttrib:: +NodePath ShaderAttrib:: get_shader_input_nodepath(const InternalName *id) const { static NodePath resfail; Inputs::const_iterator i = _inputs.find(id); diff --git a/panda/src/pgraph/shaderAttrib.h b/panda/src/pgraph/shaderAttrib.h index 96c74c6b89..29b535ff8a 100644 --- a/panda/src/pgraph/shaderAttrib.h +++ b/panda/src/pgraph/shaderAttrib.h @@ -115,7 +115,7 @@ PUBLISHED: const ShaderInput &get_shader_input(const InternalName *id) const; const ShaderInput &get_shader_input(const std::string &id) const; - const NodePath &get_shader_input_nodepath(const InternalName *id) const; + NodePath get_shader_input_nodepath(const InternalName *id) const; LVecBase4 get_shader_input_vector(InternalName *id) const; Texture *get_shader_input_texture(const InternalName *id, SamplerState *sampler=nullptr) const; const Shader::ShaderPtrData *get_shader_input_ptr(const InternalName *id) const; diff --git a/panda/src/pgraph/shaderInput.cxx b/panda/src/pgraph/shaderInput.cxx index b017045b22..ddb390f05d 100644 --- a/panda/src/pgraph/shaderInput.cxx +++ b/panda/src/pgraph/shaderInput.cxx @@ -89,7 +89,7 @@ add_hash(size_t hash) const { * Warning: no error checking is done. This *will* crash if get_value_type() * is not M_nodepath. */ -const NodePath &ShaderInput:: +NodePath ShaderInput:: get_nodepath() const { return DCAST(ParamNodePath, _value)->get_value(); } diff --git a/panda/src/pgraph/shaderInput.h b/panda/src/pgraph/shaderInput.h index 39ae9ba835..dbbf617ff0 100644 --- a/panda/src/pgraph/shaderInput.h +++ b/panda/src/pgraph/shaderInput.h @@ -119,7 +119,7 @@ PUBLISHED: INLINE const LVecBase4 &get_vector() const; INLINE const Shader::ShaderPtrData &get_ptr() const; - const NodePath &get_nodepath() const; + NodePath get_nodepath() const; Texture *get_texture() const; const SamplerState &get_sampler() const; From 6a008ae7246a0d1bbf926a94127d678c7a632f75 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 19 Feb 2019 21:21:22 +0100 Subject: [PATCH 109/144] x11display: fix threaded crash when using get_keyboard_map() --- panda/src/x11display/x11GraphicsWindow.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index df038a6dad..0aa4e0bf64 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -1976,6 +1976,8 @@ get_keyboard_map() const { // XkbGetMap(_display, XkbAllMapComponentsMask, XkbUseCoreKbd); ButtonMap *map = new ButtonMap; + LightReMutexHolder holder(x11GraphicsPipe::_x_mutex); + for (int k = 9; k <= 135; ++k) { ButtonHandle raw_button = map_raw_button(k); if (raw_button == ButtonHandle::none()) { From bf846cd461a2bac46c34ada696ff53c34af8b048 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 19 Feb 2019 21:22:04 +0100 Subject: [PATCH 110/144] makepanda: fall back to libassimpd.so if libassimp.so not found --- makepanda/makepanda.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 3251c3272a..3341262452 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -905,13 +905,14 @@ if (COMPILER=="GCC"): fcollada_libs = ("FColladaD", "FColladaSD", "FColladaS") # WARNING! The order of the ffmpeg libraries matters! ffmpeg_libs = ("libavformat", "libavcodec", "libavutil") + assimp_libs = ("libassimp", "libassimpd") # Name pkg-config libs, include(dir)s if (not RUNTIME): SmartPkgEnable("EIGEN", "eigen3", (), ("Eigen/Dense",), target_pkg = 'ALWAYS') SmartPkgEnable("ARTOOLKIT", "", ("AR"), "AR/ar.h") SmartPkgEnable("FCOLLADA", "", ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h")) - SmartPkgEnable("ASSIMP", "assimp", ("assimp"), "assimp/Importer.hpp") + SmartPkgEnable("ASSIMP", "assimp", ChooseLib(assimp_libs, "ASSIMP"), "assimp/Importer.hpp") SmartPkgEnable("FFMPEG", ffmpeg_libs, ffmpeg_libs, ("libavformat/avformat.h", "libavcodec/avcodec.h", "libavutil/avutil.h")) SmartPkgEnable("SWSCALE", "libswscale", "libswscale", ("libswscale/swscale.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg") SmartPkgEnable("SWRESAMPLE","libswresample", "libswresample", ("libswresample/swresample.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg") From 8ba6a0d844ead43032cd917c639ffd4fe51eb68a Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 19 Feb 2019 21:23:37 +0100 Subject: [PATCH 111/144] assimp: don't reuse Importer object when loading multiple models This works around a crash in v4.1.0 when loading multiple .ply files in sequence. (I have not reproduced the crash with the latest Assimp master.) --- pandatool/src/assimp/loaderFileTypeAssimp.cxx | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/pandatool/src/assimp/loaderFileTypeAssimp.cxx b/pandatool/src/assimp/loaderFileTypeAssimp.cxx index 73c27ee7d4..bd2eb19d53 100644 --- a/pandatool/src/assimp/loaderFileTypeAssimp.cxx +++ b/pandatool/src/assimp/loaderFileTypeAssimp.cxx @@ -15,6 +15,8 @@ #include "config_assimp.h" #include "assimpLoader.h" +#include + using std::string; TypeHandle LoaderFileTypeAssimp::_type_handle; @@ -23,7 +25,7 @@ TypeHandle LoaderFileTypeAssimp::_type_handle; * */ LoaderFileTypeAssimp:: -LoaderFileTypeAssimp() : _loader(new AssimpLoader) { +LoaderFileTypeAssimp() : _loader(nullptr) { } /** @@ -31,9 +33,6 @@ LoaderFileTypeAssimp() : _loader(new AssimpLoader) { */ LoaderFileTypeAssimp:: ~LoaderFileTypeAssimp() { - if (_loader != nullptr) { - delete _loader; - } } /** @@ -58,9 +57,22 @@ get_extension() const { */ string LoaderFileTypeAssimp:: get_additional_extensions() const { - string exts; - _loader->get_extensions(exts); - return exts; + aiString aexts; + aiGetExtensionList(&aexts); + + // The format is like: *.mdc;*.mdl;*.mesh.xml;*.mot + std::string ext; + char *sub = strtok(aexts.data, ";"); + while (sub != nullptr) { + ext += sub + 2; + sub = strtok(nullptr, ";"); + + if (sub != nullptr) { + ext += ' '; + } + } + + return ext; } /** @@ -82,10 +94,13 @@ load_file(const Filename &path, const LoaderOptions &options, assimp_cat.info() << "Reading " << path << "\n"; - if (!_loader->read(path)) { + AssimpLoader loader; + loader.local_object(); + + if (!loader.read(path)) { return nullptr; } - _loader->build_graph(); - return DCAST(PandaNode, _loader->_root); + loader.build_graph(); + return DCAST(PandaNode, loader._root); } From 1f9b4690e68aeaa1580541e02fc3b3e5ee838b38 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 19 Feb 2019 21:29:21 +0100 Subject: [PATCH 112/144] pgraph: fix writing to SequenceNode frame_rate property --- panda/src/pgraphnodes/sequenceNode.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/panda/src/pgraphnodes/sequenceNode.h b/panda/src/pgraphnodes/sequenceNode.h index db511dd4ae..96b7698131 100644 --- a/panda/src/pgraphnodes/sequenceNode.h +++ b/panda/src/pgraphnodes/sequenceNode.h @@ -35,6 +35,8 @@ PUBLISHED: virtual int get_num_frames() const; INLINE void set_frame_rate(double frame_rate); + MAKE_PROPERTY(frame_rate, get_frame_rate, set_frame_rate); + public: virtual PandaNode *make_copy() const; virtual bool safe_to_combine() const; From 78425b245e9e0747eaa7905e1bc5fb73ea9126bc Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 19 Feb 2019 21:48:05 +0100 Subject: [PATCH 113/144] pgraph: fix shadow buffer leak when light passed via shader input This is an extension of the fix in 9a40febdb9ce40a0936d164a2ed3d72ddf7dcc8a, but that only applied when the light was passed to the shader via LightAttrib, and not via shader inputs. ParamNodePath is not the ideal place to put this, but it's convenient (and probably more efficient than putting it into ShaderAttrib). --- panda/src/pgraph/paramNodePath.I | 18 ------------ panda/src/pgraph/paramNodePath.cxx | 47 ++++++++++++++++++++++++++++++ panda/src/pgraph/paramNodePath.h | 4 +-- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/panda/src/pgraph/paramNodePath.I b/panda/src/pgraph/paramNodePath.I index 354a2af7ec..67a9d24ea6 100644 --- a/panda/src/pgraph/paramNodePath.I +++ b/panda/src/pgraph/paramNodePath.I @@ -11,24 +11,6 @@ * @date 2015-02-25 */ -/** - * Creates a new ParamNodePath storing the given node path object. - */ -INLINE ParamNodePath:: -ParamNodePath(const NodePath &node_path) : - _node_path(node_path) -{ -} - -/** - * Creates a new ParamNodePath storing the given node path object. - */ -INLINE ParamNodePath:: -ParamNodePath(NodePath &&node_path) noexcept : - _node_path(std::move(node_path)) -{ -} - /** * Returns NodePath::get_class_type(). */ diff --git a/panda/src/pgraph/paramNodePath.cxx b/panda/src/pgraph/paramNodePath.cxx index 72a3563b22..45bfe0c12f 100644 --- a/panda/src/pgraph/paramNodePath.cxx +++ b/panda/src/pgraph/paramNodePath.cxx @@ -14,9 +14,41 @@ #include "paramNodePath.h" #include "dcast.h" #include "pandaNode.h" +#include "light.h" TypeHandle ParamNodePath::_type_handle; +/** + * Creates a new ParamNodePath storing the given node path object. + */ +ParamNodePath:: +ParamNodePath(NodePath node_path) : + _node_path(std::move(node_path)) +{ + // The reason to construct a ParamNodePath is often to apply a light to a + // shader input, so we want to keep track of the fact that the light is in + // use. + if (!_node_path.is_empty()) { + Light *light = _node_path.node()->as_light(); + if (light != nullptr) { + light->attrib_ref(); + } + } +} + +/** + * + */ +ParamNodePath:: +~ParamNodePath() { + if (!_node_path.is_empty()) { + Light *light = _node_path.node()->as_light(); + if (light != nullptr) { + light->attrib_unref(); + } + } +} + /** * */ @@ -68,6 +100,13 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { _node_path = NodePath(DCAST(PandaNode, p_list[pi++])); } + if (!_node_path.is_empty()) { + Light *light = _node_path.node()->as_light(); + if (light != nullptr) { + light->attrib_ref(); + } + } + return pi; } @@ -96,6 +135,14 @@ void ParamNodePath:: fillin(DatagramIterator &scan, BamReader *manager) { ParamValueBase::fillin(scan, manager); + if (!_node_path.is_empty()) { + Light *light = _node_path.node()->as_light(); + if (light != nullptr) { + light->attrib_unref(); + } + _node_path.clear(); + } + if (manager->get_file_minor_ver() >= 40) { _node_path.fillin(scan, manager); } else { diff --git a/panda/src/pgraph/paramNodePath.h b/panda/src/pgraph/paramNodePath.h index daab53e41e..63798cc4a8 100644 --- a/panda/src/pgraph/paramNodePath.h +++ b/panda/src/pgraph/paramNodePath.h @@ -26,8 +26,8 @@ protected: INLINE ParamNodePath() {}; PUBLISHED: - INLINE ParamNodePath(const NodePath &node_path); - INLINE ParamNodePath(NodePath &&node_path) noexcept; + ParamNodePath(NodePath node_path); + virtual ~ParamNodePath(); INLINE virtual TypeHandle get_value_type() const; INLINE NodePath get_value() const; From d11d4e0d85a18597811d18ea33a250d2f7bf6c7f Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 19 Feb 2019 21:59:04 +0100 Subject: [PATCH 114/144] display: don't render shadow cameras whose frusta are out of view This is done by collecting bounding volumes for each camera in a scene, and then only rendering a shadow camera if at least one of those bounding volumes overlaps with the shadow camera bounding volume. Closes #560 --- panda/src/display/graphicsEngine.cxx | 113 ++++++++++++++++++++------- panda/src/pgraph/cullTraverser.I | 2 + panda/src/pgraph/cullTraverser.cxx | 2 + panda/src/pgraph/sceneSetup.I | 17 ++++ panda/src/pgraph/sceneSetup.h | 5 ++ 5 files changed, 112 insertions(+), 27 deletions(-) diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 80973ae071..671f12c6aa 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -48,6 +48,7 @@ #include "displayRegionDrawCallbackData.h" #include "callbackGraphicsWindow.h" #include "depthTestAttrib.h" +#include "unionBoundingVolume.h" #if defined(WIN32) #define WINDOWS_LEAN_AND_MEAN @@ -1308,32 +1309,6 @@ do_cull(CullHandler *cull_handler, SceneSetup *scene_setup, CullTraverser *trav = dr->get_cull_traverser(); trav->set_cull_handler(cull_handler); trav->set_scene(scene_setup, gsg, dr->get_incomplete_render()); - - trav->set_view_frustum(nullptr); - if (view_frustum_cull) { - // If we're to be performing view-frustum culling, determine the bounding - // volume associated with the current viewing frustum. - - // First, we have to get the current viewing frustum, which comes from the - // lens. - PT(BoundingVolume) bv = scene_setup->get_cull_bounds(); - - if (bv != nullptr && !bv->is_infinite() && - bv->as_geometric_bounding_volume() != nullptr) { - // Transform it into the appropriate coordinate space. - PT(GeometricBoundingVolume) local_frustum; - local_frustum = bv->make_copy()->as_geometric_bounding_volume(); - nassertv(!local_frustum.is_null()); - - NodePath scene_parent = scene_setup->get_scene_root().get_parent(current_thread); - CPT(TransformState) cull_center_transform = - scene_setup->get_cull_center().get_transform(scene_parent, current_thread); - local_frustum->xform(cull_center_transform->get_mat()); - - trav->set_view_frustum(local_frustum); - } - } - trav->traverse(scene_setup->get_scene_root()); trav->end_traverse(); } @@ -1545,6 +1520,11 @@ cull_to_bins(GraphicsEngine::Windows wlist, Thread *current_thread) { typedef pmap AlreadyCulled; AlreadyCulled already_culled; + // We cull shadow passes last; whether we cull them depends on whether their + // respective frusta are in view of a "normal" camera. + pvector shadow_passes; + pmap non_shadow_bounds; + size_t wlist_size = wlist.size(); for (size_t wi = 0; wi < wlist_size; ++wi) { GraphicsOutput *win = wlist[wi]; @@ -1571,6 +1551,27 @@ cull_to_bins(GraphicsEngine::Windows wlist, Thread *current_thread) { key._lens_index = dr_reader.get_lens_index(); } + // If this is a shadow pass, postpone culling it until we've culled + // all the other passes, and collected their bounding volumes. + Light *light = nullptr; + if (!key._camera.is_empty()) { + light = key._camera.node()->as_light(); + } + if (light != nullptr) { + shadow_passes.push_back(std::move(scene_setup)); + continue; + } + else if (!shadow_passes.empty()) { + NodePath scene_root = scene_setup->get_scene_root(); + const GeometricBoundingVolume *gbv = scene_setup->get_view_frustum(); + UnionBoundingVolume &bounds = non_shadow_bounds[scene_root]; + if (gbv == nullptr || gbv->is_infinite()) { + bounds.set_infinite(); + } else { + bounds.add_component(gbv); + } + } + AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(std::move(key), nullptr)).first; if ((*aci).second == nullptr) { // We have not used this camera already in this thread. Perform @@ -1597,11 +1598,46 @@ cull_to_bins(GraphicsEngine::Windows wlist, Thread *current_thread) { } // Save the results for next frame. - dr->set_cull_result(std::move(cull_result), MOVE(scene_setup), current_thread); + dr->set_cull_result(std::move(cull_result), std::move(scene_setup), current_thread); } } } } + + // Now cull all the shadow passes if their cull bounds are in view. + // We don't bother checking the AlreadyCulled list, because we know there is + // only one output per GSG+light combination. + for (PT(SceneSetup) &scene_setup : shadow_passes) { + DisplayRegion *dr = scene_setup->get_display_region(); + GraphicsOutput *win = dr->get_window(); + PStatTimer timer(win->get_cull_window_pcollector(), current_thread); + + PT(CullResult) cull_result; + + // Are the cull bounds in view of another camera? + GeometricBoundingVolume *frustum = scene_setup->get_view_frustum(); + if (frustum == nullptr || + non_shadow_bounds[scene_setup->get_scene_root()].contains(frustum)) { + GraphicsStateGuardian *gsg = win->get_gsg(); + cull_result = dr->get_cull_result(current_thread); + if (cull_result != nullptr) { + cull_result = cull_result->make_next(); + } else { + // This DisplayRegion has no cull results; draw it. + cull_result = new CullResult(gsg, dr->get_draw_region_pcollector()); + } + cull_to_bins(win, gsg, dr, scene_setup, cull_result, current_thread); + } + else if (display_cat.is_spam()) { + display_cat.spam() + << *scene_setup->get_camera_node() + << " frustum is not in view, skipping shadow pass\n"; + } + + // Even save the results if null, to tell the draw pass that we don't want + // to draw this at all. + dr->set_cull_result(std::move(cull_result), std::move(scene_setup), current_thread); + } } /** @@ -2008,6 +2044,29 @@ setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) { CPT(TransformState) cs_world_transform = cs_transform->compose(world_transform); scene_setup->set_cs_world_transform(cs_world_transform); + if (view_frustum_cull) { + // If we're to be performing view-frustum culling, determine the bounding + // volume associated with the current viewing frustum. + + // First, we have to get the current viewing frustum, which comes from the + // lens. + PT(BoundingVolume) bv = scene_setup->get_cull_bounds(); + + if (bv != nullptr && !bv->is_infinite() && + bv->as_geometric_bounding_volume() != nullptr) { + // Transform it into the appropriate coordinate space. + PT(GeometricBoundingVolume) local_frustum; + local_frustum = bv->make_copy()->as_geometric_bounding_volume(); + nassertr(!local_frustum.is_null(), nullptr); + + CPT(TransformState) cull_center_transform = + scene_setup->get_cull_center().get_transform(scene_parent, current_thread); + local_frustum->xform(cull_center_transform->get_mat()); + + scene_setup->set_view_frustum(local_frustum); + } + } + return scene_setup; } diff --git a/panda/src/pgraph/cullTraverser.I b/panda/src/pgraph/cullTraverser.I index bb7bb35e36..98bc781b50 100644 --- a/panda/src/pgraph/cullTraverser.I +++ b/panda/src/pgraph/cullTraverser.I @@ -116,6 +116,8 @@ get_camera_mask() const { /** * Specifies the bounding volume that corresponds to the view frustum. Any * primitives that fall entirely outside of this volume are not drawn. + * + * Nowadays, this gets set automatically by set_scene(). */ INLINE void CullTraverser:: set_view_frustum(GeometricBoundingVolume *view_frustum) { diff --git a/panda/src/pgraph/cullTraverser.cxx b/panda/src/pgraph/cullTraverser.cxx index 0ecf27666a..ae0b7e8014 100644 --- a/panda/src/pgraph/cullTraverser.cxx +++ b/panda/src/pgraph/cullTraverser.cxx @@ -97,6 +97,8 @@ set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg, _camera_mask = camera->get_camera_mask(); _effective_incomplete_render = _gsg->get_incomplete_render() && dr_incomplete_render; + + _view_frustum = scene_setup->get_view_frustum(); } /** diff --git a/panda/src/pgraph/sceneSetup.I b/panda/src/pgraph/sceneSetup.I index cf420ee132..a81271cd02 100644 --- a/panda/src/pgraph/sceneSetup.I +++ b/panda/src/pgraph/sceneSetup.I @@ -182,6 +182,23 @@ get_cull_bounds() const { return _lens->make_bounds(); } +/** + * Returns the camera's cull bounds transformed to world space, or null if + * view frustum culling is disabled. + */ +INLINE void SceneSetup:: +set_view_frustum(PT(GeometricBoundingVolume) view_frustum) { + _view_frustum = std::move(view_frustum); +} + +/** + * Returns the initial state as set by a previous call to set_initial_state(). + */ +INLINE GeometricBoundingVolume *SceneSetup:: +get_view_frustum() const { + return _view_frustum; +} + /** * Sets the initial state which is applied to all nodes in the scene, as if it * were set at the top of the scene graph. diff --git a/panda/src/pgraph/sceneSetup.h b/panda/src/pgraph/sceneSetup.h index d2ad0c0edb..b6622eaee7 100644 --- a/panda/src/pgraph/sceneSetup.h +++ b/panda/src/pgraph/sceneSetup.h @@ -22,6 +22,7 @@ #include "transformState.h" #include "lens.h" #include "pointerTo.h" +#include "geometricBoundingVolume.h" class DisplayRegion; @@ -59,6 +60,9 @@ PUBLISHED: INLINE const NodePath &get_cull_center() const; INLINE PT(BoundingVolume) get_cull_bounds() const; + INLINE void set_view_frustum(PT(GeometricBoundingVolume) view_frustum); + INLINE GeometricBoundingVolume *get_view_frustum() const; + INLINE void set_initial_state(const RenderState *initial_state); INLINE const RenderState *get_initial_state() const; @@ -88,6 +92,7 @@ private: CPT(TransformState) _world_transform; CPT(TransformState) _cs_transform; CPT(TransformState) _cs_world_transform; + PT(GeometricBoundingVolume) _view_frustum; public: static TypeHandle get_class_type() { From 73873ba76781a03c0a283147ba5cd844482804fe Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 20 Feb 2019 23:11:02 +0100 Subject: [PATCH 115/144] direct: remove obsolete FindCtaPaths module --- direct/src/showbase/FindCtaPaths.py | 100 ---------------------------- makepanda/test_imports.py | 1 - 2 files changed, 101 deletions(-) delete mode 100755 direct/src/showbase/FindCtaPaths.py diff --git a/direct/src/showbase/FindCtaPaths.py b/direct/src/showbase/FindCtaPaths.py deleted file mode 100755 index 038257f5c6..0000000000 --- a/direct/src/showbase/FindCtaPaths.py +++ /dev/null @@ -1,100 +0,0 @@ -"""This module is used only by the VR Studio programmers who are using -the ctattach tools. It is imported before any other package, and its -job is to figure out the correct paths to each of the packages. - -This module is not needed if you are not using ctattach; in this case -all of the Panda packages will be collected under a common directory, -which you will presumably have already on your PYTHONPATH. """ - -__all__ = ['deCygwinify', 'getPaths'] - -import os -import sys - -def deCygwinify(path): - if os.name in ['nt'] and path[0] == '/': - # On Windows, we may need to convert from a Cygwin-style path - # to a native Windows path. - - # Check for a case like /i/ or /p/: this converts - # to i:\ or p:\. - - dirs = path.split('/') - if len(dirs) > 2 and len(dirs[1]) == 1: - path = '%s:\\%s' % (dirs[1], '\\'.join(dirs[2:])) - - else: - # Otherwise, prepend $PANDA_ROOT and flip the slashes. - pandaRoot = os.getenv('PANDA_ROOT') - if pandaRoot: - path = os.path.normpath(pandaRoot + path) - - return path - -def getPaths(): - """ - Add to sys.path the appropriate director(ies) to search for the - various Panda projects. Typically, these will all be in the same - directory (which is presumably already on sys.path), but if the VR - Studio ctattach tools are in use they could be scattered around in - several places. - """ - - ctprojs = os.getenv("CTPROJS") - if ctprojs: - # The CTPROJS environment variable is defined. We must be - # using the ctattach tools. In this case, we need to figure - # out the location of each of the separate trees, and put the - # parent directory of each one on sys.path. In many cases, - # these will all be siblings, so we filter out duplicate - # parent directories. - - print('Appending to sys.path based on $CTPROJS:') - - # First, get the list of packages, then reverse the list to - # put it in ctattach order. (The reversal may not matter too - # much these days, but let's be as correct as we can be.) - packages = [] - for proj in ctprojs.split(): - projName = proj.split(':')[0] - packages.append(projName) - packages.reverse() - - # Now walk through the packages and figure out the parent of - # each referenced directory. - - parents = [] - for package in packages: - tree = os.getenv(package) - if not tree: - print(" CTPROJS contains %s, but $%s is not defined." % (package, package)) - sys.exit(1) - - tree = deCygwinify(tree) - - parent, base = os.path.split(tree) - if base != package.lower(): - print(" Warning: $%s refers to a directory named %s (instead of %s)" % (package, base, package.lower())) - - if parent not in parents: - parents.append(parent) - - - # We also put tree/built/lib on sys.path by hand, because we - # will need to load up the generated C++ modules that got - # put there. Also, we will find the output of genPyCode - # in $DIRECT/built/lib/pandac. - libdir = os.path.join(tree, 'built', 'lib') - if os.path.isdir(libdir): - if libdir not in sys.path: - sys.path.append(libdir) - - - # Now the result goes onto sys.path. - for parent in parents: - print(" %s" % (parent)) - if parent not in sys.path: - sys.path.append(parent) - - -getPaths() diff --git a/makepanda/test_imports.py b/makepanda/test_imports.py index a9b22943c8..dd7fb5ad23 100644 --- a/makepanda/test_imports.py +++ b/makepanda/test_imports.py @@ -200,7 +200,6 @@ import direct.showbase.EventManager import direct.showbase.EventManagerGlobal import direct.showbase.ExceptionVarDump import direct.showbase.Factory -import direct.showbase.FindCtaPaths import direct.showbase.Finder import direct.showbase.GarbageReport import direct.showbase.GarbageReportScheduler From 92e8b77344229d1393ce8844dcf8a19767e76ea2 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 20 Feb 2019 23:12:06 +0100 Subject: [PATCH 116/144] assimp: remove no longer used AssimpLoader pointer --- pandatool/src/assimp/loaderFileTypeAssimp.cxx | 2 +- pandatool/src/assimp/loaderFileTypeAssimp.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/pandatool/src/assimp/loaderFileTypeAssimp.cxx b/pandatool/src/assimp/loaderFileTypeAssimp.cxx index bd2eb19d53..f19ce58e2f 100644 --- a/pandatool/src/assimp/loaderFileTypeAssimp.cxx +++ b/pandatool/src/assimp/loaderFileTypeAssimp.cxx @@ -25,7 +25,7 @@ TypeHandle LoaderFileTypeAssimp::_type_handle; * */ LoaderFileTypeAssimp:: -LoaderFileTypeAssimp() : _loader(nullptr) { +LoaderFileTypeAssimp() { } /** diff --git a/pandatool/src/assimp/loaderFileTypeAssimp.h b/pandatool/src/assimp/loaderFileTypeAssimp.h index 45d810f964..033ab9affa 100644 --- a/pandatool/src/assimp/loaderFileTypeAssimp.h +++ b/pandatool/src/assimp/loaderFileTypeAssimp.h @@ -36,9 +36,6 @@ public: virtual PT(PandaNode) load_file(const Filename &path, const LoaderOptions &options, BamCacheRecord *record) const; -public: - AssimpLoader *_loader; - public: static TypeHandle get_class_type() { return _type_handle; From a7c8827ddee0d40a605edd4d85fb3b1f55ec01b1 Mon Sep 17 00:00:00 2001 From: Younguk Kim Date: Thu, 28 Feb 2019 11:29:34 +0900 Subject: [PATCH 117/144] makepanda: add support for Visual Studio 2019 Closes #570 --- makepanda/makepanda.py | 2 +- makepanda/makepandacore.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 3341262452..05d639e7d1 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -159,7 +159,7 @@ def usage(problem): print(" --everything (enable every third-party lib)") print(" --directx-sdk=X (specify version of DirectX SDK to use: jun2010, aug2009, mar2009, aug2006)") print(" --windows-sdk=X (specify Windows SDK version, eg. 7.0, 7.1 or 10. Default is 7.1)") - print(" --msvc-version=X (specify Visual C++ version, eg. 10, 11, 12, 14. Default is 14)") + print(" --msvc-version=X (specify Visual C++ version, eg. 10, 11, 12, 14, 14.1, 14.2. Default is 14)") print(" --use-icl (experimental setting to use an intel compiler instead of MSVC on Windows)") print("") print("The simplest way to compile panda is to just type:") diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 74ce108adf..386570a0d8 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -78,6 +78,7 @@ MSVCVERSIONINFO = { (12,0): {"vsversion":(12,0), "vsname":"Visual Studio 2013"}, (14,0): {"vsversion":(14,0), "vsname":"Visual Studio 2015"}, (14,1): {"vsversion":(15,0), "vsname":"Visual Studio 2017"}, + (14,2): {"vsversion":(16,0), "vsname":"Visual Studio 2019"}, } ######################################################################## From 63fa340a51ae5d1f39b0bab903bf0a620ff63476 Mon Sep 17 00:00:00 2001 From: typewriter1 <40742741+typewriter1@users.noreply.github.com> Date: Mon, 25 Feb 2019 17:53:13 +0000 Subject: [PATCH 118/144] readme: Update download link for SDK to 1.10.1 Closes #566 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c4757d577..4d26a0a778 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Installing Panda3D ================== The latest Panda3D SDK can be downloaded from -[this page](https://www.panda3d.org/download/sdk-1-10-0/). +[this page](https://www.panda3d.org/download/sdk-1-10-1/). If you are familiar with installing Python packages, you can use the following comand: From 7f4491cb9887a2fa021059b922c4032f460aca82 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 2 Mar 2019 12:39:42 +0100 Subject: [PATCH 119/144] device: disable message loop in WinInputDeviceManager for now This was a change in aadc62a96c18d9911428da041e611f8c3b01a444 but seems to cause other problems, see #562 --- panda/src/device/winInputDeviceManager.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/panda/src/device/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index 515dc376d8..c989b0964c 100644 --- a/panda/src/device/winInputDeviceManager.cxx +++ b/panda/src/device/winInputDeviceManager.cxx @@ -397,11 +397,13 @@ on_input_device_removal(HANDLE handle) { */ void WinInputDeviceManager:: update() { + /* MSG msg; while (PeekMessage(&msg, _message_hwnd, WM_INPUT_DEVICE_CHANGE, WM_INPUT, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } + */ } /** From fa6c066b2f21856036cb24d482a7152406c6c2e2 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 3 Mar 2019 10:29:39 +0100 Subject: [PATCH 120/144] interrogate: enable true division in Python 2 as well This allows using "from __future__ import division" and get the expected result for divisions in Python 2. Fixes #529 --- dtool/src/interrogate/interfaceMakerPythonNative.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 5f351dbbc1..4d606c65d9 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -1690,7 +1690,6 @@ write_module_class(ostream &out, Object *obj) { SlottedFunctionDef def; def._answer_location = true_key; def._wrapper_type = slotted_def._wrapper_type; - def._min_version = 0x03000000; def._wrapper_name = func->_name + "_" + true_key; slots[true_key] = def; } From 92993fe8891257aed9d12967bd0fff0af03adfc4 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 3 Mar 2019 21:13:36 +0100 Subject: [PATCH 121/144] bullet: fix assert when setting mass before shape (#571) Requires compiling Bullet in debug mode to reproduce. --- panda/src/bullet/bulletRigidBodyNode.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/bullet/bulletRigidBodyNode.cxx b/panda/src/bullet/bulletRigidBodyNode.cxx index 6f5bff0d46..b97f768d1b 100644 --- a/panda/src/bullet/bulletRigidBodyNode.cxx +++ b/panda/src/bullet/bulletRigidBodyNode.cxx @@ -120,7 +120,7 @@ do_set_mass(PN_stdfloat mass) { btScalar bt_mass = mass; btVector3 bt_inertia(0.0, 0.0, 0.0); - if (bt_mass > 0.0) { + if (bt_mass > 0.0 && !_shapes.empty()) { _rigid->getCollisionShape()->calculateLocalInertia(bt_mass, bt_inertia); } From 155b1c38ade5b62872b4a60a1f27bb2e858a122e Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 3 Mar 2019 21:14:18 +0100 Subject: [PATCH 122/144] bullet: properly expose bullet_contact_added_callback symbol Fixes #571 (alongside 92993fe8891257aed9d12967bd0fff0af03adfc4) --- panda/src/bullet/bulletWorld.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/bullet/bulletWorld.h b/panda/src/bullet/bulletWorld.h index 9c709c1e91..67607923dd 100644 --- a/panda/src/bullet/bulletWorld.h +++ b/panda/src/bullet/bulletWorld.h @@ -43,7 +43,7 @@ class BulletPersistentManifold; class BulletShape; class BulletSoftBodyWorldInfo; -extern PT(CallbackObject) bullet_contact_added_callback; +extern EXPCL_PANDABULLET PT(CallbackObject) bullet_contact_added_callback; /** * From c337e58f4dbc02fb7bb1b60c7525c0ef518cee3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Derzsi=20D=C3=A1niel?= Date: Mon, 4 Mar 2019 00:21:23 +0200 Subject: [PATCH 123/144] direct: Resolve DirectScrolledFrame crash on destroy Destroying DirectScrolledFrames currently crashes the game, because they are destroyed twice. This commit makes sure to destroy the scrolls only once. Closes #574 --- direct/src/gui/DirectScrolledFrame.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/direct/src/gui/DirectScrolledFrame.py b/direct/src/gui/DirectScrolledFrame.py index c44bc7a0fb..d5274de6fe 100644 --- a/direct/src/gui/DirectScrolledFrame.py +++ b/direct/src/gui/DirectScrolledFrame.py @@ -100,8 +100,10 @@ class DirectScrolledFrame(DirectFrame): simpleChildGui = self.guiDict.get(parts[-1]) if simpleChildGui: simpleChildGui.destroy() - self.verticalScroll.destroy() - self.horizontalScroll.destroy() - del self.verticalScroll - del self.horizontalScroll + if self.verticalScroll: + self.verticalScroll.destroy() + if self.horizontalScroll: + self.horizontalScroll.destroy() + self.verticalScroll = None + self.horizontalScroll = None DirectFrame.destroy(self) From 58df4064dab3605838117542b1716e4757a7e02a Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Mar 2019 14:23:11 +0100 Subject: [PATCH 124/144] ParticlePanel: fix Pmw error spam when hovering over File menu items Fixes #552 --- direct/src/tkpanels/ParticlePanel.py | 31 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/direct/src/tkpanels/ParticlePanel.py b/direct/src/tkpanels/ParticlePanel.py index 9c4ba56a79..47faa71cb6 100644 --- a/direct/src/tkpanels/ParticlePanel.py +++ b/direct/src/tkpanels/ParticlePanel.py @@ -96,22 +96,21 @@ class ParticlePanel(AppShell): ## MENUBAR ENTRIES ## # FILE MENU - # Get a handle on the file menu so commands can be inserted - # before quit item - fileMenu = self.menuBar.component('File-menu') - # MRM: Need to add load and save effects methods - fileMenu.insert_command( - fileMenu.index('Quit'), - label = 'Load Params', - command = self.loadParticleEffectFromFile) - fileMenu.insert_command( - fileMenu.index('Quit'), - label = 'Save Params', - command = self.saveParticleEffectToFile) - fileMenu.insert_command( - fileMenu.index('Quit'), - label = 'Print Params', - command = lambda s = self: s.particles.printParams()) + # Get a handle on the file menu, and delete the Quit item that AppShell + # created so we can add it back after adding the other items. + self.menuBar.deletemenuitems('File', 0, 0) + self.menuBar.addmenuitem('File', 'command', + label='Load Params', + command=self.loadParticleEffectFromFile) + self.menuBar.addmenuitem('File', 'command', + label='Save Params', + command=self.saveParticleEffectToFile) + self.menuBar.addmenuitem('File', 'command', + label='Print Params', + command=lambda s=self:s.particles.printParams()) + self.menuBar.addmenuitem('File', 'command', 'Quit this application', + label='Quit', + command=self.quit) # PARTICLE MANAGER MENU self.menuBar.addmenu('ParticleMgr', 'ParticleMgr Operations') From 45778b9e9fbf37719964298ae8acb552a86bb135 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Mar 2019 16:19:19 +0100 Subject: [PATCH 125/144] device: use threaded message loop on Windows (see #562) --- panda/src/device/winInputDeviceManager.cxx | 260 ++++++++++++++------- panda/src/device/winInputDeviceManager.h | 3 + 2 files changed, 177 insertions(+), 86 deletions(-) diff --git a/panda/src/device/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index c989b0964c..232c612186 100644 --- a/panda/src/device/winInputDeviceManager.cxx +++ b/panda/src/device/winInputDeviceManager.cxx @@ -17,6 +17,22 @@ #if defined(_WIN32) && !defined(CPPPARSER) +#ifdef HAVE_THREADS +/** + * + */ +class InputThread : public Thread { +public: + InputThread(WinInputDeviceManager *manager) : + Thread("input", "input"), _manager(manager) {} + +private: + virtual void thread_main(); + + WinInputDeviceManager *_manager; +}; +#endif + /** * Initializes the input device manager by scanning which devices are currently * connected and setting up any platform-dependent structures necessary for @@ -37,7 +53,7 @@ WinInputDeviceManager() : _xinput_device2.local_object(); _xinput_device3.local_object(); -// This function is only available in Vista and later, so we use a wrapper. + // This function is only available in Vista and later, so we use a wrapper. HMODULE module = LoadLibraryA("cfgmgr32.dll"); if (module) { _CM_Get_DevNode_PropertyW = (pCM_Get_DevNode_Property)GetProcAddress(module, "CM_Get_DevNode_PropertyW"); @@ -45,83 +61,16 @@ WinInputDeviceManager() : _CM_Get_DevNode_PropertyW = nullptr; } - // Now create a message-only window for the raw input. - WNDCLASSEX wc = {}; - wc.cbSize = sizeof(WNDCLASSEX); - wc.lpfnWndProc = window_proc; - wc.hInstance = GetModuleHandle(nullptr); - wc.lpszClassName = "InputDeviceManager"; - if (!RegisterClassEx(&wc)) { - device_cat.warning() - << "Failed to register message-only window class.\n"; - return; - } - - _message_hwnd = CreateWindowEx(0, wc.lpszClassName, "InputDeviceManager", 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr); - if (!_message_hwnd) { - device_cat.warning() - << "Failed to create message-only window.\n"; - return; - } - - // Now listen for raw input devices using the created message loop. - RAWINPUTDEVICE rid[3]; - rid[0].usUsagePage = 1; - rid[0].usUsage = 4; // Joysticks - rid[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; - rid[0].hwndTarget = _message_hwnd; - rid[1].usUsagePage = 1; - rid[1].usUsage = 5; // Gamepads - rid[1].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; - rid[1].hwndTarget = _message_hwnd; - rid[2].usUsagePage = 1; - rid[2].usUsage = 8; // Multi-axis controllers (including 3D mice) - rid[2].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; - rid[2].hwndTarget = _message_hwnd; - if (!RegisterRawInputDevices(rid, 3, sizeof(RAWINPUTDEVICE))) { - device_cat.warning() - << "Failed to register raw input devices.\n"; - } - - // Do we have any XInput devices plugged in now? - int num_xinput = 0; - HANDLE xinput_handle; - RAWINPUTDEVICELIST devices[64]; - UINT num_devices = 64; - num_devices = GetRawInputDeviceList(devices, &num_devices, sizeof(RAWINPUTDEVICELIST)); - if (num_devices == (UINT)-1) { - return; - } - for (UINT i = 0; i < num_devices; ++i) { - if (devices[i].dwType != RIM_TYPEHID) { - continue; - } - HANDLE handle = devices[i].hDevice; - UINT size; - if (GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, nullptr, &size) != 0) { - continue; - } - - char *path = (char *)alloca(size); - if (path == nullptr || - GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, (void *)path, &size) < 0) { - continue; - } - - if (strstr(path, "&IG_") != nullptr) { - xinput_handle = handle; - ++num_xinput; - } - } - if (num_xinput == 1) { - // There's only one XInput device, so we know which one it is. - on_input_device_arrival(xinput_handle); - } else if (num_xinput > 0) { - // Just poll all the XInput devices. - _xinput_device0.detect(this); - _xinput_device1.detect(this); - _xinput_device2.detect(this); - _xinput_device3.detect(this); + // If we have threading enabled, start a thread with a message-only window + // loop to listen for input events. +#ifdef HAVE_THREADS + if (Thread::is_threading_supported()) { + PT(Thread) thread = new InputThread(this); + thread->start(TP_normal, false); + } else +#endif + { + setup_message_loop(); } } @@ -131,8 +80,17 @@ WinInputDeviceManager() : WinInputDeviceManager:: ~WinInputDeviceManager() { if (_message_hwnd != nullptr) { - DestroyWindow(_message_hwnd); - _message_hwnd = nullptr; +#ifdef HAVE_THREADS + if (Thread::is_threading_supported()) { + HWND hwnd = _message_hwnd; + if (hwnd) { + SendMessage(hwnd, WM_QUIT, 0, 0); + } + } else +#endif + { + destroy_message_loop(); + } } } @@ -397,13 +355,111 @@ on_input_device_removal(HANDLE handle) { */ void WinInputDeviceManager:: update() { - /* - MSG msg; - while (PeekMessage(&msg, _message_hwnd, WM_INPUT_DEVICE_CHANGE, WM_INPUT, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); +} + +/** + * Sets up a Windows message loop. Should be called from the thread that will + * be handling the messages. + */ +HWND WinInputDeviceManager:: +setup_message_loop() { + _message_hwnd = 0; + + // Now create a message-only window for the raw input. + WNDCLASSEX wc = {}; + wc.cbSize = sizeof(WNDCLASSEX); + wc.lpfnWndProc = window_proc; + wc.hInstance = GetModuleHandle(nullptr); + wc.lpszClassName = "InputDeviceManager"; + if (!RegisterClassEx(&wc)) { + device_cat.warning() + << "Failed to register message-only window class for input device detection.\n"; + } else { + _message_hwnd = CreateWindowEx(0, wc.lpszClassName, "InputDeviceManager", 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr); + if (!_message_hwnd) { + device_cat.warning() + << "Failed to create message-only window for input device detection.\n"; + } + } + + // Now listen for raw input devices using the created message loop. + RAWINPUTDEVICE rid[3]; + rid[0].usUsagePage = 1; + rid[0].usUsage = 4; // Joysticks + rid[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; + rid[0].hwndTarget = _message_hwnd; + rid[1].usUsagePage = 1; + rid[1].usUsage = 5; // Gamepads + rid[1].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; + rid[1].hwndTarget = _message_hwnd; + rid[2].usUsagePage = 1; + rid[2].usUsage = 8; // Multi-axis controllers (including 3D mice) + rid[2].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; + rid[2].hwndTarget = _message_hwnd; + if (!RegisterRawInputDevices(rid, 3, sizeof(RAWINPUTDEVICE))) { + device_cat.warning() + << "Failed to register raw input devices.\n"; + } + + // Do we have any XInput devices plugged in now? + int num_xinput = 0; + HANDLE xinput_handle; + RAWINPUTDEVICELIST devices[64]; + UINT num_devices = 64; + num_devices = GetRawInputDeviceList(devices, &num_devices, sizeof(RAWINPUTDEVICELIST)); + if (num_devices == (UINT)-1) { + num_devices = 0; + } + for (UINT i = 0; i < num_devices; ++i) { + if (devices[i].dwType != RIM_TYPEHID) { + continue; + } + HANDLE handle = devices[i].hDevice; + UINT size; + if (GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, nullptr, &size) != 0) { + continue; + } + + char *path = (char *)alloca(size); + if (path == nullptr || + GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, (void *)path, &size) < 0) { + continue; + } + + if (strstr(path, "&IG_") != nullptr) { + xinput_handle = handle; + ++num_xinput; + } + } + if (num_xinput == 1) { + // There's only one XInput device, so we know which one it is. + on_input_device_arrival(xinput_handle); + } else if (num_xinput > 0) { + // Just poll all the XInput devices. + _xinput_device0.detect(this); + _xinput_device1.detect(this); + _xinput_device2.detect(this); + _xinput_device3.detect(this); + } + + return _message_hwnd; +} + +/** + * Tears down the message loop. Should be called from the thread that called + * setup_message_loop(). + */ +void WinInputDeviceManager:: +destroy_message_loop() { + HWND hwnd = nullptr; + { + LightMutexHolder holder(_lock); + std::swap(_message_hwnd, hwnd); + } + + if (hwnd) { + DestroyWindow(hwnd); } - */ } /** @@ -444,4 +500,36 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { return DefWindowProcW(hwnd, msg, wparam, lparam); } +#ifdef HAVE_THREADS +/** + * Thread entry point for the input listener thread. + */ +void InputThread:: +thread_main() { + WinInputDeviceManager *manager = _manager; + HWND hwnd = manager->setup_message_loop(); + if (!hwnd) { + return; + } + + if (device_cat.is_debug()) { + device_cat.debug() + << "Started input device listener thread.\n"; + } + + MSG msg; + while (GetMessage(&msg, nullptr, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (device_cat.is_debug()) { + device_cat.debug() + << "Stopping input device listener thread.\n"; + } + + manager->destroy_message_loop(); +} +#endif // HAVE_THREADS + #endif diff --git a/panda/src/device/winInputDeviceManager.h b/panda/src/device/winInputDeviceManager.h index e99a01f761..44eaa053dc 100644 --- a/panda/src/device/winInputDeviceManager.h +++ b/panda/src/device/winInputDeviceManager.h @@ -41,6 +41,9 @@ public: void on_input_device_arrival(HANDLE handle); void on_input_device_removal(HANDLE handle); + HWND setup_message_loop(); + void destroy_message_loop(); + private: // There are always exactly four of these in existence. XInputDevice _xinput_device0; From 8e4add0326292b398ef99f5c0f9033efdba21ff4 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Mar 2019 16:46:28 +0100 Subject: [PATCH 126/144] interrogate: fix refcount trouble assigning PyObject* properties In particular, this fixes accessing PythonTask.__dict__ --- dtool/src/interrogate/functionRemap.cxx | 19 ++++++++++++++++--- .../interfaceMakerPythonNative.cxx | 6 +++++- dtool/src/interrogatedb/py_panda.I | 13 +++++++++++++ dtool/src/interrogatedb/py_panda.h | 2 ++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/dtool/src/interrogate/functionRemap.cxx b/dtool/src/interrogate/functionRemap.cxx index fabbb8a311..d5d6ab643c 100644 --- a/dtool/src/interrogate/functionRemap.cxx +++ b/dtool/src/interrogate/functionRemap.cxx @@ -397,17 +397,25 @@ get_call_str(const string &container, const vector_string &pexprs) const { } // It's not possible to assign arrays in C++, we have to copy them. - CPPArrayType *array_type = _parameters[_first_true_parameter]._remap->get_orig_type()->as_array_type(); + bool paren_close = false; + CPPType *param_type = _parameters[_first_true_parameter]._remap->get_orig_type(); + CPPArrayType *array_type = param_type->as_array_type(); if (array_type != nullptr) { call << "std::copy(" << expr << ", " << expr << " + " << *array_type->_bounds << ", "; - } else { + paren_close = true; + } + else if (TypeManager::is_pointer_to_PyObject(param_type)) { + call << "Dtool_Assign_PyObject(" << expr << ", "; + paren_close = true; + } + else { call << expr << " = "; } _parameters[_first_true_parameter]._remap->pass_parameter(call, get_parameter_expr(_first_true_parameter, pexprs)); - if (array_type != nullptr) { + if (paren_close) { call << ')'; } @@ -772,6 +780,11 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak _return_value_destructor = builder.get_destructor_for(return_meat_type); } + if (_type == T_getter && TypeManager::is_pointer_to_PyObject(return_type)) { + _manage_reference_count = true; + _return_value_needs_management = true; + } + // Check for a special meaning by name and signature. size_t first_param = 0; if (_has_this) { diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 4d606c65d9..c617b6597e 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -5979,7 +5979,11 @@ write_function_instance(ostream &out, FunctionRemap *remap, indent(out, indent_level) << "}\n"; } - return_expr = manage_return_value(out, indent_level, remap, "return_value"); + if (TypeManager::is_pointer_to_PyObject(remap->_return_type->get_orig_type())) { + indent(out, indent_level) << "Py_XINCREF(return_value);\n"; + } else { + return_expr = manage_return_value(out, indent_level, remap, "return_value"); + } return_expr = remap->_return_type->temporary_to_return(return_expr); } diff --git a/dtool/src/interrogatedb/py_panda.I b/dtool/src/interrogatedb/py_panda.I index 12f20f1f1e..d6b95efe35 100644 --- a/dtool/src/interrogatedb/py_panda.I +++ b/dtool/src/interrogatedb/py_panda.I @@ -90,6 +90,19 @@ INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, i Py_RETURN_RICHCOMPARE(cmpval, 0, op); } +/** + * Utility function for assigning a PyObject pointer while managing refcounts. + */ +ALWAYS_INLINE void +Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value) { + PyObject *prev_value = ptr; + if (prev_value != value) { + Py_XINCREF(value); + ptr = value; + Py_XDECREF(prev_value); + } +} + /** * Converts the enum value to a C long. */ diff --git a/dtool/src/interrogatedb/py_panda.h b/dtool/src/interrogatedb/py_panda.h index 353af53608..026d1c6858 100644 --- a/dtool/src/interrogatedb/py_panda.h +++ b/dtool/src/interrogatedb/py_panda.h @@ -238,6 +238,8 @@ EXPCL_PYPANDA PyObject *_Dtool_Return(PyObject *value); #define Dtool_Return(value) _Dtool_Return(value) #endif +ALWAYS_INLINE void Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value); + /** * Wrapper around Python 3.4's enum library, which does not have a C API. */ From 0f5da1c155468ae097ebb7598bb7774c99ba5f44 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Mar 2019 16:58:18 +0100 Subject: [PATCH 127/144] dtoolbase: fix warning when compiling on Windows --- dtool/src/dtoolbase/mutexWin32Impl.I | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtool/src/dtoolbase/mutexWin32Impl.I b/dtool/src/dtoolbase/mutexWin32Impl.I index a0867d94fb..b61d314d61 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.I +++ b/dtool/src/dtoolbase/mutexWin32Impl.I @@ -36,7 +36,7 @@ lock() { */ INLINE bool MutexWin32Impl:: try_lock() { - return _funcs._try_lock(_lock); + return (_funcs._try_lock(_lock) != 0); } /** From 05eaf930b17aef35a3922e6f92a42320f8cf0447 Mon Sep 17 00:00:00 2001 From: Q Misell Date: Mon, 4 Mar 2019 17:01:38 +0100 Subject: [PATCH 128/144] bullet: make suspension rest length of vehicle adjustable Fixes #569 --- panda/src/bullet/bulletVehicle.cxx | 4 ++-- panda/src/bullet/bulletVehicle.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/panda/src/bullet/bulletVehicle.cxx b/panda/src/bullet/bulletVehicle.cxx index ba7ee35d6d..adb5d6c692 100644 --- a/panda/src/bullet/bulletVehicle.cxx +++ b/panda/src/bullet/bulletVehicle.cxx @@ -171,14 +171,14 @@ set_pitch_control(PN_stdfloat pitch) { * Factory method for creating wheels for this vehicle instance. */ BulletWheel BulletVehicle:: -create_wheel() { +create_wheel(PN_stdfloat suspension_rest_length) { LightMutexHolder holder(BulletWorld::get_global_lock()); btVector3 pos(0.0, 0.0, 0.0); btVector3 direction = get_axis(_vehicle->getUpAxis()); btVector3 axle = get_axis(_vehicle->getRightAxis()); - btScalar suspension(0.4); + btScalar suspension(suspension_rest_length); btScalar radius(0.3); btWheelInfo &info = _vehicle->addWheel(pos, direction, axle, suspension, radius, _tuning._, false); diff --git a/panda/src/bullet/bulletVehicle.h b/panda/src/bullet/bulletVehicle.h index 9f9da751c3..486e38a049 100644 --- a/panda/src/bullet/bulletVehicle.h +++ b/panda/src/bullet/bulletVehicle.h @@ -85,7 +85,7 @@ PUBLISHED: void apply_engine_force(PN_stdfloat force, int idx); // Wheels - BulletWheel create_wheel(); + BulletWheel create_wheel(PN_stdfloat suspension_rest_length=0.4); int get_num_wheels() const; BulletWheel get_wheel(int idx) const; From ba256a8b07b189f3f046c38110ba4ad7166b0ab0 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Mar 2019 22:51:20 +0100 Subject: [PATCH 129/144] interrogate: fix regression in 2c91fdda1b6630b3b1166bf99f8ad3cb6bd6baa9 --- dtool/src/interrogate/interfaceMakerPythonNative.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 0305384730..bfcac69506 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -1885,7 +1885,9 @@ write_module_class(ostream &out, Object *obj) { out << " Py_INCREF(Py_NotImplemented);\n"; out << " return Py_NotImplemented;\n"; } else if (all_nonconst) { - out << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; + out << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" + << ClassName << ", (void **)&local_this, \"" << ClassName + << "." << methodNameFromCppName(fname, "", false) << "\")) {\n"; out << " return nullptr;\n"; } else { out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; From 71b8bceb795ad796edfd8f341f7f4e4eaa9d4481 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Mar 2019 22:58:50 +0100 Subject: [PATCH 130/144] task: allow overriding methods of PythonTask --- panda/src/event/pythonTask.cxx | 51 ++++++++++++++++------------------ panda/src/event/pythonTask.h | 2 +- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/panda/src/event/pythonTask.cxx b/panda/src/event/pythonTask.cxx index 86200802a9..fdf6be440c 100644 --- a/panda/src/event/pythonTask.cxx +++ b/panda/src/event/pythonTask.cxx @@ -283,15 +283,25 @@ exception() const { */ int PythonTask:: __setattr__(PyObject *self, PyObject *attr, PyObject *v) { - if (PyObject_GenericSetAttr(self, attr, v) == 0) { - return 0; - } - - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { +#if PY_MAJOR_VERSION >= 3 + if (!PyUnicode_Check(attr)) { +#else + if (!PyString_Check(attr)) { +#endif + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", + attr->ob_type->tp_name); return -1; } - PyErr_Clear(); + PyObject *descr = _PyType_Lookup(Py_TYPE(self), attr); + if (descr != nullptr) { + Py_INCREF(descr); + descrsetfunc f = descr->ob_type->tp_descr_set; + if (f != nullptr) { + return f(descr, self, v); + } + } if (task_cat.is_debug()) { PyObject *str = PyObject_Repr(v); @@ -352,31 +362,18 @@ __delattr__(PyObject *self, PyObject *attr) { * object. */ PyObject *PythonTask:: -__getattr__(PyObject *attr) const { - // Note that with the new Interrogate behavior, this method behaves more - // like the Python __getattr__ rather than being directly assigned to the - // tp_getattro slot (a la __getattribute__). So, we won't get here when the - // attribute has already been found via other methods. - +__getattribute__(PyObject *self, PyObject *attr) const { + // We consult the instance dict first, since the user may have overridden a + // method or something. PyObject *item = PyDict_GetItem(__dict__, attr); - if (item == nullptr) { - // PyDict_GetItem does not raise an exception. -#if PY_MAJOR_VERSION < 3 - PyErr_Format(PyExc_AttributeError, - "'PythonTask' object has no attribute '%.400s'", - PyString_AS_STRING(attr)); -#else - PyErr_Format(PyExc_AttributeError, - "'PythonTask' object has no attribute '%U'", - attr); -#endif - return nullptr; + if (item != nullptr) { + // PyDict_GetItem returns a borrowed reference. + Py_INCREF(item); + return item; } - // PyDict_GetItem returns a borrowed reference. - Py_INCREF(item); - return item; + return PyObject_GenericGetAttr(self, attr); } /** diff --git a/panda/src/event/pythonTask.h b/panda/src/event/pythonTask.h index 06ff8b6fe4..0861827f94 100644 --- a/panda/src/event/pythonTask.h +++ b/panda/src/event/pythonTask.h @@ -55,7 +55,7 @@ public: PUBLISHED: int __setattr__(PyObject *self, PyObject *attr, PyObject *v); int __delattr__(PyObject *self, PyObject *attr); - PyObject *__getattr__(PyObject *attr) const; + PyObject *__getattribute__(PyObject *self, PyObject *attr) const; int __traverse__(visitproc visit, void *arg); int __clear__(); From 5f0f0057239e5f170a2e522fa27a0690eb780905 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Mar 2019 22:59:17 +0100 Subject: [PATCH 131/144] tests: add various tests for PythonTask.__dict__ access --- tests/event/test_pythontask.py | 78 ++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 tests/event/test_pythontask.py diff --git a/tests/event/test_pythontask.py b/tests/event/test_pythontask.py new file mode 100644 index 0000000000..d6806b4f72 --- /dev/null +++ b/tests/event/test_pythontask.py @@ -0,0 +1,78 @@ +from panda3d.core import PythonTask +import pytest +import types +import sys + + +def test_pythontask_property_builtin(): + task = PythonTask() + + # Read-write property + assert task.name == "" + task.name = "ABC" + + # Read-only property + assert task.dt == 0.0 + with pytest.raises(AttributeError): + task.dt = 1.0 + assert task.dt == 0.0 + + # Non-existent property + with pytest.raises(AttributeError): + task.abc + + +def test_pythontask_property_custom(): + task = PythonTask() + assert not hasattr(task, 'custom_field') + + task.custom_field = 1.0 + assert hasattr(task, 'custom_field') + assert task.custom_field == 1.0 + + task.custom_field = 2.0 + assert task.custom_field == 2.0 + + del task.custom_field + assert not hasattr(task, 'custom_field') + + +def test_pythontask_property_override(): + task = PythonTask() + assert isinstance(task.gather, types.BuiltinMethodType) + + task.gather = 123 + assert task.gather == 123 + + del task.gather + assert isinstance(task.gather, types.BuiltinMethodType) + + +def test_pythontask_dict_get(): + task = PythonTask() + + d = task.__dict__ + rc1 = sys.getrefcount(d) + + task.__dict__ + task.__dict__ + + rc2 = sys.getrefcount(d) + + assert rc1 == rc2 + + +def test_pythontask_dict_set(): + task = PythonTask() + d = {} + + rc1 = sys.getrefcount(d) + task.__dict__ = d + rc2 = sys.getrefcount(d) + + assert rc1 + 1 == rc2 + + task.__dict__ = {} + rc2 = sys.getrefcount(d) + + assert rc1 == rc2 From e3602ae7c0dfe8207066d9cdfcd1c07aca0396f3 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 5 Mar 2019 12:03:56 +0100 Subject: [PATCH 132/144] Add BACKERS.md, update README.md with info about OpenCollective [skip ci] --- BACKERS.md | 28 ++++++++++++++++++++++++++++ README.md | 24 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 BACKERS.md diff --git a/BACKERS.md b/BACKERS.md new file mode 100644 index 0000000000..b86afc0e71 --- /dev/null +++ b/BACKERS.md @@ -0,0 +1,28 @@ +# Panda3D Backers + +This is a list of all the people who are contributing financially to Panda3D. If you'd like to join them, visit [our campaign on OpenCollective](https://opencollective.com/panda3d)! + +## Gold Sponsors + +![Gold Sponsors](https://opencollective.com/panda3d/tiers/gold-sponsor.svg?avatarHeight=48&width=600) + +* [tcdude](https://opencollective.com/tizilogic) + +## Bronze Sponsors + +![Bronze Sponsors](https://opencollective.com/panda3d/tiers/bronze-sponsor.svg?avatarHeight=48&width=600) + +* [Mitchell Stokes](https://opencollective.com/mitchell-stokes) +* [Daniel Stokes](https://opencollective.com/daniel-stokes) +* [David Rose](https://opencollective.com/david-rose) +* [Carnetsoft](https://cs-driving-simulator.com/) + +## Benefactors + +![Benefactors](https://opencollective.com/panda3d/tiers/benefactor.svg?avatarHeight=48&width=600) + +* Sam Edwards + +## Backers + +![Backers](https://opencollective.com/panda3d/tiers/backer.svg?avatarHeight=48&width=600) diff --git a/README.md b/README.md index 4d26a0a778..73205e7cc4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ [![Build Status](https://travis-ci.org/panda3d/panda3d.svg?branch=master)](https://travis-ci.org/panda3d/panda3d) +[![OpenCollective](https://opencollective.com/panda3d/backers/badge.svg)](https://opencollective.com/panda3d) +[![OpenCollective](https://opencollective.com/panda3d/sponsors/badge.svg)](https://opencollective.com/panda3d) @@ -229,3 +231,25 @@ models that are necessary for the developers to reproduce the issue. If you're not sure whether you've encountered a bug, feel free to ask about it in the forums or the IRC channel first. + +Supporting the Project +====================== + +If you would like to support the project financially, visit +[our campaign on OpenCollective](https://opencollective.com/panda3d). Your +contributions help us accelerate the development of Panda3D. + +For the list of backers, see the [BACKERS.md](BACKERS.md) file or visit the +[Sponsors page](https://www.panda3d.org/sponsors) on our web site. Thank you +to everyone who has donated! + + + + + +### Gold Sponsors +[![](https://opencollective.com/panda3d/tiers/gold-sponsor/0/avatar.svg?avatarHeight=128)](https://opencollective.com/panda3d/tiers/gold-sponsor/0/website) +[![](https://opencollective.com/panda3d/tiers/gold-sponsor/1/avatar.svg?avatarHeight=128)](https://opencollective.com/panda3d/tiers/gold-sponsor/1/website) +[![](https://opencollective.com/panda3d/tiers/gold-sponsor/2/avatar.svg?avatarHeight=128)](https://opencollective.com/panda3d/tiers/gold-sponsor/2/website) +[![](https://opencollective.com/panda3d/tiers/gold-sponsor/3/avatar.svg?avatarHeight=128)](https://opencollective.com/panda3d/tiers/gold-sponsor/3/website) +[![](https://opencollective.com/panda3d/tiers/gold-sponsor/4/avatar.svg?avatarHeight=128)](https://opencollective.com/panda3d/tiers/gold-sponsor/4/website) From 12eeff0dec48784ea551c37d8d9d833d24db4a31 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 7 Mar 2019 17:33:21 +0100 Subject: [PATCH 133/144] py_panda: fix memory leak accessing map/seq properties --- dtool/src/interrogatedb/py_wrappers.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/dtool/src/interrogatedb/py_wrappers.cxx b/dtool/src/interrogatedb/py_wrappers.cxx index e004246249..9f463c9f92 100644 --- a/dtool/src/interrogatedb/py_wrappers.cxx +++ b/dtool/src/interrogatedb/py_wrappers.cxx @@ -47,6 +47,7 @@ static void Dtool_WrapperBase_dealloc(PyObject *self) { Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self; nassertv(wrap); Py_XDECREF(wrap->_self); + Py_TYPE(self)->tp_free(self); } static PyObject *Dtool_WrapperBase_repr(PyObject *self) { From 5426ec68dd6560d7102c8160cc88f25638646c23 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 7 Mar 2019 17:33:57 +0100 Subject: [PATCH 134/144] makepanda: properly respect --x11-incdir setting --- makepanda/makepanda.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 05d639e7d1..aeaa09585d 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -4026,12 +4026,12 @@ if (not RUNTIME): # if (not RUNTIME): - OPTS=['DIR:panda/src/display', 'BUILDING:PANDA'] + OPTS=['DIR:panda/src/display', 'BUILDING:PANDA', 'X11'] TargetAdd('p3display_graphicsStateGuardian.obj', opts=OPTS, input='graphicsStateGuardian.cxx') TargetAdd('p3display_composite1.obj', opts=OPTS, input='p3display_composite1.cxx') TargetAdd('p3display_composite2.obj', opts=OPTS, input='p3display_composite2.cxx') - OPTS=['DIR:panda/src/display'] + OPTS=['DIR:panda/src/display', 'X11'] IGATEFILES=GetDirectoryContents('panda/src/display', ["*.h", "*_composite*.cxx"]) IGATEFILES.remove("renderBuffer.h") TargetAdd('libp3display.in', opts=OPTS, input=IGATEFILES) @@ -5243,7 +5243,7 @@ if (GetTarget() == 'android' and PkgSkip("EGL")==0 and PkgSkip("GLES")==0 and no # if (not RUNTIME and (GetTarget() in ('windows', 'darwin') or PkgSkip("X11")==0) and PkgSkip("TINYDISPLAY")==0): - OPTS=['DIR:panda/src/tinydisplay', 'BUILDING:TINYDISPLAY'] + OPTS=['DIR:panda/src/tinydisplay', 'BUILDING:TINYDISPLAY', 'X11'] TargetAdd('p3tinydisplay_composite1.obj', opts=OPTS, input='p3tinydisplay_composite1.cxx') TargetAdd('p3tinydisplay_composite2.obj', opts=OPTS, input='p3tinydisplay_composite2.cxx') TargetAdd('p3tinydisplay_ztriangle_1.obj', opts=OPTS, input='ztriangle_1.cxx') From 5b00ff1aa72545d7b047d7dd906c06d06dab1d47 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 7 Mar 2019 17:45:00 +0100 Subject: [PATCH 135/144] readme: update links to point to 1.10.2 thirdparty packages The 1.10.2 thirdparty packages include a newer version of Pmw (with an __init__.py that will choose the older version when using Python 2). Fixes #573 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 73205e7cc4..9c4de7903d 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,8 @@ depending on whether you are on a 32-bit or 64-bit system, or you can [click here](https://github.com/rdb/panda3d-thirdparty) for instructions on building them from source. -https://www.panda3d.org/download/panda3d-1.10.1/panda3d-1.10.1-tools-win64.zip -https://www.panda3d.org/download/panda3d-1.10.1/panda3d-1.10.1-tools-win32.zip +https://www.panda3d.org/download/panda3d-1.10.2/panda3d-1.10.2-tools-win64.zip +https://www.panda3d.org/download/panda3d-1.10.2/panda3d-1.10.2-tools-win32.zip After acquiring these dependencies, you may simply build Panda3D from the command prompt using the following command. (Change `14.1` to `14` if you are @@ -135,7 +135,7 @@ macOS ----- On macOS, you will need to download a set of precompiled thirdparty packages in order to -compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.1/panda3d-1.10.1-tools-mac.tar.gz). +compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.2/panda3d-1.10.2-tools-mac.tar.gz). After placing the thirdparty directory inside the panda3d source directory, you may build Panda3D using a command like the following: From 08c686ba188160f90b2e331710ff236c2bc03fbe Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 8 Mar 2019 11:14:56 +0100 Subject: [PATCH 136/144] windisplay: fix issues with runtime fullscreen switching --- panda/src/windisplay/winGraphicsWindow.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index 195189ac9e..d3e444cac9 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -979,12 +979,12 @@ make_style(const WindowProperties &properties) { DWORD window_style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - if (_properties.get_fullscreen()) { + if (properties.get_fullscreen()) { window_style |= WS_SYSMENU; - } else if (!_properties.get_undecorated()) { + } else if (!properties.get_undecorated()) { window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX); - if (!_properties.get_fixed_size()) { + if (!properties.get_fixed_size()) { window_style |= (WS_SIZEBOX | WS_MAXIMIZEBOX); } else { window_style |= WS_BORDER; From a634e729c83a44db91c40991686930454309f1fd Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 8 Mar 2019 11:45:47 +0100 Subject: [PATCH 137/144] interrogate: fix uninitialized var, fixes sporadic nb_true_divide This was a regression introduced by fa6c066b2f21856036cb24d482a7152406c6c2e2 (which in turn fixed #529) --- dtool/src/interrogate/interfaceMakerPythonNative.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.h b/dtool/src/interrogate/interfaceMakerPythonNative.h index 8b18ef1957..c667ab22fa 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.h +++ b/dtool/src/interrogate/interfaceMakerPythonNative.h @@ -121,7 +121,7 @@ private: public: std::string _answer_location; WrapperType _wrapper_type; - int _min_version; + int _min_version = 0; std::string _wrapper_name; std::set _remaps; bool _keep_method; From a7d9baeeb8dd1ed788889a4e71be051c3dc532be Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 10 Mar 2019 19:20:43 +0100 Subject: [PATCH 138/144] Remove unused ProfileTimer class It doesn't seem to be used by anything, but it does take up 64+ KiB of memory in every Panda process. --- makepanda/makepanda.vcproj | 3 - panda/src/express/p3express_composite1.cxx | 1 - panda/src/express/profileTimer.I | 67 -------- panda/src/express/profileTimer.cxx | 179 --------------------- panda/src/express/profileTimer.h | 103 ------------ panda/src/putil/datagramInputFile.cxx | 1 - 6 files changed, 354 deletions(-) delete mode 100644 panda/src/express/profileTimer.I delete mode 100644 panda/src/express/profileTimer.cxx delete mode 100644 panda/src/express/profileTimer.h diff --git a/makepanda/makepanda.vcproj b/makepanda/makepanda.vcproj index 2fee06a963..785061eea8 100644 --- a/makepanda/makepanda.vcproj +++ b/makepanda/makepanda.vcproj @@ -2206,7 +2206,6 @@ - @@ -2215,10 +2214,8 @@ - - diff --git a/panda/src/express/p3express_composite1.cxx b/panda/src/express/p3express_composite1.cxx index 6bfb55de8e..7f071921e7 100644 --- a/panda/src/express/p3express_composite1.cxx +++ b/panda/src/express/p3express_composite1.cxx @@ -30,5 +30,4 @@ #include "pointerToArray.cxx" #include "pointerToBase.cxx" #include "pointerToVoid.cxx" -#include "profileTimer.cxx" #include "pStatCollectorForwardBase.cxx" diff --git a/panda/src/express/profileTimer.I b/panda/src/express/profileTimer.I deleted file mode 100644 index bd5102e6de..0000000000 --- a/panda/src/express/profileTimer.I +++ /dev/null @@ -1,67 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file profileTimer.I - */ - -INLINE void ProfileTimer:: -on() { - _on = TrueClock::get_global_ptr()->get_short_time(); -} - - -INLINE double ProfileTimer:: -getTime() { - double time = TrueClock::get_global_ptr()->get_short_time(); - double et=_elapsedTime+=time-_on; - _on=time; - _elapsedTime=0.0; - return et; -} - - -INLINE void ProfileTimer:: -mark(const char* tag) { - if (!_entries) { - std::cerr << "ProfileTimer::mark !_entries" << std::endl; - exit(1); - } - if (_entryCount < _maxEntries-1) { - TimerEntry& p=_entries[_entryCount]; - p._tag=tag; - p._time=getTime(); - ++_entryCount; - } else { - _entries[_entryCount]._tag="*** Overflow ***"; - } -} - - -INLINE void ProfileTimer:: -off() { - double time = TrueClock::get_global_ptr()->get_short_time(); - _elapsedTime+=time-_on; -} - - -INLINE void ProfileTimer:: -off(const char* tag) { - double time = TrueClock::get_global_ptr()->get_short_time(); - _elapsedTime+=time-_on; - mark(tag); -} - - -INLINE ProfileTimer::AutoTimer:: -~AutoTimer() { - // If the AutoTimer is the first auto ctor, then it will be the last auto - // dtor, for that block. Therefore, now is the time to mark the time for - // the blockfunction: - _profile.mark(_tag); - --_profile._autoTimerCount; -} diff --git a/panda/src/express/profileTimer.cxx b/panda/src/express/profileTimer.cxx deleted file mode 100644 index dfad4b03b4..0000000000 --- a/panda/src/express/profileTimer.cxx +++ /dev/null @@ -1,179 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file profileTimer.cxx - */ - -#include "profileTimer.h" - -#include "pmap.h" - -using std::ostream; -using std::string; - -// See ProfileTimer.h for documentation. - - -EXPCL_PANDA_EXPRESS ProfileTimer Skyler_timer_global=ProfileTimer("startup"); - -ProfileTimer* ProfileTimer::_head; - -ProfileTimer:: -ProfileTimer(const char* name, int maxEntries) : - _entries(nullptr), - _autoTimerCount(0) { - // Keep a list of the ProfileTimers, so we can print them: - _next=_head; - _head=this; - if (name) { - init(name, maxEntries); - } -} - -ProfileTimer:: -ProfileTimer(const ProfileTimer& other) { - // Add to list: - _next=_head; - _head=this; - // init it: - _name=other._name; - _maxEntries=other._maxEntries; - if (_name) { - init(_name, _maxEntries); - } - // Copy other entries: - _on=other._on; - _elapsedTime=other._elapsedTime; - _autoTimerCount=other._autoTimerCount; - _entryCount=other._entryCount; - if (other._entries) { - memcpy(_entries, other._entries, _entryCount * sizeof(TimerEntry)); - } -} - -ProfileTimer:: -~ProfileTimer() { - PANDA_FREE_ARRAY(_entries); - // Remove this from the list: - if (_head==this) { - _head=_next; - } else { - ProfileTimer* p=_head; - ProfileTimer* prior=p; - while (p) { - if (p==this) { - prior->_next=_next; - break; - } - prior=p; - p=p->_next; - } - } -} - -void ProfileTimer:: -init(const char* name, int maxEntries) { - _name=name; - _maxEntries=maxEntries; - _entries = (TimerEntry *)PANDA_MALLOC_ARRAY(_maxEntries * sizeof(TimerEntry)); - _entryCount=0; - _elapsedTime=0.0; - _on=0.0; -} - -double ProfileTimer:: -getTotalTime() const { - double total=0; - int i; - for (i=0; i<_entryCount; ++i) { - TimerEntry& te=_entries[i]; - total+=te._time; - } - return total; -} - -void ProfileTimer:: -consolidateAllTo(ostream &out) { - ProfileTimer* p=_head; - while (p) { - p->consolidateTo(out); - p=p->_next; - } -} - -void ProfileTimer:: -consolidateTo(ostream &out) const { - pmap entries; - int i; - for (i=0; i<_entryCount; ++i) { - TimerEntry& te=_entries[i]; - entries[te._tag]+=te._time; - } - out << "-------------------------------------------------------------------\n" - << "Profile Timing of " << _name - << "\n\n"; // ...should print data and time too. - double total=0; - { - pmap::const_iterator i=entries.begin(); - for (;i!=entries.end(); ++i) { - out << " " << std::setw(50) << i->first << ": " - << std::setiosflags(std::ios::fixed) << std::setprecision(6) << std::setw(10) << i->second << "\n"; - total+=i->second; - } - } - out << "\n [Total Time: " - << std::setiosflags(std::ios::fixed) << std::setprecision(6) << total - << " seconds]\n" - << "-------------------------------------------------------------------\n"; - out << std::endl; -} - -void ProfileTimer:: -printAllTo(ostream &out) { - ProfileTimer* p=_head; - while (p) { - p->printTo(out); - p=p->_next; - } -} - -void ProfileTimer:: -printTo(ostream &out) const { - out << "-------------------------------------------------------------------\n" - << "Profile Timing of " << _name - << "\n\n"; // ...should print data and time too. - double total=0; - int i; - for (i=0; i<_entryCount; ++i) { - TimerEntry& te=_entries[i]; - out << " " << std::setw(50) << te._tag << ": " - << std::setiosflags(std::ios::fixed) << std::setprecision(6) << std::setw(10) << te._time << "\n"; - total+=te._time; - } - out << "\n [Total Time: " - << std::setiosflags(std::ios::fixed) << std::setprecision(6) << total - << " seconds]\n" - << "-------------------------------------------------------------------\n"; - out << std::endl; -} - -ProfileTimer::AutoTimer::AutoTimer(ProfileTimer& profile, const char* tag) : - _profile(profile) { - _tag=tag; - if (_profile._autoTimerCount) { - // ...this is a nested call to another AutoTimer. Assign the time to the - // prior AutoTimer: - _profile.mark(_profile._entries[_profile._entryCount-1]._tag); - } else { - // ...this is not a nested call. - _profile.mark("other"); - } - // Tell the profile that it's in an AutoTimer: - ++_profile._autoTimerCount; - _profile.mark(_tag); -} diff --git a/panda/src/express/profileTimer.h b/panda/src/express/profileTimer.h deleted file mode 100644 index 39ab65c588..0000000000 --- a/panda/src/express/profileTimer.h +++ /dev/null @@ -1,103 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file profileTimer.h - * @author skyler - */ - -#ifndef PROFILETIMER_H -#define PROFILETIMER_H - -#include "pandabase.h" -#include "trueClock.h" - -/* - ProfileTimer - - HowTo: - Create a ProfileTimer and hold onto it. - Call init() whenever you like (the timer doesn't - start yet). - Call on() to start the timer. - While the timer is on, call mark() at each point of interest, - in the code you are timing. - You can turn the timer off() and on() to skip things you - don't want to time. - When your timing is finished, call printTo() to see the - results (e.g. myTimer.printTo(cerr)). - - Notes: - You should be able to time things down to the millisecond - well enough, but if you call on() and off() within micro- - seconds of each other, I don't think you'll get very good - results. -*/ -class EXPCL_PANDA_EXPRESS ProfileTimer { - enum { MaxEntriesDefault=4096 }; -PUBLISHED: - explicit ProfileTimer(const char* name=0, int maxEntries=MaxEntriesDefault); - ProfileTimer(const ProfileTimer& other); - ~ProfileTimer(); - - void init(const char* name, int maxEntries=MaxEntriesDefault); - - void on(); - void mark(const char* tag); - void off(); - void off(const char* tag); - - // Don't call any of the following during timing: (Because they are slow, - // not because anything will break). - double getTotalTime() const; - static void consolidateAllTo(std::ostream &out=std::cout); - void consolidateTo(std::ostream &out=std::cout) const; - static void printAllTo(std::ostream &out=std::cout); - void printTo(std::ostream &out=std::cout) const; - -public: - /* - e.g. - void Foo() { - ProfileTimer::AutoTimer(myProfiler, "Foo()"); - ... - } - */ - class EXPCL_PANDA_EXPRESS AutoTimer { - public: - AutoTimer(ProfileTimer& profile, const char* tag); - ~AutoTimer(); - - protected: - ProfileTimer& _profile; - const char* _tag; - }; - -protected: - static ProfileTimer* _head; - ProfileTimer* _next; - class TimerEntry { - public: - const char* _tag; // not owned by this. - double _time; - }; - double _on; - double _elapsedTime; - const char* _name; // not owned by this. - int _maxEntries; - int _entryCount; - TimerEntry* _entries; - int _autoTimerCount; // see class AutoTimer - - double getTime(); - - friend class ProfileTimer::AutoTimer; -}; - -#include "profileTimer.I" - -#endif //] diff --git a/panda/src/putil/datagramInputFile.cxx b/panda/src/putil/datagramInputFile.cxx index 600f699635..3c7da5d320 100644 --- a/panda/src/putil/datagramInputFile.cxx +++ b/panda/src/putil/datagramInputFile.cxx @@ -15,7 +15,6 @@ #include "temporaryFile.h" #include "numeric_types.h" #include "datagramIterator.h" -#include "profileTimer.h" #include "config_putil.h" #include "config_express.h" #include "virtualFileSystem.h" From 511b0e7af3e8f9541ee8c3ba3a9a3800c585074e Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 10 Mar 2019 19:23:05 +0100 Subject: [PATCH 139/144] gobj: prevent GeomVertexReader/Writer.set_row with negative row --- panda/src/gobj/geomVertexReader.I | 1 + panda/src/gobj/geomVertexWriter.I | 1 + 2 files changed, 2 insertions(+) diff --git a/panda/src/gobj/geomVertexReader.I b/panda/src/gobj/geomVertexReader.I index 893d6458cf..2fc27b911a 100644 --- a/panda/src/gobj/geomVertexReader.I +++ b/panda/src/gobj/geomVertexReader.I @@ -328,6 +328,7 @@ set_row_unsafe(int row) { */ INLINE void GeomVertexReader:: set_row(int row) { + nassertv(row >= 0); _start_row = row; if (has_column()) { bool result = set_pointer(_start_row); diff --git a/panda/src/gobj/geomVertexWriter.I b/panda/src/gobj/geomVertexWriter.I index b55fdd5f4a..00b9652e8d 100644 --- a/panda/src/gobj/geomVertexWriter.I +++ b/panda/src/gobj/geomVertexWriter.I @@ -297,6 +297,7 @@ set_row_unsafe(int row) { */ INLINE void GeomVertexWriter:: set_row(int row) { + nassertv(row >= 0); _start_row = row; if (has_column()) { set_pointer(_start_row); From 0e70997fbf627c9a7a7057df66497b53e8249869 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 10 Mar 2019 19:30:13 +0100 Subject: [PATCH 140/144] x11display: fixes for multi-monitor and fullscreen support - DisplayInformation now gives the list of display modes returned by XRRGetScreenResources if RandR 1.2 is supported, which is apparently more reliable than the previous XRRSizes/XRRRates approach. - Switching fullscreen on X11 to the current resolution on the CRTC that the monitor is on will make the window cover the CRTC properly, rather than forcing the window to have an origin of (0, 0). - Passing in the pipe's display width/height is commonly done to go fullscreen at native res, but this may not correspond to a real display resolution. It now detects when this is done, and interprets this as "go fullscreen at the native resolution on the current CRTC". Fixes #575 --- panda/src/x11display/x11GraphicsPipe.cxx | 175 ++++++++++++++++++--- panda/src/x11display/x11GraphicsPipe.h | 64 ++++++++ panda/src/x11display/x11GraphicsWindow.cxx | 91 ++++++++--- 3 files changed, 283 insertions(+), 47 deletions(-) diff --git a/panda/src/x11display/x11GraphicsPipe.cxx b/panda/src/x11display/x11GraphicsPipe.cxx index e5e8da18c8..6050911fb4 100644 --- a/panda/src/x11display/x11GraphicsPipe.cxx +++ b/panda/src/x11display/x11GraphicsPipe.cxx @@ -156,21 +156,55 @@ x11GraphicsPipe(const std::string &display) : void *xrandr = dlopen("libXrandr.so.2", RTLD_NOW | RTLD_LOCAL); if (xrandr != nullptr) { pfn_XRRQueryExtension _XRRQueryExtension = (pfn_XRRQueryExtension)dlsym(xrandr, "XRRQueryExtension"); + pfn_XRRQueryVersion _XRRQueryVersion = (pfn_XRRQueryVersion)dlsym(xrandr, "XRRQueryVersion"); + _XRRSizes = (pfn_XRRSizes)dlsym(xrandr, "XRRSizes"); _XRRRates = (pfn_XRRRates)dlsym(xrandr, "XRRRates"); _XRRGetScreenInfo = (pfn_XRRGetScreenInfo)dlsym(xrandr, "XRRGetScreenInfo"); _XRRConfigCurrentConfiguration = (pfn_XRRConfigCurrentConfiguration)dlsym(xrandr, "XRRConfigCurrentConfiguration"); _XRRSetScreenConfig = (pfn_XRRSetScreenConfig)dlsym(xrandr, "XRRSetScreenConfig"); + int event, error, major, minor; if (_XRRQueryExtension == nullptr || _XRRSizes == nullptr || _XRRRates == nullptr || _XRRGetScreenInfo == nullptr || _XRRConfigCurrentConfiguration == nullptr || - _XRRSetScreenConfig == nullptr) { + _XRRSetScreenConfig == nullptr || _XRRQueryVersion == nullptr) { _have_xrandr = false; x11display_cat.warning() << "libXrandr.so.2 does not provide required functions; resolution setting will not work.\n"; + } + else if (_XRRQueryExtension(_display, &event, &error) && + _XRRQueryVersion(_display, &major, &minor)) { + _have_xrandr = true; + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Found RandR extension " << major << "." << minor << "\n"; + } + + if (major > 1 || (major == 1 && minor >= 2)) { + if (major > 1 || (major == 1 && minor >= 3)) { + _XRRGetScreenResourcesCurrent = (pfn_XRRGetScreenResources) + dlsym(xrandr, "XRRGetScreenResourcesCurrent"); + } else { + // Fall back to this slower version. + _XRRGetScreenResourcesCurrent = (pfn_XRRGetScreenResources) + dlsym(xrandr, "XRRGetScreenResources"); + } + + _XRRFreeScreenResources = (pfn_XRRFreeScreenResources)dlsym(xrandr, "XRRFreeScreenResources"); + _XRRGetCrtcInfo = (pfn_XRRGetCrtcInfo)dlsym(xrandr, "XRRGetCrtcInfo"); + _XRRFreeCrtcInfo = (pfn_XRRFreeCrtcInfo)dlsym(xrandr, "XRRFreeCrtcInfo"); + } else { + _XRRGetScreenResourcesCurrent = nullptr; + _XRRFreeScreenResources = nullptr; + _XRRGetCrtcInfo = nullptr; + _XRRFreeCrtcInfo = nullptr; + } } else { - int event, error; - _have_xrandr = _XRRQueryExtension(_display, &event, &error); + _have_xrandr = false; + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "RandR extension not supported; resolution setting will not work.\n"; + } } } else { _have_xrandr = false; @@ -182,29 +216,61 @@ x11GraphicsPipe(const std::string &display) : // Use Xrandr to fill in the supported resolution list. if (_have_xrandr) { - int num_sizes, num_rates; - XRRScreenSize *xrrs; - xrrs = _XRRSizes(_display, 0, &num_sizes); - _display_information->_total_display_modes = 0; - for (int i = 0; i < num_sizes; ++i) { - _XRRRates(_display, 0, i, &num_rates); - _display_information->_total_display_modes += num_rates; - } + // If we have XRRGetScreenResources, we prefer that. It seems to be more + // reliable than XRRSizes in multi-monitor set-ups. + if (auto res = get_screen_resources()) { + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Using XRRScreenResources to obtain display modes\n"; + } + _display_information->_total_display_modes = res->nmode; + _display_information->_display_mode_array = new DisplayMode[res->nmode]; + for (int i = 0; i < res->nmode; ++i) { + XRRModeInfo &mode = res->modes[i]; - short *rates; - short counter = 0; - _display_information->_display_mode_array = new DisplayMode[_display_information->_total_display_modes]; - for (int i = 0; i < num_sizes; ++i) { - int num_rates; - rates = _XRRRates(_display, 0, i, &num_rates); - for (int j = 0; j < num_rates; ++j) { - DisplayMode* dm = _display_information->_display_mode_array + counter; - dm->width = xrrs[i].width; - dm->height = xrrs[i].height; - dm->refresh_rate = rates[j]; + DisplayMode *dm = _display_information->_display_mode_array + i; + dm->width = mode.width; + dm->height = mode.height; dm->bits_per_pixel = -1; dm->fullscreen_only = false; - ++counter; + + if (mode.hTotal && mode.vTotal) { + dm->refresh_rate = (double)mode.dotClock / + ((double)mode.hTotal * (double)mode.vTotal); + } else { + dm->refresh_rate = 0; + } + } + } else { + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Using XRRSizes and XRRRates to obtain display modes\n"; + } + + int num_sizes, num_rates; + XRRScreenSize *xrrs; + xrrs = _XRRSizes(_display, 0, &num_sizes); + _display_information->_total_display_modes = 0; + for (int i = 0; i < num_sizes; ++i) { + _XRRRates(_display, 0, i, &num_rates); + _display_information->_total_display_modes += num_rates; + } + + short *rates; + short counter = 0; + _display_information->_display_mode_array = new DisplayMode[_display_information->_total_display_modes]; + for (int i = 0; i < num_sizes; ++i) { + int num_rates; + rates = _XRRRates(_display, 0, i, &num_rates); + for (int j = 0; j < num_rates; ++j) { + DisplayMode* dm = _display_information->_display_mode_array + counter; + dm->width = xrrs[i].width; + dm->height = xrrs[i].height; + dm->refresh_rate = rates[j]; + dm->bits_per_pixel = -1; + dm->fullscreen_only = false; + ++counter; + } } } } @@ -258,6 +324,69 @@ x11GraphicsPipe:: } } +/** + * Returns an XRRScreenResources object, or null if RandR 1.2 is not supported. + */ +std::unique_ptr x11GraphicsPipe:: +get_screen_resources() const { + XRRScreenResources *res = nullptr; + + if (_have_xrandr && _XRRGetScreenResourcesCurrent != nullptr) { + res = _XRRGetScreenResourcesCurrent(_display, _root); + } + + return std::unique_ptr(res, _XRRFreeScreenResources); +} + +/** + * Returns an XRRCrtcInfo object, or null if RandR 1.2 is not supported. + */ +std::unique_ptr x11GraphicsPipe:: +get_crtc_info(XRRScreenResources *res, RRCrtc crtc) const { + XRRCrtcInfo *info = nullptr; + + if (_have_xrandr && _XRRGetCrtcInfo != nullptr) { + info = _XRRGetCrtcInfo(_display, res, crtc); + } + + return std::unique_ptr(info, _XRRFreeCrtcInfo); +} + +/** + * Finds a CRTC for going fullscreen to, at the given origin. The new CRTC + * is returned, along with its x, y, width and height. + * + * If the required RandR extension is not supported, a value of None will be + * returned, but x, y, width and height will still be populated. + */ +RRCrtc x11GraphicsPipe:: +find_fullscreen_crtc(const LPoint2i &point, + int &x, int &y, int &width, int &height) { + x = 0; + y = 0; + width = DisplayWidth(_display, _screen); + height = DisplayHeight(_display, _screen); + + if (auto res = get_screen_resources()) { + for (int i = 0; i < res->ncrtc; ++i) { + RRCrtc crtc = res->crtcs[i]; + if (auto info = get_crtc_info(res.get(), crtc)) { + if (point[0] >= info->x && point[0] < info->x + info->width && + point[1] >= info->y && point[1] < info->y + info->height) { + + x = info->x; + y = info->y; + width = info->width; + height = info->height; + return crtc; + } + } + } + } + + return None; +} + /** * Returns an indication of the thread in which this GraphicsPipe requires its * window processing to be performed: typically either the app thread (e.g. diff --git a/panda/src/x11display/x11GraphicsPipe.h b/panda/src/x11display/x11GraphicsPipe.h index 3b8802e6e2..e1abf80b00 100644 --- a/panda/src/x11display/x11GraphicsPipe.h +++ b/panda/src/x11display/x11GraphicsPipe.h @@ -32,12 +32,61 @@ typedef struct _XcursorImages XcursorImages; typedef unsigned short Rotation; typedef unsigned short SizeID; +typedef unsigned long XRRModeFlags; +typedef XID RROutput; +typedef XID RRCrtc; +typedef XID RRMode; + typedef struct _XRRScreenConfiguration XRRScreenConfiguration; typedef struct { int width, height; int mwidth, mheight; } XRRScreenSize; +typedef struct _XRRModeInfo { + RRMode id; + unsigned int width; + unsigned int height; + unsigned long dotClock; + unsigned int hSyncStart; + unsigned int hSyncEnd; + unsigned int hTotal; + unsigned int hSkew; + unsigned int vSyncStart; + unsigned int vSyncEnd; + unsigned int vTotal; + char *name; + unsigned int nameLength; + XRRModeFlags modeFlags; +} XRRModeInfo; + +typedef struct _XRRScreenResources { + Time timestamp; + Time configTimestamp; + int ncrtc; + RRCrtc *crtcs; + int noutput; + RROutput *outputs; + int nmode; + XRRModeInfo *modes; +} XRRScreenResources; + +typedef struct _XRRCrtcInfo { + Time timestamp; + int x, y; + unsigned int width, height; + RRMode mode; + Rotation rotation; + int noutput; + RROutput *outputs; + Rotation rotations; + int npossible; + RROutput *possible; +} XRRCrtcInfo; + +typedef void (*pfn_XRRFreeScreenResources)(XRRScreenResources *resources); +typedef void (*pfn_XRRFreeCrtcInfo)(XRRCrtcInfo *crtcInfo); + class FrameBufferProperties; /** @@ -64,6 +113,12 @@ public: static INLINE int enable_x_error_messages(); static INLINE int get_x_error_count(); + std::unique_ptr get_screen_resources() const; + std::unique_ptr get_crtc_info(XRRScreenResources *res, RRCrtc crtc) const; + + RRCrtc find_fullscreen_crtc(const LPoint2i &point, + int &x, int &y, int &width, int &height); + public: virtual PreferredWindowThread get_preferred_window_thread() const; @@ -100,6 +155,7 @@ public: pfn_XcursorImageDestroy _XcursorImageDestroy; typedef Bool (*pfn_XRRQueryExtension)(X11_Display *, int*, int*); + typedef Status (*pfn_XRRQueryVersion)(X11_Display *, int*, int*); typedef XRRScreenSize *(*pfn_XRRSizes)(X11_Display*, int, int*); typedef short *(*pfn_XRRRates)(X11_Display*, int, int, int*); typedef XRRScreenConfiguration *(*pfn_XRRGetScreenInfo)(X11_Display*, X11_Window); @@ -126,6 +182,14 @@ protected: typedef Status (*pfn_XF86DGADirectVideo)(X11_Display *, int, int); pfn_XF86DGADirectVideo _XF86DGADirectVideo; + typedef XRRScreenResources *(*pfn_XRRGetScreenResources)(X11_Display*, X11_Window); + typedef XRRCrtcInfo *(*pfn_XRRGetCrtcInfo)(X11_Display *dpy, XRRScreenResources *resources, RRCrtc crtc); + + pfn_XRRGetScreenResources _XRRGetScreenResourcesCurrent; + pfn_XRRFreeScreenResources _XRRFreeScreenResources; + pfn_XRRGetCrtcInfo _XRRGetCrtcInfo; + pfn_XRRFreeCrtcInfo _XRRFreeCrtcInfo; + private: void make_hidden_cursor(); void release_hidden_cursor(); diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index 0aa4e0bf64..5599959cdb 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -579,20 +579,60 @@ set_properties_now(WindowProperties &properties) { bool is_fullscreen = _properties.has_fullscreen() && _properties.get_fullscreen(); bool want_fullscreen = properties.has_fullscreen() ? properties.get_fullscreen() : is_fullscreen; + if (want_fullscreen && properties.has_origin()) { + // If we're fullscreen, reject changes to the origin. + properties.clear_origin(); + } + if (is_fullscreen != want_fullscreen || (is_fullscreen && properties.has_size())) { if (want_fullscreen) { - if (x11_pipe->_have_xrandr) { - XRRScreenConfiguration* conf = _XRRGetScreenInfo(_display, x11_pipe->get_root()); + // OK, first figure out which CRTC the window is on. It may be on more + // than one, actually, so grab a point in the center in order to figure + // out which one it's more-or-less mostly on. + LPoint2i center = _properties.get_origin() + _properties.get_size() / 2; + int x, y, width, height; + x11_pipe->find_fullscreen_crtc(center, x, y, width, height); + + // Which size should we go fullscreen in? + int reqsizex, reqsizey; + if (properties.has_size()) { + reqsizex = properties.get_x_size(); + reqsizey = properties.get_y_size(); + } else if (_properties.has_size()) { + reqsizex = _properties.get_x_size(); + reqsizey = _properties.get_y_size(); + } else { + reqsizex = width; + reqsizey = height; + } + + // Are we passing in pipe.display_width/height? This is actually the + // size of the virtual desktop, which may not be a real resolution, so + // if that is passed in, we have to assume that the user means to just + // fullscreen without changing the screen resolution. + if ((reqsizex == x11_pipe->get_display_width() && + reqsizey == x11_pipe->get_display_height()) + || (width == reqsizex && height == reqsizey) + || !x11_pipe->_have_xrandr) { + + // Cover the current CRTC. + properties.set_origin(x, y); + properties.set_size(width, height); + + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Setting window to fullscreen on CRTC " + << width << "x" << height << "+" << x << "+" << y << "\n"; + } + } else { + // We may need to change the screen resolution. The code below is + // suboptimal; in the future, we probably want to only touch the CRTC + // that the window is on. + XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, _xwindow); SizeID old_size_id = x11_pipe->_XRRConfigCurrentConfiguration(conf, &_orig_rotation); SizeID new_size_id = (SizeID) -1; - int num_sizes = 0, reqsizex, reqsizey; - if (properties.has_size()) { - reqsizex = properties.get_x_size(); - reqsizey = properties.get_y_size(); - } else { - reqsizex = _properties.get_x_size(); - reqsizey = _properties.get_y_size(); - } + int num_sizes = 0; + XRRScreenSize *xrrs; xrrs = x11_pipe->_XRRSizes(_display, 0, &num_sizes); for (int i = 0; i < num_sizes; ++i) { @@ -605,21 +645,29 @@ set_properties_now(WindowProperties &properties) { x11display_cat.error() << "Videocard has no supported display resolutions at specified res (" << reqsizex << " x " << reqsizey << ")\n"; - } else { - if (new_size_id != old_size_id) { + // Just go fullscreen at native resolution, then. + properties.set_origin(x, y); + properties.set_size(width, height); + } else { + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Switching to fullscreen with resolution " + << reqsizex << "x" << reqsizey << "\n"; + } + + if (new_size_id != old_size_id) { _XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), new_size_id, _orig_rotation, CurrentTime); if (_orig_size_id == (SizeID) -1) { // Remember the original resolution so we can switch back to it. _orig_size_id = old_size_id; } + + // Since the above changes the entire screen configuration, we + // have to set the origin to 0, 0. + properties.set_origin(0, 0); } } - } else { - // If we don't have Xrandr support, we fake the fullscreen support by - // setting the window size to the desktop size. - properties.set_size(x11_pipe->get_display_width(), - x11_pipe->get_display_height()); } } else { // Change the resolution back to what it was. Don't remove the SizeID @@ -1130,13 +1178,8 @@ set_wm_properties(const WindowProperties &properties, bool already_mapped) { size_hints_p = XAllocSizeHints(); if (size_hints_p != nullptr) { if (properties.has_origin()) { - if (_properties.get_fullscreen()) { - size_hints_p->x = 0; - size_hints_p->y = 0; - } else { - size_hints_p->x = properties.get_x_origin(); - size_hints_p->y = properties.get_y_origin(); - } + size_hints_p->x = properties.get_x_origin(); + size_hints_p->y = properties.get_y_origin(); size_hints_p->flags |= USPosition; } LVecBase2i size = _properties.get_size(); From 088b90e887d2646ffcaf9a1670472388e173cbf4 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 10 Mar 2019 20:20:56 +0100 Subject: [PATCH 141/144] TexMemWatcher: fix compatibility issues with Python 3 Closes #578 --- direct/src/showutil/TexMemWatcher.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/direct/src/showutil/TexMemWatcher.py b/direct/src/showutil/TexMemWatcher.py index 843395d58d..eb9a5b84cf 100644 --- a/direct/src/showutil/TexMemWatcher.py +++ b/direct/src/showutil/TexMemWatcher.py @@ -786,8 +786,9 @@ class TexMemWatcher(DirectObject): # Look for a single rectangular hole to hold this piece. tp = self.findHole(tr.area, tr.w, tr.h) if tp: - texCmp = cmp(tr.w, tr.h) - holeCmp = cmp(tp.p[1] - tp.p[0], tp.p[3] - tp.p[2]) + texCmp = (tr.w > tr.h) - (tr.w < tr.h) + holeCmp = ((tp.p[1] - tp.p[0]) > (tp.p[3] - tp.p[2])) \ + - ((tp.p[1] - tp.p[0]) < (tp.p[3] - tp.p[2])) if texCmp != 0 and holeCmp != 0 and texCmp != holeCmp: tp.rotated = True tr.placements = [tp] @@ -803,10 +804,11 @@ class TexMemWatcher(DirectObject): # in. tpList = self.findHolePieces(tr.area) if tpList: - texCmp = cmp(tr.w, tr.h) + texCmp = (tr.w > tr.h) - (tr.w < tr.h) tr.placements = tpList for tp in tpList: - holeCmp = cmp(tp.p[1] - tp.p[0], tp.p[3] - tp.p[2]) + holeCmp = ((tp.p[1] - tp.p[0]) > (tp.p[3] - tp.p[2])) \ + - ((tp.p[1] - tp.p[0]) < (tp.p[3] - tp.p[2])) if texCmp != 0 and holeCmp != 0 and texCmp != holeCmp: tp.rotated = True tp.setBitmasks(self.bitmasks) @@ -858,11 +860,11 @@ class TexMemWatcher(DirectObject): # we have to squish it? if tw < w: # We'd have to make it taller. - nh = min(area / tw, th) + nh = min(area // tw, th) th = nh elif th < h: # We'd have to make it narrower. - nw = min(area / th, tw) + nw = min(area // th, tw) tw = nw else: # Hey, we don't have to squish it after all! Just @@ -912,7 +914,7 @@ class TexMemWatcher(DirectObject): tpArea = (r - l) * (t - b) if tpArea >= area: # we're done. - shorten = (tpArea - area) / (r - l) + shorten = (tpArea - area) // (r - l) t -= shorten tp.p = (l, r, b, t) tp.area = (r - l) * (t - b) From 0dd33265ee008878ef36b9352235bea539da3575 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 10 Mar 2019 20:44:02 +0100 Subject: [PATCH 142/144] doc: add release notes for 1.10.2 --- doc/ReleaseNotes | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index ba67ff8dc8..b9a1150731 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -1,3 +1,28 @@ +------------------------ RELEASE 1.10.2 ----------------------- + +This release fixes several more bugs, including a few regressions +in 1.10.2. Upgrading is highly recommended. + +* Fix regression on Windows causing freezes and instability +* Fix a memory leak issue in Python applications +* Fix crash reading unaligned float4 column in GeomVertexReader +* Fixes for switching to fullscreen at runtime on Windows and Linux +* Fix incorrect display mode listing in some Linux distributions +* Fix threading crash on Linux when using get_keyboard_map() +* Support "from __future__ import division" for Panda types +* Support building with Visual Studio 2019 in makepanda +* Work around Assimp crash when loading multiple .ply models +* On Windows, a Python 3-compatible version of Pmw is included +* Fix ParticlePanel spam when hovering over File menu items +* TexMemWatcher has been fixed for Python 3 +* Prevent macOS window getting stuck after base.destroy() +* Fix assertion setting mass before shape with Bullet debug build +* Don't error if DirectScrolledFrame is destroyed twice +* Fix reference count corruption accessing task.__dict__ +* Fix writing to SequenceNode frame_rate property +* Fix collider sort not copied when copying CollisionNode +* Add OpenCollective backer file + ------------------------ RELEASE 1.10.1 ----------------------- This is a bugfix release intended to fix several issues in 1.10.0. From 3f97c3534e5eb4e490f97c4c00d0ab58a27fd239 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 10 Mar 2019 20:46:13 +0100 Subject: [PATCH 143/144] doc: fix typo in release notes [skip ci] --- doc/ReleaseNotes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index b9a1150731..41d69d7f99 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -1,7 +1,7 @@ ------------------------ RELEASE 1.10.2 ----------------------- This release fixes several more bugs, including a few regressions -in 1.10.2. Upgrading is highly recommended. +in 1.10.1. Upgrading is highly recommended. * Fix regression on Windows causing freezes and instability * Fix a memory leak issue in Python applications From 138e7f935f377a19bc458f3f0b179b3e3aac68e3 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 12 Mar 2019 01:50:20 -0600 Subject: [PATCH 144/144] collide: Fix missing includes --- panda/src/collide/collisionInvSphere.cxx | 2 ++ panda/src/collide/collisionPolygon.cxx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/panda/src/collide/collisionInvSphere.cxx b/panda/src/collide/collisionInvSphere.cxx index 1428078d09..ada39574c3 100644 --- a/panda/src/collide/collisionInvSphere.cxx +++ b/panda/src/collide/collisionInvSphere.cxx @@ -12,7 +12,9 @@ */ #include "collisionInvSphere.h" + #include "collisionSphere.h" +#include "collisionCapsule.h" #include "collisionLine.h" #include "collisionRay.h" #include "collisionSegment.h" diff --git a/panda/src/collide/collisionPolygon.cxx b/panda/src/collide/collisionPolygon.cxx index 0c467c1d4c..c4f6b4e7bb 100644 --- a/panda/src/collide/collisionPolygon.cxx +++ b/panda/src/collide/collisionPolygon.cxx @@ -12,9 +12,11 @@ */ #include "collisionPolygon.h" + #include "collisionHandler.h" #include "collisionEntry.h" #include "collisionSphere.h" +#include "collisionCapsule.h" #include "collisionLine.h" #include "collisionRay.h" #include "collisionSegment.h"