Browse Source

Merge branch 'release/1.10.x'

rdb 5 years ago
parent
commit
c59b91f503

+ 15 - 27
direct/src/dist/commands.py

@@ -396,27 +396,22 @@ class build_apps(setuptools.Command):
 
 
         self.announce('Gathering wheels for platform: {}'.format(platform), distutils.log.INFO)
         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
-
-        abi_tag = pep425tags.get_abi_tag()
+        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__))
 
 
-        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
         # 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'):
         if abi_tag in ('cp26m', 'cp27m', 'cp32m') and not platform.startswith('win') and not platform.startswith('macosx'):
             abi_tag += 'u'
             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
         # Remove any .zip files. These are built from a VCS and block for an
         # interactive prompt on subsequent downloads.
         # interactive prompt on subsequent downloads.
@@ -444,19 +439,12 @@ class build_apps(setuptools.Command):
 
 
         subprocess.check_call([sys.executable, '-m', 'pip'] + pip_args)
         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):
     def update_pe_resources(self, appname, runtime):
         """Update resources (e.g., icons) in windows PE file"""
         """Update resources (e.g., icons) in windows PE file"""

+ 1 - 1
dtool/src/dtoolutil/win32ArgParser.cxx

@@ -22,7 +22,7 @@
 #include "executionEnvironment.h"
 #include "executionEnvironment.h"
 
 
 #include <windows.h>
 #include <windows.h>
-#include <Tlhelp32.h>
+#include <tlhelp32.h>
 
 
 using std::string;
 using std::string;
 
 

+ 9 - 1
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
  * 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::
 bool TypeManager::
 is_reference_count(CPPType *type) {
 is_reference_count(CPPType *type) {
@@ -1459,6 +1459,14 @@ is_reference_count(CPPType *type) {
   case CPPDeclaration::ST_struct:
   case CPPDeclaration::ST_struct:
     {
     {
       CPPStructType *stype = type->as_struct_type();
       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;
       CPPStructType::Derivation::const_iterator di;
       for (di = stype->_derivation.begin();
       for (di = stype->_derivation.begin();
            di != stype->_derivation.end();
            di != stype->_derivation.end();

+ 14 - 0
makepanda/makepanda.py

@@ -397,6 +397,20 @@ elif target == 'linux' and (os.path.isfile("/lib/libc-2.5.so") or os.path.isfile
     else:
     else:
         PLATFORM = 'manylinux1-i686'
         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():
 elif not CrossCompiling():
     if HasTargetArch():
     if HasTargetArch():
         # Replace the architecture in the platform string.
         # Replace the architecture in the platform string.

+ 14 - 5
makepanda/makewheel.py

@@ -92,7 +92,7 @@ EXCLUDE_EXT = [".pyc", ".pyo", ".N", ".prebuilt", ".xcf", ".plist", ".vcproj", "
 # Plug-ins to install.
 # Plug-ins to install.
 PLUGIN_LIBS = ["pandagl", "pandagles", "pandagles2", "pandadx9", "p3tinydisplay", "p3ptloader", "p3assimp", "p3ffmpeg", "p3openal_audio", "p3fmod_audio"]
 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 = [
 MANYLINUX_LIBS = [
     "libgcc_s.so.1", "libstdc++.so.6", "libm.so.6", "libdl.so.2", "librt.so.1",
     "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",
     "libcrypt.so.1", "libc.so.6", "libnsl.so.1", "libutil.so.1",
@@ -530,10 +530,14 @@ def makewheel(version, output_dir, platform=None):
         else:
         else:
             print("Could not find platform.dat in build directory")
             print("Could not find platform.dat in build directory")
             platform = get_platform()
             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")
                     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('.', '_')
     platform = platform.replace('-', '_').replace('.', '_')
 
 
@@ -735,7 +739,12 @@ if __debug__:
         pylib_path = os.path.join(get_config_var('LIBDIR'), pylib_name)
         pylib_path = os.path.join(get_config_var('LIBDIR'), pylib_name)
     else:
     else:
         pylib_name = get_config_var('LDLIBRARY')
         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.write_file('deploy_libs/' + pylib_name, pylib_path)
 
 
     whl.close()
     whl.close()

+ 1 - 1
panda/src/device/winInputDeviceManager.h

@@ -20,7 +20,7 @@
 
 
 #include "xInputDevice.h"
 #include "xInputDevice.h"
 
 
-#include <CfgMgr32.h>
+#include <cfgmgr32.h>
 #include <devpkey.h>
 #include <devpkey.h>
 
 
 class WinRawInputDevice;
 class WinRawInputDevice;

+ 1 - 1
panda/src/device/winRawInputDevice.cxx

@@ -19,7 +19,7 @@
 
 
 #if defined(_WIN32) && !defined(CPPPARSER)
 #if defined(_WIN32) && !defined(CPPPARSER)
 
 
-#include <CfgMgr32.h>
+#include <cfgmgr32.h>
 #include <devpkey.h>
 #include <devpkey.h>
 #include "phidsdi.h"
 #include "phidsdi.h"
 
 

+ 2 - 2
panda/src/device/xInputDevice.cxx

@@ -19,8 +19,8 @@
 #include "inputDeviceManager.h"
 #include "inputDeviceManager.h"
 #include "string_utils.h"
 #include "string_utils.h"
 
 
-#include <XInput.h>
-#include <CfgMgr32.h>
+#include <xinput.h>
+#include <cfgmgr32.h>
 
 
 #ifndef XUSER_MAX_COUNT
 #ifndef XUSER_MAX_COUNT
 #define XUSER_MAX_COUNT 4
 #define XUSER_MAX_COUNT 4

+ 1 - 1
panda/src/device/xInputDevice.h

@@ -19,7 +19,7 @@
 
 
 #if defined(_WIN32) && !defined(CPPPARSER)
 #if defined(_WIN32) && !defined(CPPPARSER)
 
 
-#include <CfgMgr32.h>
+#include <cfgmgr32.h>
 
 
 class InputDeviceManager;
 class InputDeviceManager;
 
 

+ 1 - 1
panda/src/display/graphicsEngine.cxx

@@ -56,7 +56,7 @@
 
 
 #if defined(_WIN32)
 #if defined(_WIN32)
   #define WINDOWS_LEAN_AND_MEAN
   #define WINDOWS_LEAN_AND_MEAN
-  #include <WinSock2.h>
+  #include <winsock2.h>
   #include <wtypes.h>
   #include <wtypes.h>
   #undef WINDOWS_LEAN_AND_MEAN
   #undef WINDOWS_LEAN_AND_MEAN
 #else
 #else

+ 1 - 1
panda/src/downloader/bioStreamBuf.cxx

@@ -19,7 +19,7 @@
 #ifdef HAVE_OPENSSL
 #ifdef HAVE_OPENSSL
 
 
 #ifdef _WIN32
 #ifdef _WIN32
-  #include <WinSock2.h>
+  #include <winsock2.h>
   #include <windows.h>  // for WSAGetLastError()
   #include <windows.h>  // for WSAGetLastError()
   #undef X509_NAME
   #undef X509_NAME
 #endif  // _WIN32
 #endif  // _WIN32

+ 1 - 1
panda/src/downloader/httpChannel.cxx

@@ -30,7 +30,7 @@
 #include "openSSLWrapper.h"
 #include "openSSLWrapper.h"
 
 
 #ifdef _WIN32
 #ifdef _WIN32
-  #include <WinSock2.h>
+  #include <winsock2.h>
   #include <windows.h>  // for select()
   #include <windows.h>  // for select()
   #undef X509_NAME
   #undef X509_NAME
 #endif  // _WIN32
 #endif  // _WIN32

+ 1 - 1
panda/src/nativenet/socket_portable.h

@@ -53,7 +53,7 @@ typedef unsigned long SOCKET;
 ************************************************************************/
 ************************************************************************/
 #elif defined(_WIN32)
 #elif defined(_WIN32)
 #include <winsock2.h>
 #include <winsock2.h>
-#include <Ws2tcpip.h>
+#include <ws2tcpip.h>
 
 
 typedef u_short sa_family_t;
 typedef u_short sa_family_t;
 
 

+ 1 - 1
panda/src/net/connectionManager.cxx

@@ -25,7 +25,7 @@
 #if defined(CPPPARSER)
 #if defined(CPPPARSER)
 #elif defined(_WIN32)
 #elif defined(_WIN32)
 #include <winsock2.h>  // For gethostname()
 #include <winsock2.h>  // For gethostname()
-#include <Iphlpapi.h> // For GetAdaptersAddresses()
+#include <iphlpapi.h> // For GetAdaptersAddresses()
 #elif defined(__ANDROID__)
 #elif defined(__ANDROID__)
 #include <net/if.h>
 #include <net/if.h>
 #else
 #else

+ 94 - 44
panda/src/pgraph/cullableObject.cxx

@@ -223,29 +223,23 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
     return false;
     return false;
   }
   }
 
 
+  GeomVertexDataPipelineReader reader(source_data, current_thread);
+  reader.check_array_readers();
+
   PStatTimer timer(_munge_sprites_pcollector, current_thread);
   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();
   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_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_rotate = (rotate.has_column());
   bool has_size = (size.has_column());
   bool has_size = (size.has_column());
   bool has_aspect_ratio = (aspect_ratio.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);
     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);
     FormatMap::iterator fmi = _format_map.find(sformat);
     if (fmi != _format_map.end()) {
     if (fmi != _format_map.end()) {
       new_format = (*fmi).second;
       new_format = (*fmi).second;
@@ -304,13 +298,13 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
                                     Geom::C_clip_point);
                                     Geom::C_clip_point);
       }
       }
       if (has_normal) {
       if (has_normal) {
-        const GeomVertexColumn *c = normal.get_column();
+        const GeomVertexColumn *c = reader.get_format()->get_normal_column();
         new_array_format->add_column
         new_array_format->add_column
           (InternalName::get_normal(), c->get_num_components(),
           (InternalName::get_normal(), c->get_num_components(),
            c->get_numeric_type(), c->get_contents());
            c->get_numeric_type(), c->get_contents());
       }
       }
       if (has_color) {
       if (has_color) {
-        const GeomVertexColumn *c = color.get_column();
+        const GeomVertexColumn *c = reader.get_format()->get_color_column();
         new_array_format->add_column
         new_array_format->add_column
           (InternalName::get_color(), c->get_num_components(),
           (InternalName::get_color(), c->get_num_components(),
            c->get_numeric_type(), c->get_contents());
            c->get_numeric_type(), c->get_contents());
@@ -322,12 +316,34 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
            Geom::C_texcoord);
            Geom::C_texcoord);
 
 
       } else if (has_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
         new_array_format->add_column
           (InternalName::get_texcoord(), c->get_num_components(),
           (InternalName::get_texcoord(), c->get_num_components(),
            c->get_numeric_type(), c->get_contents());
            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);
       new_format = GeomVertexFormat::register_format(new_array_format);
       _format_map[sformat] = new_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
   // Now convert all of the vertices in the GeomVertexData to quads.  We
   // always convert all the vertices, assuming all the vertices are referenced
   // always convert all the vertices, assuming all the vertices are referenced
   // by GeomPrimitives, because we want to optimize for the most common case.
   // 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.
   int new_verts = 4 * orig_verts;        // each vertex becomes four.
 
 
   PT(GeomVertexData) new_data = new GeomVertexData
   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_vertex(new_data, InternalName::get_vertex());
   GeomVertexWriter new_normal(new_data, InternalName::get_normal());
   GeomVertexWriter new_normal(new_data, InternalName::get_normal());
-  GeomVertexWriter new_color(new_data, InternalName::get_color());
   GeomVertexWriter new_texcoord(new_data, InternalName::get_texcoord());
   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<CopyOp> 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
   // 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
   // their distance from the camera, so we can sort the points for each
   // primitive, below.
   // 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] - 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])));
         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 {
       } else {
         // Without retransform_sprites, we can simply load the clip-space
         // Without retransform_sprites, we can simply load the clip-space
         // coordinates.
         // 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]);
         new_vertex.set_data4(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3]);
 
 
         if (has_normal) {
         if (has_normal) {
+          // We need to transform the normals to clip-space too, then.
           LNormal c = render_transform.xform_vec(normal.get_data3());
           LNormal c = render_transform.xform_vec(normal.get_data3());
           new_normal.set_data3(c);
           new_normal.set_data3(c);
           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);
           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) {
       if (sprite_texcoord) {
         new_texcoord.set_data2(1.0f, 0.0f);
         new_texcoord.set_data2(1.0f, 0.0f);
         new_texcoord.set_data2(0.0f, 0.0f);
         new_texcoord.set_data2(0.0f, 0.0f);
         new_texcoord.set_data2(1.0f, 1.0f);
         new_texcoord.set_data2(1.0f, 1.0f);
         new_texcoord.set_data2(0.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 &copy : 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;
       ++vi;

+ 1 - 1
panda/src/pstatclient/pStatClientImpl.cxx

@@ -28,7 +28,7 @@
 #include <algorithm>
 #include <algorithm>
 
 
 #ifdef _WIN32
 #ifdef _WIN32
-#include <Winsock2.h>
+#include <winsock2.h>
 #include <windows.h>
 #include <windows.h>
 #endif
 #endif
 
 

+ 29 - 2
panda/src/x11display/x11GraphicsWindow.cxx

@@ -2038,6 +2038,13 @@ get_keyboard_map() const {
   LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
   LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
 
 
   for (int k = 9; k <= 135; ++k) {
   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);
     ButtonHandle raw_button = map_raw_button(k);
     if (raw_button == ButtonHandle::none()) {
     if (raw_button == ButtonHandle::none()) {
       continue;
       continue;
@@ -2045,11 +2052,31 @@ get_keyboard_map() const {
 
 
     KeySym sym = XkbKeycodeToKeysym(_display, k, 0, 0);
     KeySym sym = XkbKeycodeToKeysym(_display, k, 0, 0);
     ButtonHandle button = map_button(sym);
     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;
       continue;
     }
     }
 
 
-    map->map_button(raw_button, button);
+    map->map_button(raw_button, button, label);
   }
   }
 
 
   return map;
   return map;