From 391578ea1f64d1930be37fae3d2547020eac639c Mon Sep 17 00:00:00 2001 From: Mitchell Stokes Date: Sun, 9 Feb 2020 16:52:05 -0800 Subject: [PATCH 1/9] build_apps: Fix running with Pip 20 Fixes #854 Closes #856 --- direct/src/dist/commands.py | 42 +++++++++++++------------------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/direct/src/dist/commands.py b/direct/src/dist/commands.py index c9682bc864..78d4cde5a5 100644 --- a/direct/src/dist/commands.py +++ b/direct/src/dist/commands.py @@ -399,27 +399,22 @@ class build_apps(setuptools.Command): self.announce('Gathering wheels for platform: {}'.format(platform), distutils.log.INFO) - whldir = os.path.join(self.build_base, '__whl_cache__') + whlcache = os.path.join(self.build_base, '__whl_cache__') - #TODO find a better way to get abi tag than from internal/private pip APIs - if hasattr(pip, 'pep425tags'): - pep425tags = pip.pep425tags - wheel = pip.wheel - else: - from pip._internal import pep425tags, wheel + pip_version = int(pip.__version__.split('.')[0]) + if pip_version < 9: + raise RuntimeError("pip 9.0 or greater is required, but found {}".format(pip.__version__)) - abi_tag = pep425tags.get_abi_tag() - - if 'u' in abi_tag and (platform.startswith('win') or platform.startswith('macosx')): - abi_tag = abi_tag.replace('u', '') + abi_tag = 'cp%d%d' % (sys.version_info[:2]) + if sys.version_info < (3, 8): + abi_tag += 'm' # For these distributions, we need to append 'u' on Linux if abi_tag in ('cp26m', 'cp27m', 'cp32m') and not platform.startswith('win') and not platform.startswith('macosx'): abi_tag += 'u' - pip_version = pip.__version__.split('.') - if int(pip_version[0]) < 9: - raise RuntimeError("pip 9.0 or greater is required, but found {}".format(pip.__version__)) + whldir = os.path.join(whlcache, '_'.join((platform, abi_tag))) + os.makedirs(whldir, exist_ok=True) # Remove any .zip files. These are built from a VCS and block for an # interactive prompt on subsequent downloads. @@ -447,19 +442,12 @@ class build_apps(setuptools.Command): subprocess.check_call([sys.executable, '-m', 'pip'] + pip_args) - # Now figure out which of the downloaded wheels are relevant to us. - tags = pep425tags.get_supported(platform=platform, abi=abi_tag) - wheelpaths = [] - for filename in os.listdir(whldir): - try: - whl = wheel.Wheel(filename) - except wheel.InvalidWheelFilename: - continue - - if whl.supported(tags): - wheelpaths.append(os.path.join(whldir, filename)) - - return wheelpaths + # Return a list of paths to the downloaded whls + return [ + os.path.join(whldir, filename) + for filename in os.listdir(whldir) + if filename.endswith('.whl') + ] def update_pe_resources(self, appname, runtime): """Update resources (e.g., icons) in windows PE file""" From 4ef8e5228e3011acea61f7ad1d29d3273e883f0c Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 22 Feb 2020 12:08:03 +0100 Subject: [PATCH 2/9] interrogate: fix ability to return ReferenceCount-like classes Classes with virtual ref(), unref() and get_ref_count() methods, like RecorderBase, could not be returned by PT() from methods because they didn't inherit from ReferenceCount. However, classes do not need to inherit ReferenceCount to be able to be tracked by a PointerTo, and defining an abstract base class with pure virtual ref()/unref()/get_ref_count() is a way to avoid dual inheritance of ReferenceCount. --- dtool/src/interrogate/typeManager.cxx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dtool/src/interrogate/typeManager.cxx b/dtool/src/interrogate/typeManager.cxx index ab1fbffce3..dba10f4520 100644 --- a/dtool/src/interrogate/typeManager.cxx +++ b/dtool/src/interrogate/typeManager.cxx @@ -1442,7 +1442,7 @@ is_void(CPPType *type) { /** * Returns true if the indicated type is some class that derives from - * ReferenceCount, or false otherwise. + * ReferenceCount, or defines ref and unref(), or false otherwise. */ bool TypeManager:: is_reference_count(CPPType *type) { @@ -1459,6 +1459,14 @@ is_reference_count(CPPType *type) { case CPPDeclaration::ST_struct: { CPPStructType *stype = type->as_struct_type(); + + // If we have methods named ref() and unref(), this is good enough. + if (stype->_scope->_functions.count("ref") && + stype->_scope->_functions.count("unref") && + stype->_scope->_functions.count("get_ref_count")) { + return true; + } + CPPStructType::Derivation::const_iterator di; for (di = stype->_derivation.begin(); di != stype->_derivation.end(); From 8ff2064fe553e276a4662a1d47b317f469a81aa3 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 22 Feb 2020 12:10:06 +0100 Subject: [PATCH 3/9] makepanda: auto-detect manylinux2010 and manylinux2014 platforms --- makepanda/makepanda.py | 14 ++++++++++++++ makepanda/makewheel.py | 12 ++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 39cffbd924..4af9d6402b 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -459,6 +459,20 @@ elif target == 'linux' and (os.path.isfile("/lib/libc-2.5.so") or os.path.isfile else: PLATFORM = 'manylinux1-i686' +elif target == 'linux' and (os.path.isfile("/lib/libc-2.12.so") or os.path.isfile("/lib64/libc-2.12.so")) and os.path.isdir("/opt/python"): + # Same sloppy check for manylinux2010. + if GetTargetArch() in ('x86_64', 'amd64'): + PLATFORM = 'manylinux2010-x86_64' + else: + PLATFORM = 'manylinux2010-i686' + +elif target == 'linux' and (os.path.isfile("/lib/libc-2.17.so") or os.path.isfile("/lib64/libc-2.17.so")) and os.path.isdir("/opt/python"): + # Same sloppy check for manylinux2014. + if GetTargetArch() in ('x86_64', 'amd64'): + PLATFORM = 'manylinux2014-x86_64' + else: + PLATFORM = 'manylinux2014-i686' + elif not CrossCompiling(): if HasTargetArch(): # Replace the architecture in the platform string. diff --git a/makepanda/makewheel.py b/makepanda/makewheel.py index 1ba176116c..f4fce36de4 100644 --- a/makepanda/makewheel.py +++ b/makepanda/makewheel.py @@ -92,7 +92,7 @@ EXCLUDE_EXT = [".pyc", ".pyo", ".N", ".prebuilt", ".xcf", ".plist", ".vcproj", " # Plug-ins to install. PLUGIN_LIBS = ["pandagl", "pandagles", "pandagles2", "pandadx9", "p3tinydisplay", "p3ptloader", "p3assimp", "p3ffmpeg", "p3openal_audio", "p3fmod_audio"] -# Libraries included in manylinux ABI that should be ignored. See PEP 513/571. +# Libraries included in manylinux ABI that should be ignored. See PEP 513/571/599. MANYLINUX_LIBS = [ "libgcc_s.so.1", "libstdc++.so.6", "libm.so.6", "libdl.so.2", "librt.so.1", "libcrypt.so.1", "libc.so.6", "libnsl.so.1", "libutil.so.1", @@ -530,10 +530,14 @@ def makewheel(version, output_dir, platform=None): else: print("Could not find platform.dat in build directory") platform = get_platform() - if platform.startswith("linux-"): - # Is this manylinux1? - if os.path.isfile("/lib/libc-2.5.so") and os.path.isdir("/opt/python"): + if platform.startswith("linux-") and os.path.isdir("/opt/python"): + # Is this manylinux? + if os.path.isfile("/lib/libc-2.5.so") or os.path.isfile("/lib64/libc-2.5.so"): platform = platform.replace("linux", "manylinux1") + elif os.path.isfile("/lib/libc-2.12.so") or os.path.isfile("/lib64/libc-2.12.so"): + platform = platform.replace("linux", "manylinux2010") + elif os.path.isfile("/lib/libc-2.17.so") or os.path.isfile("/lib64/libc-2.17.so"): + platform = platform.replace("linux", "manylinux2014") platform = platform.replace('-', '_').replace('.', '_') From c2866ea4edae129edebc5b8438f81fe2688651a1 Mon Sep 17 00:00:00 2001 From: kamgha Date: Sat, 22 Feb 2020 12:55:45 +0100 Subject: [PATCH 4/9] Fix includes for Windows on case-sensitive filesystems Closes #866 --- dtool/src/dtoolutil/win32ArgParser.cxx | 2 +- panda/src/device/winInputDeviceManager.h | 2 +- panda/src/device/winRawInputDevice.cxx | 2 +- panda/src/device/xInputDevice.cxx | 4 ++-- panda/src/device/xInputDevice.h | 2 +- panda/src/display/graphicsEngine.cxx | 2 +- panda/src/downloader/bioStreamBuf.cxx | 2 +- panda/src/downloader/httpChannel.cxx | 2 +- panda/src/nativenet/socket_portable.h | 2 +- panda/src/net/connectionManager.cxx | 2 +- panda/src/pstatclient/pStatClientImpl.cxx | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dtool/src/dtoolutil/win32ArgParser.cxx b/dtool/src/dtoolutil/win32ArgParser.cxx index 4faf6bff95..81fb6ba7e9 100644 --- a/dtool/src/dtoolutil/win32ArgParser.cxx +++ b/dtool/src/dtoolutil/win32ArgParser.cxx @@ -22,7 +22,7 @@ #include "executionEnvironment.h" #include -#include +#include using std::string; diff --git a/panda/src/device/winInputDeviceManager.h b/panda/src/device/winInputDeviceManager.h index 13cab3d7c0..e98a42a0bb 100644 --- a/panda/src/device/winInputDeviceManager.h +++ b/panda/src/device/winInputDeviceManager.h @@ -20,7 +20,7 @@ #include "xInputDevice.h" -#include +#include #include class WinRawInputDevice; diff --git a/panda/src/device/winRawInputDevice.cxx b/panda/src/device/winRawInputDevice.cxx index 9411ad508b..010766edf0 100644 --- a/panda/src/device/winRawInputDevice.cxx +++ b/panda/src/device/winRawInputDevice.cxx @@ -19,7 +19,7 @@ #if defined(_WIN32) && !defined(CPPPARSER) -#include +#include #include #include "phidsdi.h" diff --git a/panda/src/device/xInputDevice.cxx b/panda/src/device/xInputDevice.cxx index b86a5cd90b..e59a937f20 100644 --- a/panda/src/device/xInputDevice.cxx +++ b/panda/src/device/xInputDevice.cxx @@ -19,8 +19,8 @@ #include "inputDeviceManager.h" #include "string_utils.h" -#include -#include +#include +#include #ifndef XUSER_MAX_COUNT #define XUSER_MAX_COUNT 4 diff --git a/panda/src/device/xInputDevice.h b/panda/src/device/xInputDevice.h index 2088c19182..c4a1f58d27 100644 --- a/panda/src/device/xInputDevice.h +++ b/panda/src/device/xInputDevice.h @@ -19,7 +19,7 @@ #if defined(_WIN32) && !defined(CPPPARSER) -#include +#include class InputDeviceManager; diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index c7951ee95a..b900dc26e6 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -55,7 +55,7 @@ #if defined(WIN32) #define WINDOWS_LEAN_AND_MEAN - #include + #include #include #undef WINDOWS_LEAN_AND_MEAN #else diff --git a/panda/src/downloader/bioStreamBuf.cxx b/panda/src/downloader/bioStreamBuf.cxx index 1598b15259..33782df154 100644 --- a/panda/src/downloader/bioStreamBuf.cxx +++ b/panda/src/downloader/bioStreamBuf.cxx @@ -19,7 +19,7 @@ #ifdef HAVE_OPENSSL #if defined(WIN32_VC) || defined(WIN64_VC) - #include + #include #include // for WSAGetLastError() #undef X509_NAME #endif // WIN32_VC diff --git a/panda/src/downloader/httpChannel.cxx b/panda/src/downloader/httpChannel.cxx index 365c819b0f..679cb6f6de 100644 --- a/panda/src/downloader/httpChannel.cxx +++ b/panda/src/downloader/httpChannel.cxx @@ -30,7 +30,7 @@ #include "openSSLWrapper.h" #if defined(WIN32_VC) || defined(WIN64_VC) - #include + #include #include // for select() #undef X509_NAME #endif // WIN32_VC diff --git a/panda/src/nativenet/socket_portable.h b/panda/src/nativenet/socket_portable.h index a4a249f92e..2ac1c89248 100644 --- a/panda/src/nativenet/socket_portable.h +++ b/panda/src/nativenet/socket_portable.h @@ -53,7 +53,7 @@ typedef unsigned long SOCKET; ************************************************************************/ #elif defined(_WIN32) #include -#include +#include typedef u_short sa_family_t; diff --git a/panda/src/net/connectionManager.cxx b/panda/src/net/connectionManager.cxx index f125356f50..0a92cb1222 100644 --- a/panda/src/net/connectionManager.cxx +++ b/panda/src/net/connectionManager.cxx @@ -25,7 +25,7 @@ #if defined(CPPPARSER) #elif defined(WIN32_VC) || defined(WIN64_VC) #include // For gethostname() -#include // For GetAdaptersAddresses() +#include // For GetAdaptersAddresses() #elif defined(__ANDROID__) #include #else diff --git a/panda/src/pstatclient/pStatClientImpl.cxx b/panda/src/pstatclient/pStatClientImpl.cxx index d607a53bd9..ffdd5e2362 100644 --- a/panda/src/pstatclient/pStatClientImpl.cxx +++ b/panda/src/pstatclient/pStatClientImpl.cxx @@ -28,7 +28,7 @@ #include #if defined(WIN32_VC) || defined(WIN64_VC) -#include +#include #include #endif From f1af6c80ffd25434ae5282baf2c80661501d84e3 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 22 Feb 2020 14:43:38 +0100 Subject: [PATCH 5/9] test_wheel: fix for Python 3.4 [skip ci] --- makepanda/test_wheel.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/makepanda/test_wheel.py b/makepanda/test_wheel.py index d3f936ec68..73e4bb8e13 100755 --- a/makepanda/test_wheel.py +++ b/makepanda/test_wheel.py @@ -32,7 +32,11 @@ def test_wheel(wheel, verbose=False): python = os.path.join(envdir, "bin", "python") # Upgrade pip inside the environment too. - if subprocess.call([python, "-m", "pip", "install", "-U", "pip"]) != 0: + pip_pkg = "pip" + if sys.version_info[0:2] == (3, 4): + pip_pkg = "pip<19.2" + + if subprocess.call([python, "-m", "pip", "install", "-U", pip_pkg]) != 0: shutil.rmtree(envdir) sys.exit(1) From f57cd186bb0bc33e8ac7ec129ba6e8a80650eb9a Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 23 Feb 2020 10:20:38 +0100 Subject: [PATCH 6/9] makewheel: fix location of libpythonX.Y.so on Debian/Ubuntu --- makepanda/makewheel.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/makepanda/makewheel.py b/makepanda/makewheel.py index f4fce36de4..51948386b1 100644 --- a/makepanda/makewheel.py +++ b/makepanda/makewheel.py @@ -726,7 +726,12 @@ __version__ = '{0}' pylib_path = os.path.join(get_config_var('LIBDIR'), pylib_name) else: pylib_name = get_config_var('LDLIBRARY') - pylib_path = os.path.join(get_config_var('LIBDIR'), pylib_name) + pylib_arch = get_config_var('MULTIARCH') + libdir = get_config_var('LIBDIR') + if pylib_arch and os.path.exists(os.path.join(libdir, pylib_arch, pylib_name)): + pylib_path = os.path.join(libdir, pylib_arch, pylib_name) + else: + pylib_path = os.path.join(libdir, pylib_name) whl.write_file('deploy_libs/' + pylib_name, pylib_path) whl.close() From e2d6c4cb308ed1fed89d57a4bac746f4d692c2ed Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 23 Feb 2020 14:02:59 +0100 Subject: [PATCH 7/9] x11: don't include numpad keys in get_keyboard_map() This is a hack until we introduce separate ButtonHandles for numpad keys --- panda/src/x11display/x11GraphicsWindow.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index de58cd1028..1454346aa4 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -2000,6 +2000,13 @@ get_keyboard_map() const { LightReMutexHolder holder(x11GraphicsPipe::_x_mutex); for (int k = 9; k <= 135; ++k) { + if (k >= 78 && k <= 91) { + // Ignore numpad keys for now. These are not mapped to separate button + // handles in Panda, so we don't want their mappings to conflict with + // the regular numeric keys. + continue; + } + ButtonHandle raw_button = map_raw_button(k); if (raw_button == ButtonHandle::none()) { continue; From 54cf7b9a5da05f8da46ea410cf6d485acedf5046 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 23 Feb 2020 14:04:42 +0100 Subject: [PATCH 8/9] x11: add labels to various buttons returned from get_keyboard_map() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows identifying, eg. the é button on French keyboard (which is at the location where 2 is on QWERTY) This is not intended to be complete. One must still choose what to display depending on the label and the mapped button handle (if any). --- panda/src/x11display/x11GraphicsWindow.cxx | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index 1454346aa4..7dbd7c53dc 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -2014,11 +2014,31 @@ get_keyboard_map() const { KeySym sym = XkbKeycodeToKeysym(_display, k, 0, 0); ButtonHandle button = map_button(sym); - if (button == ButtonHandle::none()) { + std::string label; + + // Compose a label for some keys; I have not yet been able to find an API + // that does this effectively. + if (sym >= XK_a && sym <= XK_z) { + label = toupper((char)sym); + } + else if (sym >= XK_F1 && sym <= XK_F35) { + label = "F" + format_string(sym - XK_F1 + 1); + } + else if (sym >= XK_exclamdown && sym <= XK_ydiaeresis) { + // A latin-1 symbol. Translate this to the label. + char buffer[255]; + int nbytes = XkbTranslateKeySym(_display, &sym, 0, buffer, 255, 0); + if (nbytes > 0) { + label.assign(buffer, nbytes); + } + } + + if (button == ButtonHandle::none() && label.empty()) { + // No label and no mapping; this is useless. continue; } - map->map_button(raw_button, button); + map->map_button(raw_button, button, label); } return map; From 18bb8a5559f8db69283ca1505e1d047c9de4d2ab Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 23 Feb 2020 14:48:57 +0100 Subject: [PATCH 9/9] pgraph: fix for additional columns in munge_points_to_quads() Fixes #870 --- panda/src/pgraph/cullableObject.cxx | 138 +++++++++++++++++++--------- 1 file changed, 94 insertions(+), 44 deletions(-) diff --git a/panda/src/pgraph/cullableObject.cxx b/panda/src/pgraph/cullableObject.cxx index 920e524659..38f35f7024 100644 --- a/panda/src/pgraph/cullableObject.cxx +++ b/panda/src/pgraph/cullableObject.cxx @@ -223,29 +223,23 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) { return false; } + GeomVertexDataPipelineReader reader(source_data, current_thread); + reader.check_array_readers(); + PStatTimer timer(_munge_sprites_pcollector, current_thread); - _sw_sprites_pcollector.add_level(source_data->get_num_rows()); + _sw_sprites_pcollector.add_level(reader.get_num_rows()); GraphicsStateGuardianBase *gsg = traverser->get_gsg(); - GeomVertexReader vertex(source_data, InternalName::get_vertex(), - current_thread); - GeomVertexReader normal(source_data, InternalName::get_normal(), - current_thread); - GeomVertexReader color(source_data, InternalName::get_color(), - current_thread); - GeomVertexReader texcoord(source_data, InternalName::get_texcoord(), - current_thread); - GeomVertexReader rotate(source_data, InternalName::get_rotate(), - current_thread); - GeomVertexReader size(source_data, InternalName::get_size(), - current_thread); - GeomVertexReader aspect_ratio(source_data, InternalName::get_aspect_ratio(), - current_thread); + GeomVertexReader vertex(&reader, InternalName::get_vertex()); + GeomVertexReader normal(&reader, InternalName::get_normal()); + GeomVertexReader rotate(&reader, InternalName::get_rotate()); + GeomVertexReader size(&reader, InternalName::get_size()); + GeomVertexReader aspect_ratio(&reader, InternalName::get_aspect_ratio()); bool has_normal = (normal.has_column()); - bool has_color = (color.has_column()); - bool has_texcoord = (texcoord.has_column()); + bool has_color = (reader.has_column(InternalName::get_color())); + bool has_texcoord = (reader.has_column(InternalName::get_texcoord())); bool has_rotate = (rotate.has_column()); bool has_size = (size.has_column()); bool has_aspect_ratio = (aspect_ratio.has_column()); @@ -280,7 +274,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) { { LightMutexHolder holder(_format_lock); - SourceFormat sformat(source_data->get_format(), sprite_texcoord); + SourceFormat sformat(reader.get_format(), sprite_texcoord); FormatMap::iterator fmi = _format_map.find(sformat); if (fmi != _format_map.end()) { new_format = (*fmi).second; @@ -304,13 +298,13 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) { Geom::C_clip_point); } if (has_normal) { - const GeomVertexColumn *c = normal.get_column(); + const GeomVertexColumn *c = reader.get_format()->get_normal_column(); new_array_format->add_column (InternalName::get_normal(), c->get_num_components(), c->get_numeric_type(), c->get_contents()); } if (has_color) { - const GeomVertexColumn *c = color.get_column(); + const GeomVertexColumn *c = reader.get_format()->get_color_column(); new_array_format->add_column (InternalName::get_color(), c->get_num_components(), c->get_numeric_type(), c->get_contents()); @@ -322,12 +316,34 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) { Geom::C_texcoord); } else if (has_texcoord) { - const GeomVertexColumn *c = texcoord.get_column(); + const GeomVertexColumn *c = reader.get_format()->get_column(InternalName::get_texcoord()); new_array_format->add_column (InternalName::get_texcoord(), c->get_num_components(), c->get_numeric_type(), c->get_contents()); } + // Go through the other columns and copy them from the original. + for (size_t ai = 0; ai < sformat._format->get_num_arrays(); ++ai) { + const GeomVertexArrayFormat *aformat = sformat._format->get_array(ai); + + for (size_t ci = 0; ci < aformat->get_num_columns(); ++ci) { + const GeomVertexColumn *column = aformat->get_column(ci); + const InternalName *name = column->get_name(); + if (name != InternalName::get_vertex() && + name != InternalName::get_normal() && + name != InternalName::get_color() && + name != InternalName::get_texcoord() && + name != InternalName::get_rotate() && + name != InternalName::get_size() && + name != InternalName::get_aspect_ratio()) { + + new_array_format->add_column(name, + column->get_num_components(), column->get_numeric_type(), + column->get_contents()); + } + } + } + new_format = GeomVertexFormat::register_format(new_array_format); _format_map[sformat] = new_format; } @@ -362,7 +378,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) { // Now convert all of the vertices in the GeomVertexData to quads. We // always convert all the vertices, assuming all the vertices are referenced // by GeomPrimitives, because we want to optimize for the most common case. - int orig_verts = source_data->get_num_rows(); + int orig_verts = reader.get_num_rows(); int new_verts = 4 * orig_verts; // each vertex becomes four. PT(GeomVertexData) new_data = new GeomVertexData @@ -371,9 +387,50 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) { GeomVertexWriter new_vertex(new_data, InternalName::get_vertex()); GeomVertexWriter new_normal(new_data, InternalName::get_normal()); - GeomVertexWriter new_color(new_data, InternalName::get_color()); GeomVertexWriter new_texcoord(new_data, InternalName::get_texcoord()); + nassertr(new_vertex.has_column(), false); + unsigned char *write_ptr = new_vertex.get_array_handle()->get_write_pointer(); + + // Collect all other columns that we just need to copy the data of. + struct CopyOp { + unsigned char *_to_pointer; + const unsigned char *_from_pointer; + size_t _num_bytes; + size_t _from_stride; + }; + pvector copies; + + const GeomVertexArrayFormat *aformat = new_format->get_array(0); + for (size_t ci = 0; ci < aformat->get_num_columns(); ++ci) { + const GeomVertexColumn *column = aformat->get_column(ci); + const InternalName *name = column->get_name(); + if (name != InternalName::get_vertex() && + (retransform_sprites || name != InternalName::get_normal()) && + (!sprite_texcoord || name != InternalName::get_texcoord())) { + + int source_array; + const GeomVertexColumn *source_column; + if (reader.get_format()->get_array_info(name, source_array, source_column)) { + CopyOp copy; + copy._to_pointer = write_ptr + (size_t)column->get_start(); + copy._from_pointer = reader.get_array_reader(source_array)->get_read_pointer(true) + (size_t)source_column->get_start(); + copy._num_bytes = (size_t)column->get_total_bytes(); + copy._from_stride = reader.get_format()->get_array(source_array)->get_stride(); + + if (!copies.empty() && + (copy._to_pointer == copies.back()._to_pointer + copies.back()._num_bytes) && + (copy._from_pointer == copies.back()._from_pointer + copies.back()._num_bytes)) { + // Merge with previous. + copies.back()._num_bytes += copy._num_bytes; + } else { + copies.push_back(copy); + } + } + } + } + size_t to_stride = aformat->get_stride(); + // We'll keep an array of all of the points' eye-space coordinates, and // their distance from the camera, so we can sort the points for each // primitive, below. @@ -447,14 +504,6 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) { new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3]))); new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3]))); - if (has_normal) { - const LNormal &c = normal.get_data3(); - new_normal.set_data3(c); - new_normal.set_data3(c); - new_normal.set_data3(c); - new_normal.set_data3(c); - } - } else { // Without retransform_sprites, we can simply load the clip-space // coordinates. @@ -464,6 +513,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) { new_vertex.set_data4(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3]); if (has_normal) { + // We need to transform the normals to clip-space too, then. LNormal c = render_transform.xform_vec(normal.get_data3()); new_normal.set_data3(c); new_normal.set_data3(c); @@ -471,24 +521,24 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) { new_normal.set_data3(c); } } - if (has_color) { - const LColor &c = color.get_data4(); - new_color.set_data4(c); - new_color.set_data4(c); - new_color.set_data4(c); - new_color.set_data4(c); - } if (sprite_texcoord) { new_texcoord.set_data2(1.0f, 0.0f); new_texcoord.set_data2(0.0f, 0.0f); new_texcoord.set_data2(1.0f, 1.0f); new_texcoord.set_data2(0.0f, 1.0f); - } else if (has_texcoord) { - const LVecBase4 &c = texcoord.get_data4(); - new_texcoord.set_data4(c); - new_texcoord.set_data4(c); - new_texcoord.set_data4(c); - new_texcoord.set_data4(c); + } + + // Other columns are simply duplicated for each vertex. + for (CopyOp © : copies) { + memcpy(copy._to_pointer, copy._from_pointer, copy._num_bytes); + copy._to_pointer += to_stride; + memcpy(copy._to_pointer, copy._from_pointer, copy._num_bytes); + copy._to_pointer += to_stride; + memcpy(copy._to_pointer, copy._from_pointer, copy._num_bytes); + copy._to_pointer += to_stride; + memcpy(copy._to_pointer, copy._from_pointer, copy._num_bytes); + copy._to_pointer += to_stride; + copy._from_pointer += copy._from_stride; } ++vi;