diff --git a/.travis.yml b/.travis.yml index 3dd97b7000..f89aabe267 100644 --- a/.travis.yml +++ b/.travis.yml @@ -113,3 +113,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 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 a9de69e51b..314ed49ff5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ [![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) - + Panda3D ======= @@ -8,12 +10,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 +23,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-1/). +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 +42,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.php?version=devel&sdk). These are automatically kept up-to-date with the latest GitHub version of Panda. @@ -55,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.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.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 @@ -96,14 +105,14 @@ 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 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 @@ -126,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.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.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: @@ -135,9 +144,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 @@ -151,7 +159,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. @@ -222,3 +230,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) 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/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/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/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: 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) 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/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/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/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() diff --git a/direct/src/leveleditor/LevelEditorUIBase.py b/direct/src/leveleditor/LevelEditorUIBase.py index f457f838d6..33101dff22 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 @@ -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/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/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/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/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/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..6736311821 100755 --- a/direct/src/leveleditor/ProtoPaletteUI.py +++ b/direct/src/leveleditor/ProtoPaletteUI.py @@ -3,13 +3,13 @@ Defines ProtoPalette tree UI """ import wx import os -from pandac.PandaModules import * +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 c98cf8505c..66537fbbdf 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 @@ -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/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 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) 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 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. diff --git a/direct/src/showbase/FindCtaPaths.py b/direct/src/showbase/FindCtaPaths.py deleted file mode 100755 index 4832400b46..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/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): 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: 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/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) 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') 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 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): diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index 07139af55b..41d69d7f99 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -1,7 +1,60 @@ +------------------------ RELEASE 1.10.2 ----------------------- + +This release fixes several more bugs, including a few regressions +in 1.10.1. 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. + +* 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 * 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 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 +* 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 ----------------------- 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/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/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" 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/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..b61d314d61 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) != 0); } /** * */ 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..4b0e63a357 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.cxx +++ b/dtool/src/dtoolbase/mutexWin32Impl.cxx @@ -13,16 +13,412 @@ #include "selectThreadImpl.h" -#ifdef WIN32_VC +#if defined(WIN32_VC) && !defined(CPPPARSER) #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; + +// 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]); + } +} + +#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. + */ +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); +} + +/** + * 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. + */ +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_initially, +#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; + } + +#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) { + 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; + } +#endif // _WIN32_WINNT < 0x0600 +} + +/** + * 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..47f31a2e8f 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.h +++ b/dtool/src/dtoolbase/mutexWin32Impl.h @@ -24,16 +24,69 @@ #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(); MutexWin32Impl &operator = (const MutexWin32Impl ©) = delete; +public: + INLINE void lock(); + INLINE bool try_lock(); + INLINE void unlock(); + + static void init_lock_funcs(); + +private: +#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; +}; + +/** + * 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(); @@ -41,8 +94,6 @@ public: private: CRITICAL_SECTION _lock; - friend class ConditionVarWin32Impl; - friend class ConditionVarFullWin32Impl; }; #include "mutexWin32Impl.I" 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); 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 360dfcd9e4..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,24 +204,24 @@ record_alternate_name(TypeHandle type, const string &name) { } - _lock->unlock(); + _lock.unlock(); } #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) { - _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; 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(); 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 ca2ed7eb8d..bfcac69506 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; } @@ -1860,6 +1859,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 +1877,18 @@ 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, \"" << ClassName + << "." << methodNameFromCppName(fname, "", false) << "\")) {\n"; + out << " return nullptr;\n"; } else { out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; out << " return nullptr;\n"; @@ -1883,7 +1897,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"; @@ -4701,7 +4715,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 +4762,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" @@ -5980,7 +5994,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); } @@ -7526,6 +7544,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; } 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; 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. */ diff --git a/dtool/src/interrogatedb/py_wrappers.cxx b/dtool/src/interrogatedb/py_wrappers.cxx index 0b8a751cad..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) { @@ -1091,7 +1092,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 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; } 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 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/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; } 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 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(); } 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/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 diff --git a/makepanda/installpanda.py b/makepanda/installpanda.py index 7f9b79cd60..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() @@ -155,24 +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+"/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") @@ -184,7 +189,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 +242,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: 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/makepackage.py b/makepanda/makepackage.py index daf0877544..9b34192e94 100755 --- a/makepanda/makepackage.py +++ b/makepanda/makepackage.py @@ -5,6 +5,9 @@ from installpanda import * import sys import os import shutil +import glob +import re +import subprocess INSTALLER_DEB_FILE = """ @@ -438,7 +441,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) @@ -473,7 +477,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) @@ -834,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] @@ -856,19 +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 '.so.' in line: - dep = line.rpartition('.so.')[0] + '.so' - oscmd("patchelf --replace-needed %s %s %s" % (line, dep, target), True) - else: - dep = line + + # 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 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: @@ -957,21 +969,28 @@ 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. - 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)) # 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 dc0bded1f8..e7d12ce4d6 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' @@ -94,7 +93,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 @@ -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))") @@ -159,7 +157,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:") @@ -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,6 +176,7 @@ def parseopts(args): # Options for which to display a deprecation warning. removedopts = [ "use-touchinput", "no-touchinput", "no-awesomium", "no-directscripts", + "no-carbon", "universal", ] # All recognized options. @@ -187,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()) @@ -220,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() @@ -302,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] @@ -432,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"): @@ -622,7 +585,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 +837,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"]) @@ -905,13 +863,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") @@ -938,7 +897,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. @@ -1351,9 +1309,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": @@ -1570,7 +1530,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 +1635,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 +1743,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" @@ -1871,9 +1831,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() @@ -2043,7 +2005,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: @@ -2124,10 +2089,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): @@ -2450,7 +2415,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 +3318,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') @@ -3402,7 +3365,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') @@ -4022,12 +3984,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) @@ -4875,26 +4837,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/ # @@ -5035,10 +4977,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']) @@ -5048,15 +4990,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']) @@ -5066,7 +5008,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/ @@ -5239,7 +5181,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') @@ -5247,14 +5189,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') @@ -5799,15 +5737,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/ # @@ -5825,7 +5754,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/ @@ -6072,7 +6001,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') @@ -6089,15 +6018,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') @@ -6482,18 +6402,11 @@ 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 + 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') @@ -6501,7 +6414,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') @@ -6525,7 +6438,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') @@ -6536,7 +6449,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') @@ -6546,7 +6459,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') @@ -6556,38 +6469,23 @@ 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('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]+ARCH_OPTS) + TargetAdd('egg2maya'+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('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('egg2maya'+VNUM+'.exe', opts=['ADVAPI']) # # DIRECTORY: contrib/src/ai/ @@ -6645,7 +6543,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') diff --git a/makepanda/makepanda.vcproj b/makepanda/makepanda.vcproj index 03324fb60e..785061eea8 100644 --- a/makepanda/makepanda.vcproj +++ b/makepanda/makepanda.vcproj @@ -1619,7 +1619,6 @@ - @@ -1627,13 +1626,11 @@ - - @@ -1675,12 +1672,10 @@ - - @@ -2211,7 +2206,6 @@ - @@ -2220,10 +2214,8 @@ - - @@ -3506,20 +3498,6 @@ - - - - - - - - - - - - - - @@ -4591,17 +4569,6 @@ - - - - - - - - - - - @@ -4769,11 +4736,9 @@ - - @@ -4939,11 +4904,9 @@ - - diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 8790538395..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"}, } ######################################################################## @@ -564,11 +565,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 +578,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 +589,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))) @@ -1091,9 +1105,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: @@ -2463,22 +2487,46 @@ 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!') + # 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') - 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)) + # 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): + exit('Cannot find %s. Please install Android SDK and set ANDROID_SDK_ROOT or ANDROID_HOME.' % (sdk_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 +2575,44 @@ 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') + 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 = [] + 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)) + + # 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 ######################################################################## ## @@ -2793,6 +2878,13 @@ 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 "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() @@ -2844,8 +2936,22 @@ 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() + sysroot_flag + " -x c++ -v -E /dev/null" + cmd = GetCXX() + " -x c++ -v -E " + os.devnull + if "ANDROID_NDK" in SDK: + 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 + null = open(os.devnull, 'w') handle = subprocess.Popen(cmd, stdout=null, stderr=subprocess.PIPE, shell=True) scanning = False @@ -2858,8 +2964,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)"): diff --git a/makepanda/makewheel.py b/makepanda/makewheel.py index 18f92379b8..fea29bd17f 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. @@ -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 @@ -526,11 +552,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"] @@ -549,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] 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 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/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 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); } 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; 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; /** * 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/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()); 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; } 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 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/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/collisionInvSphere.cxx b/panda/src/collide/collisionInvSphere.cxx index 8a75135e55..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" @@ -288,6 +290,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(); 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) { } diff --git a/panda/src/collide/collisionPolygon.cxx b/panda/src/collide/collisionPolygon.cxx index 24c8230d2f..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" @@ -842,6 +844,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. @@ -1335,37 +1473,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..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(); @@ -131,7 +133,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; diff --git a/panda/src/device/evdevInputDevice.cxx b/panda/src/device/evdevInputDevice.cxx index b137888d6d..4ebbc55498 100644 --- a/panda/src/device/evdevInputDevice.cxx +++ b/panda/src/device/evdevInputDevice.cxx @@ -82,8 +82,10 @@ 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}, + // 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 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.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) { 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/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/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index 95f73549dd..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(); + } } } @@ -289,8 +247,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; @@ -391,6 +349,119 @@ 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() { +} + +/** + * 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); + } +} + /** * Implementation of the message loop. */ @@ -429,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 6c3fefd8c1..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; @@ -52,9 +55,11 @@ 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 (*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..583ad920da 100644 --- a/panda/src/device/winRawInputDevice.cxx +++ b/panda/src/device/winRawInputDevice.cxx @@ -14,156 +14,56 @@ #include "winRawInputDevice.h" #include "gamepadButton.h" #include "mouseButton.h" +#include "buttonRegistry.h" #if defined(_WIN32) && !defined(CPPPARSER) #include #include +#include "phidsdi.h" -// Copy definitions from hidusage.h, until we can drop support for the 7.1 SDK -typedef USHORT USAGE, *PUSAGE; +enum QuirkBits : int { + // Has no trigger axes. + QB_no_analog_triggers = 1, -#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) + // Throttle goes from -1 to 1 rather than from 0 to 1. + QB_centered_throttle = 2, -#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) + // Throttle is reversed. + QB_reversed_throttle = 4, +}; -#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) +// 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}, +}; -// 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 (*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); +// 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; @@ -246,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; @@ -264,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; @@ -273,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 && @@ -306,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) { @@ -342,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); @@ -414,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 @@ -429,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) { @@ -491,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; @@ -530,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); @@ -555,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; @@ -580,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 { 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.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; 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/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index ae1052ba1d..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 @@ -593,7 +594,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); @@ -1309,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(); } @@ -1546,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]; @@ -1572,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 @@ -1598,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); + } } /** @@ -2009,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/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 93a3f36651..5ca7e6bc32 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); } @@ -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()); } 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..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() && !in.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() && !in.eof() && ch != ']') { + while (!in.fail() && 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..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() && !in.eof() && ch != '"') { + while (!in.fail() && 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/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/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.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 */ 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/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/asyncFuture.h b/panda/src/event/asyncFuture.h index 27cab7b585..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 @@ -55,6 +54,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/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; } /** 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/event/pythonTask.cxx b/panda/src/event/pythonTask.cxx index 554e1368e7..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); } /** @@ -598,7 +595,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()) { 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__(); 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/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/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/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index ebb038de7a..bdeb26345f 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,18 @@ 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 if (_fb_properties.get_float_color()) { + gl_format = GL_RGBA32F_ARB; + } else { + gl_format = GL_RGBA; + } break; } #endif 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 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/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; 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); 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/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/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/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.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/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/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 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; 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 216efe10d9..0000000000 Binary files a/panda/src/osxdisplay/resize_box.rgb and /dev/null differ 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/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/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. 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/pgraph/paramNodePath.I b/panda/src/pgraph/paramNodePath.I index 89d6a9e67b..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(). */ @@ -40,7 +22,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.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 bd0967d5f8..63798cc4a8 100644 --- a/panda/src/pgraph/paramNodePath.h +++ b/panda/src/pgraph/paramNodePath.h @@ -26,11 +26,11 @@ 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 const NodePath &get_value() const; + INLINE NodePath get_value() const; virtual void output(std::ostream &out) const; diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 9bac4e666a..4abde672dd 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; @@ -45,8 +45,6 @@ RenderAttrib() { */ RenderAttrib:: ~RenderAttrib() { - LightReMutexHolder holder(*_attribs_lock); - // unref() should have cleared this. nassertv(_saved_entry == -1); } @@ -156,11 +154,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 +166,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 +180,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 +208,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 +232,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 +253,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 +271,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 +350,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 +372,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 +489,7 @@ release_new() { if (_saved_entry != -1) { _saved_entry = -1; - nassertv_always(_attribs->remove(this)); + nassertv_always(_attribs.remove(this)); } } @@ -508,8 +502,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/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() { diff --git a/panda/src/pgraph/shaderAttrib.cxx b/panda/src/pgraph/shaderAttrib.cxx index e519289b28..24b245b218 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 @@ -291,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 6cd04c6d99..29b535ff8a 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); @@ -113,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; 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, 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/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/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; diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index 16a7483478..5065a9c054 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() { @@ -580,9 +582,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; @@ -614,14 +616,16 @@ 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() { 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(); } @@ -745,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) { @@ -825,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"; @@ -850,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"; @@ -865,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; @@ -942,9 +959,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. @@ -954,7 +968,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"; @@ -962,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) { @@ -972,6 +988,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 @@ -991,7 +1018,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) { @@ -1016,9 +1043,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"; @@ -1032,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"; @@ -1074,6 +1105,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"; @@ -1098,7 +1135,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"; @@ -1195,7 +1232,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. @@ -1214,8 +1251,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) { @@ -1247,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"; @@ -1638,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); 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/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 bbf9ce0d22..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,18 +154,15 @@ 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:: 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 +170,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"; } @@ -185,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 746991e79c..0000000000 --- a/panda/src/pipeline/conditionVarFullDebug.cxx +++ /dev/null @@ -1,230 +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(); - - Thread *current_thread = Thread::get_current_thread(); - - if (!_mutex.do_debug_is_locked()) { - 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_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(); - - Thread *current_thread = Thread::get_current_thread(); - - if (!_mutex.do_debug_is_locked()) { - 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_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 386a9d5784..0000000000 --- a/panda/src/pipeline/conditionVarFullWin32Impl.I +++ /dev/null @@ -1,119 +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) { - _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; -} - -/** - * - */ -INLINE ConditionVarFullWin32Impl:: -~ConditionVarFullWin32Impl() { - CloseHandle(_event_signal); - CloseHandle(_event_broadcast); -} - -/** - * - */ -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); -} - -/** - * - */ -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); -} - -/** - * - */ -INLINE void ConditionVarFullWin32Impl:: -notify() { - bool have_waiters = AtomicAdjust::get(_waiters_count) > 0; - - if (have_waiters) { - SetEvent(_event_signal); - } -} - -/** - * - */ -INLINE void ConditionVarFullWin32Impl:: -notify_all() { - bool have_waiters = AtomicAdjust::get(_waiters_count) > 0; - - if (have_waiters) { - SetEvent(_event_broadcast); - } -} 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 a42d4d86a8..0000000000 --- a/panda/src/pipeline/conditionVarFullWin32Impl.h +++ /dev/null @@ -1,63 +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: - CRITICAL_SECTION *_external_mutex; - HANDLE _event_signal; - HANDLE _event_broadcast; - TVOLATILE AtomicAdjust::Integer _waiters_count; -}; - -#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 5994c638d5..7f2b24a079 100644 --- a/panda/src/pipeline/conditionVarWin32Impl.I +++ b/panda/src/pipeline/conditionVarWin32Impl.I @@ -15,11 +15,7 @@ * */ INLINE ConditionVarWin32Impl:: -ConditionVarWin32Impl(MutexWin32Impl &mutex) { - _external_mutex = &mutex._lock; - - // Create an auto-reset event. - _event_signal = CreateEvent(nullptr, false, false, nullptr); +ConditionVarWin32Impl(MutexWin32Impl &mutex) : _mutex(mutex) { } /** @@ -27,7 +23,14 @@ ConditionVarWin32Impl(MutexWin32Impl &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]); + } } /** @@ -35,12 +38,7 @@ INLINE ConditionVarWin32Impl:: */ INLINE void ConditionVarWin32Impl:: wait() { - LeaveCriticalSection(_external_mutex); - - DWORD result = WaitForSingleObject(_event_signal, INFINITE); - nassertv(result == WAIT_OBJECT_0); - - EnterCriticalSection(_external_mutex); + MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, INFINITE, 0); } /** @@ -48,12 +46,7 @@ wait() { */ INLINE void ConditionVarWin32Impl:: wait(double timeout) { - LeaveCriticalSection(_external_mutex); - - DWORD result = WaitForSingleObject(_event_signal, (DWORD)(timeout * 1000.0)); - nassertv(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT); - - EnterCriticalSection(_external_mutex); + MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, (DWORD)(timeout * 1000.0), 0); } /** @@ -61,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 7ed6513d6e..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: - CRITICAL_SECTION *_external_mutex; - HANDLE _event_signal; + 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 "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; diff --git a/panda/src/pipeline/threadPosixImpl.cxx b/panda/src/pipeline/threadPosixImpl.cxx index 0d88c5ebe8..18e76cb8d2 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(); } /** @@ -180,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(); } 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/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 diff --git a/panda/src/putil/datagramInputFile.cxx b/panda/src/putil/datagramInputFile.cxx index c4802ceed2..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" @@ -109,7 +108,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 +129,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 +140,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 +181,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 +197,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 +227,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; } 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 { 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 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; 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 df038a6dad..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(); @@ -1976,6 +2019,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()) { 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(); diff --git a/pandatool/src/assimp/loaderFileTypeAssimp.cxx b/pandatool/src/assimp/loaderFileTypeAssimp.cxx index 73c27ee7d4..f19ce58e2f 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() { } /** @@ -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); } 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; 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/flt/fltRecordReader.cxx b/pandatool/src/flt/fltRecordReader.cxx index c999001d64..eb3ba94840 100644 --- a/pandatool/src/flt/fltRecordReader.cxx +++ b/pandatool/src/flt/fltRecordReader.cxx @@ -131,20 +131,21 @@ 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); - } - _datagram = Datagram(buffer, length); - delete[] buffer; - - if (_in.eof()) { - _state = S_eof; - assert(!flt_error_abort); - return FE_end_of_file; + vector_uchar data((size_t)length); + _in.read((char *)&data[0], length); + _datagram = Datagram(std::move(data)); + } else { + _datagram = Datagram(); } 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; @@ -162,20 +163,20 @@ 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; - - if (_in.eof()) { - _state = S_eof; - assert(!flt_error_abort); - return FE_end_of_file; + _datagram.append_data(buffer, length); + delete[] buffer; } 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; @@ -221,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; } 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 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) { 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(); 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): diff --git a/setup.cfg b/setup.cfg index 8a1a50afe0..decaaeff15 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 @@ -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 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) 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 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/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() 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'