Browse Source

Merge branch 'release/1.10.x'

rdb 5 years ago
parent
commit
ed397b3ab8

+ 3 - 3
direct/src/directtools/DirectSelection.py

@@ -529,7 +529,7 @@ class SelectionQueue(CollisionHandlerQueue):
             # Well, no way to tell.  Assume we're not backfacing.
             return 0
 
-        if direct:
+        if base.direct:
             cam = base.direct.cam
         else:
             cam = base.cam
@@ -602,7 +602,7 @@ class SelectionRay(SelectionQueue):
         if xy:
             mx = xy[0]
             my = xy[1]
-        elif direct:
+        elif base.direct:
             mx = base.direct.dr.mouseX
             my = base.direct.dr.mouseY
         else:
@@ -613,7 +613,7 @@ class SelectionRay(SelectionQueue):
             mx = base.mouseWatcherNode.getMouseX()
             my = base.mouseWatcherNode.getMouseY()
 
-        if direct:
+        if base.direct:
             self.collider.setFromLens(base.direct.camNode, mx, my)
         else:
             self.collider.setFromLens(base.camNode, mx, my)

+ 6 - 1
direct/src/showbase/VFSImporter.py

@@ -181,7 +181,12 @@ class VFSLoader:
         filename = Filename(self.filename)
         filename.setExtension('py')
         filename.setText()
-        return open(self.filename, self.desc[1]).read()
+
+        # Use the tokenize module to detect the encoding.
+        import tokenize
+        fh = open(self.filename, 'rb')
+        encoding, lines = tokenize.detect_encoding(fh.readline)
+        return (b''.join(lines) + fh.read()).decode(encoding)
 
     def _import_extension_module(self, fullname):
         """ Loads the binary shared object as a Python module, and

+ 2 - 0
dtool/src/dtoolbase/dtool_platform.h

@@ -39,6 +39,8 @@
 #define DTOOL_PLATFORM "osx_i386"
 #elif defined(__x86_64)
 #define DTOOL_PLATFORM "osx_amd64"
+#elif defined(__aarch64__)
+#define DTOOL_PLATFORM "osx_aarch64"
 #endif
 
 #elif defined(__FreeBSD__)

+ 6 - 6
makepanda/makepanda.py

@@ -87,7 +87,7 @@ PkgListSet(["PYTHON", "DIRECT",                        # Python support
   "ARTOOLKIT", "OPENCV", "DIRECTCAM", "VISION",        # Augmented Reality
   "GTK2",                                              # GTK2 is used for PStats on Unix
   "MFC", "WX", "FLTK",                                 # Used for web plug-in only
-  "COCOA",                                             # Mac OS X toolkits
+  "COCOA",                                             # macOS toolkits
   "X11",                                               # Unix platform support
   "PANDATOOL", "PVIEW", "DEPLOYTOOLS",                 # Toolchain
   "SKEL",                                              # Example SKEL project
@@ -132,7 +132,7 @@ def usage(problem):
     print("  --distributor X   (short string identifying the distributor of the build)")
     print("  --outputdir X     (use the specified directory instead of 'built')")
     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("  --osxtarget N     (the macOS version number to build for (macOS 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))")
@@ -939,7 +939,7 @@ if (COMPILER=="GCC"):
         if (PkgSkip(pkg)==0 and (pkg in SDK)):
             if (GetHost() == "darwin"):
                 # Sheesh, Autodesk really can't make up their mind
-                # regarding the location of the Maya devkit on OS X.
+                # regarding the location of the Maya devkit on macOS.
                 if (os.path.isdir(SDK[pkg] + "/Maya.app/Contents/lib")):
                     LibDirectory(pkg, SDK[pkg] + "/Maya.app/Contents/lib")
                 if (os.path.isdir(SDK[pkg] + "/Maya.app/Contents/MacOS")):
@@ -1480,7 +1480,7 @@ def CompileIgate(woutd,wsrc,opts):
         target_arch = GetTargetArch()
         if target_arch in ("x86_64", "amd64"):
             cmd += ' -D_LP64'
-        elif target_arch == 'aarch64':
+        elif target_arch in ('aarch64', 'arm64'):
             cmd += ' -D_LP64 -D__LP64__ -D__aarch64__'
         else:
             cmd += ' -D__i386__'
@@ -1766,7 +1766,7 @@ def CompileLink(dll, obj, opts):
         if (GetOrigExt(dll) == ".exe" and GetTarget() == 'windows' and "NOICON" not in opts):
             cmd += " " + GetOutputDir() + "/tmp/pandaIcon.res"
 
-        # Mac OS X specific flags.
+        # macOS specific flags.
         if GetTarget() == 'darwin':
             cmd += " -headerpad_max_install_names"
             if OSXTARGET is not None:
@@ -2012,7 +2012,7 @@ def FreezePy(target, inputs, opts):
 ##########################################################################################
 
 def CompileBundle(target, inputs, opts):
-    assert GetTarget() == "darwin", 'bundles can only be made for Mac OS X'
+    assert GetTarget() == "darwin", 'bundles can only be made for macOS'
     plist = None
     resources = []
     objects = []

+ 7 - 5
makepanda/makepandacore.py

@@ -40,7 +40,7 @@ DEBUG_DEPENDENCIES = False
 # Is the current Python a 32-bit or 64-bit build?  There doesn't
 # appear to be a universal test for this.
 if sys.platform == 'darwin':
-    # On OSX, platform.architecture reports '64bit' even if it is
+    # On macOS, platform.architecture reports '64bit' even if it is
     # currently running in 32-bit mode.  But sys.maxint is a reliable
     # indicator.
     host_64 = (sys.maxsize > 0x100000000)
@@ -365,11 +365,13 @@ def SetTarget(target, arch=None):
     elif target == 'darwin':
         if arch == 'amd64':
             arch = 'x86_64'
+        if arch == 'aarch64':
+            arch = 'arm64'
 
         if arch is not None:
-            choices = ('i386', 'x86_64', 'ppc', 'ppc64')
+            choices = ('i386', 'x86_64', 'ppc', 'ppc64', 'arm64')
             if arch not in choices:
-                exit('Mac OS X architecture must be one of %s' % (', '.join(choices)))
+                exit('macOS architecture must be one of %s' % (', '.join(choices)))
 
     elif target == 'android' or target.startswith('android-'):
         if arch is None:
@@ -1297,7 +1299,7 @@ def GetThirdpartyDir():
             THIRDPARTYDIR = base + "/win-libs-vc" + vc + "/"
 
     elif (target == 'darwin'):
-        # OSX thirdparty binaries are universal, where possible.
+        # macOS thirdparty binaries are universal, where possible.
         THIRDPARTYDIR = base + "/darwin-libs-a/"
 
     elif (target == 'linux'):
@@ -3002,7 +3004,7 @@ def SetupBuildEnvironment(compiler):
             dyldpath.insert(0, os.path.join(builtdir, 'lib'))
             os.environ["DYLD_LIBRARY_PATH"] = os.pathsep.join(dyldpath)
 
-            # OS X 10.11 removed DYLD_LIBRARY_PATH, but we still need to pass
+            # macOS 10.11 removed DYLD_LIBRARY_PATH, but we still need to pass
             # on our lib directory to ppackage, so add it to PATH instead.
             os.environ["PATH"] = os.path.join(builtdir, 'lib') + ':' + os.environ.get("PATH", "")
 

+ 2 - 1
makepanda/makewheel.py

@@ -381,7 +381,8 @@ class WheelFile(object):
             # On macOS, if no fat wheel was requested, extract the right architecture.
             if sys.platform == "darwin" and is_fat_file(source_path) \
                 and not self.platform.endswith("_intel") \
-                and "_fat" not in self.platform:
+                and "_fat" not in self.platform \
+                and "_universal" not in self.platform:
 
                 if self.platform.endswith("_x86_64"):
                     arch = 'x86_64'

+ 8 - 0
panda/src/bullet/bulletSoftBodyNode.cxx

@@ -187,14 +187,22 @@ transform_changed() {
 
     // Offset between current approx center and current initial transform
     btVector3 pos = LVecBase3_to_btVector3(this->do_get_aabb().get_approx_center());
+#if BT_BULLET_VERSION >= 290
+    btVector3 origin = _soft->getWorldTransform().getOrigin();
+#else
     btVector3 origin = _soft->m_initialWorldTransform.getOrigin();
+#endif
     btVector3 offset = pos - origin;
 
     // Subtract offset to get new transform for the body
     trans.setOrigin(trans.getOrigin() - offset);
 
     // Now apply the new transform
+#if BT_BULLET_VERSION >= 290
+    _soft->transform(_soft->getWorldTransform().inverse());
+#else
     _soft->transform(_soft->m_initialWorldTransform.inverse());
+#endif
     _soft->transform(trans);
 
     if (ts->has_scale()) {

+ 1 - 0
panda/src/pgraph/lightAttrib.I

@@ -42,6 +42,7 @@ get_num_non_ambient_lights() const {
  */
 INLINE NodePath LightAttrib::
 get_on_light(size_t n) const {
+  check_sorted();
   nassertr(n < _sorted_on_lights.size(), NodePath::fail());
   return _sorted_on_lights[n];
 }

+ 60 - 0
panda/src/pgraph/lightAttrib.cxx

@@ -443,6 +443,36 @@ remove_on_light(const NodePath &light) const {
   return return_new(attrib);
 }
 
+/**
+ * Returns a new LightAttrib, just like this one, but with the indicated light
+ * replaced with the given other light.
+ */
+CPT(RenderAttrib) LightAttrib::
+replace_on_light(const NodePath &source, const NodePath &dest) const {
+  if (source == dest) {
+    return this;
+  }
+
+  nassertr(!source.is_empty(), this);
+  Light *slobj = source.node()->as_light();
+  nassertr(slobj != nullptr, this);
+
+  nassertr(!dest.is_empty(), this);
+  Light *dlobj = dest.node()->as_light();
+  nassertr(dlobj != nullptr, this);
+
+  LightAttrib *attrib = new LightAttrib(*this);
+
+  auto it = attrib->_on_lights.find(source);
+  if (it != attrib->_on_lights.end()) {
+    dlobj->attrib_ref();
+    slobj->attrib_unref();
+
+    *it = dest;
+  }
+  return return_new(attrib);
+}
+
 /**
  * Returns a new LightAttrib, just like this one, but with the indicated light
  * added to the list of lights turned off by this attrib.
@@ -475,6 +505,36 @@ remove_off_light(const NodePath &light) const {
   return return_new(attrib);
 }
 
+/**
+ * Returns a new LightAttrib, just like this one, but with the indicated light
+ * replaced with the given other light.
+ */
+CPT(RenderAttrib) LightAttrib::
+replace_off_light(const NodePath &source, const NodePath &dest) const {
+  if (source == dest) {
+    return this;
+  }
+
+  nassertr(!source.is_empty(), this);
+  Light *slobj = source.node()->as_light();
+  nassertr(slobj != nullptr, this);
+
+  nassertr(!dest.is_empty(), this);
+  Light *dlobj = dest.node()->as_light();
+  nassertr(dlobj != nullptr, this);
+
+  LightAttrib *attrib = new LightAttrib(*this);
+
+  auto it = attrib->_off_lights.find(source);
+  if (it != attrib->_off_lights.end()) {
+    dlobj->attrib_ref();
+    slobj->attrib_unref();
+
+    *it = dest;
+  }
+  return return_new(attrib);
+}
+
 /**
  * Returns the most important light (that is, the light with the highest
  * priority) in the LightAttrib, excluding any ambient lights.  Returns an

+ 2 - 0
panda/src/pgraph/lightAttrib.h

@@ -85,8 +85,10 @@ PUBLISHED:
 
   CPT(RenderAttrib) add_on_light(const NodePath &light) const;
   CPT(RenderAttrib) remove_on_light(const NodePath &light) const;
+  CPT(RenderAttrib) replace_on_light(const NodePath &source, const NodePath &dest) const;
   CPT(RenderAttrib) add_off_light(const NodePath &light) const;
   CPT(RenderAttrib) remove_off_light(const NodePath &light) const;
+  CPT(RenderAttrib) replace_off_light(const NodePath &source, const NodePath &dest) const;
 
   NodePath get_most_important_light() const;
   LColor get_ambient_contribution() const;

+ 3 - 3
panda/src/pgraph/loader.cxx

@@ -292,7 +292,7 @@ try_load_file(const Filename &pathname, const LoaderOptions &options,
             << "Model " << pathname << " found in ModelPool.\n";
         }
         // But return a deep copy of the shared model.
-        node = node->copy_subgraph();
+        node = NodePath(node).copy_to(NodePath()).node();
       }
       return node;
     }
@@ -329,7 +329,7 @@ try_load_file(const Filename &pathname, const LoaderOptions &options,
             // from the RAM cached version.
             ModelPool::add_model(pathname, model_root);
             if ((options.get_flags() & LoaderOptions::LF_allow_instance) == 0) {
-              return model_root->copy_subgraph();
+              return NodePath(model_root).copy_to(NodePath()).node();
             }
           }
         }
@@ -398,7 +398,7 @@ try_load_file(const Filename &pathname, const LoaderOptions &options,
     // cached version.
     ModelPool::add_model(pathname, DCAST(ModelRoot, result.p()));
     if ((options.get_flags() & LoaderOptions::LF_allow_instance) == 0) {
-      result = result->copy_subgraph();
+      result = NodePath(result).copy_to(NodePath()).node();
     }
   }
 

+ 77 - 2
panda/src/pgraph/nodePath.cxx

@@ -539,12 +539,45 @@ copy_to(const NodePath &other, int sort, Thread *current_thread) const {
   nassertr(other._error_type == ET_ok, fail());
 
   PandaNode *source_node = node();
-  PT(PandaNode) copy_node = source_node->copy_subgraph(current_thread);
+  PandaNode::InstanceMap inst_map;
+  PT(PandaNode) copy_node = source_node->r_copy_subgraph(inst_map, current_thread);
   nassertr(copy_node != nullptr, fail());
 
   copy_node->reset_prev_transform(current_thread);
 
-  return other.attach_new_node(copy_node, sort, current_thread);
+  NodePath result = other.attach_new_node(copy_node, sort, current_thread);
+
+  // Temporary hack fix: if this root NodePath had lights applied that are
+  // located inside this subgraph, we need to fix them.
+  const RenderState *state = source_node->get_state();
+  const LightAttrib *lattr;
+  if (state->get_attrib(lattr)) {
+    CPT(LightAttrib) new_lattr = lattr;
+
+    for (size_t i = 0; i < lattr->get_num_off_lights(); ++i) {
+      NodePath light = lattr->get_off_light(i);
+      NodePath light2 = light;
+
+      if (light2.replace_copied_nodes(*this, result, inst_map, current_thread)) {
+        new_lattr = DCAST(LightAttrib, new_lattr->replace_off_light(light, light2));
+      }
+    }
+
+    for (size_t i = 0; i < lattr->get_num_on_lights(); ++i) {
+      NodePath light = lattr->get_on_light(i);
+      NodePath light2 = light;
+
+      if (light2.replace_copied_nodes(*this, result, inst_map, current_thread)) {
+        new_lattr = DCAST(LightAttrib, new_lattr->replace_on_light(light, light2));
+      }
+    }
+
+    if (new_lattr != lattr) {
+      result.set_state(state->set_attrib(std::move(new_lattr)));
+    }
+  }
+
+  return result;
 }
 
 /**
@@ -5803,6 +5836,48 @@ decode_from_bam_stream(vector_uchar data, BamReader *reader) {
   return result;
 }
 
+/**
+ * If the given root node is an ancestor of this NodePath, replaces all
+ * components below it using the given instance map.
+ *
+ * This is a helper method used by copy_to().
+ */
+bool NodePath::
+replace_copied_nodes(const NodePath &source, const NodePath &dest,
+                     const PandaNode::InstanceMap &inst_map,
+                     Thread *current_thread) {
+  nassertr(!dest.is_empty(), false);
+
+  int pipeline_stage = current_thread->get_pipeline_stage();
+
+  pvector<PandaNode *> nodes;
+
+  NodePathComponent *comp = _head;
+  while (comp != nullptr && comp != source._head) {
+    nodes.push_back(comp->get_node());
+
+    comp = comp->get_next(pipeline_stage, current_thread);
+  }
+
+  if (comp == nullptr) {
+    // The given source NodePath isn't an ancestor of this NodePath.
+    return false;
+  }
+
+  // Start at the dest NodePath and compose the new NodePath.
+  PT(NodePathComponent) new_comp = dest._head;
+  pvector<PandaNode *>::reverse_iterator it;
+  for (it = nodes.rbegin(); it != nodes.rend(); ++it) {
+    PandaNode::InstanceMap::const_iterator iit = inst_map.find(*it);
+    nassertr_always(iit != inst_map.end(), false);
+    new_comp = PandaNode::get_component(new_comp, iit->second, pipeline_stage, current_thread);
+  }
+
+  nassertr(new_comp != nullptr, false);
+  _head = std::move(new_comp);
+  return true;
+}
+
 /**
  * Walks up from both NodePaths to find the first node that both have in
  * common, if any.  Fills a_count and b_count with the number of nodes below

+ 4 - 0
panda/src/pgraph/nodePath.h

@@ -952,6 +952,10 @@ PUBLISHED:
   static NodePath decode_from_bam_stream(vector_uchar data, BamReader *reader = nullptr);
 
 private:
+  bool replace_copied_nodes(const NodePath &source, const NodePath &dest,
+                            const PandaNode::InstanceMap &inst_map,
+                            Thread *current_thread);
+
   static NodePathComponent *
   find_common_ancestor(const NodePath &a, const NodePath &b,
                        int &a_count, int &b_count,