ソースを参照

Merge branch 'release/1.10.x' into incoming

rdb 6 年 前
コミット
1723fae158

+ 0 - 1
makepanda/makepanda.py

@@ -2325,7 +2325,6 @@ DTOOL_CONFIG=[
     ("COMPILE_IN_DEFAULT_FONT",        '1',                      '1'),
     ("STDFLOAT_DOUBLE",                'UNDEF',                  'UNDEF'),
     ("HAVE_MAYA",                      '1',                      '1'),
-    ("HAVE_SOFTIMAGE",                 'UNDEF',                  'UNDEF'),
     ("REPORT_OPENSSL_ERRORS",          '1',                      '1'),
     ("USE_PANDAFILESTREAM",            '1',                      '1'),
     ("USE_DELETED_CHAIN",              '1',                      '1'),

+ 3 - 0
panda/src/device/linuxInputDeviceManager.cxx

@@ -61,6 +61,9 @@ LinuxInputDeviceManager() {
 
     // We'll want to sort the devices by index, since the order may be
     // meaningful (eg. for the Xbox wireless receiver).
+    if (indices.empty()) {
+      return;
+    }
     std::sort(indices.begin(), indices.end());
     _evdev_devices.resize(indices.back() + 1, nullptr);
 

+ 2 - 2
panda/src/express/zStreamBuf.cxx

@@ -202,8 +202,8 @@ seekoff(streamoff off, ios_seekdir dir, ios_openmode which) {
 
   gbump(n);
 
-  _source->seekg(0, ios::beg);
-  if (_source->tellg() == (streampos)0) {
+  if (_source->rdbuf()->pubseekpos(0, ios::in) == (streampos)0) {
+    _source->clear();
     _z_source.next_in = Z_NULL;
     _z_source.avail_in = 0;
     _z_source.next_out = Z_NULL;

+ 12 - 0
panda/src/movies/movieTypeRegistry.cxx

@@ -31,6 +31,12 @@ PT(MovieAudio) MovieTypeRegistry::
 make_audio(const Filename &name) {
   string ext = downcase(name.get_extension());
 
+#ifdef HAVE_ZLIB
+  if (ext == "pz" || ext == "gz") {
+    ext = Filename(name.get_basename_wo_extension()).get_extension();
+  }
+#endif
+
   _audio_lock.lock();
 
   // Make sure that the list of audio types has been read in.
@@ -154,6 +160,12 @@ PT(MovieVideo) MovieTypeRegistry::
 make_video(const Filename &name) {
   string ext = downcase(name.get_extension());
 
+#ifdef HAVE_ZLIB
+  if (ext == "pz" || ext == "gz") {
+    ext = Filename(name.get_basename_wo_extension()).get_extension();
+  }
+#endif
+
   _video_lock.lock();
 
   // Make sure that the list of video types has been read in.

+ 16 - 0
panda/src/movies/opusAudioCursor.cxx

@@ -56,6 +56,22 @@ int cb_seek(void *stream, opus_int64 offset, int whence) {
     break;
 
   case SEEK_CUR:
+    // opusfile uses a seek with offset 0 to determine whether seeking is
+    // supported, but this is not good enough.  We seek to the end and back.
+    if (offset == 0) {
+      std::streambuf *buf = in->rdbuf();
+      std::streampos pos = buf->pubseekoff(0, std::ios::cur, std::ios::in);
+      if (pos < 0) {
+        return -1;
+      }
+      if (buf->pubseekoff(0, std::ios::end, std::ios::in) >= 0) {
+        // It worked; seek back to the previous location.
+        buf->pubseekpos(pos, std::ios::in);
+        return 0;
+      } else {
+        return -1;
+      }
+    }
     in->seekg(offset, std::ios::cur);
     break;
 

+ 51 - 8
panda/src/movies/vorbisAudioCursor.cxx

@@ -91,19 +91,46 @@ seek(double t) {
   t = std::max(t, 0.0);
 
   // Use ov_time_seek_lap if cross-lapping is enabled.
+  int result;
   if (vorbis_seek_lap) {
-    if (ov_time_seek_lap(&_ov, t) != 0) {
-      movies_cat.error()
-        << "Seek failed.  Ogg Vorbis stream may not be seekable.\n";
-      return;
-    }
+    result = ov_time_seek_lap(&_ov, t);
   } else {
-    if (ov_time_seek(&_ov, t) != 0) {
-      movies_cat.error()
-        << "Seek failed.  Ogg Vorbis stream may not be seekable.\n";
+    result = ov_time_seek(&_ov, t);
+  }
+
+  // Special case for seeking to the beginning; if normal seek fails, we may
+  // be able to explicitly seek to the beginning of the file and call ov_open
+  // again.  This allows looping compressed .ogg files.
+  if (result == OV_ENOSEEK && t == 0.0) {
+    std::istream *stream = (std::istream *)_ov.datasource;
+
+    if (stream->rdbuf()->pubseekpos(0, std::ios::in) == 0) {
+      // Back up the callbacks, then destroy the stream, making sure to first
+      // unset the datasource so that it won't close the file.
+      ov_callbacks callbacks = _ov.callbacks;
+      _ov.datasource = nullptr;
+      ov_clear(&_ov);
+
+      if (ov_open_callbacks((void *)stream, &_ov, nullptr, 0, callbacks) != 0) {
+        movies_cat.error()
+          << "Failed to reopen Ogg Vorbis file to seek to beginning.\n";
+        return;
+      }
+
+      // Reset these fields for good measure, just in case the file changed.
+      vorbis_info *vi = ov_info(&_ov, -1);
+      _audio_channels = vi->channels;
+      _audio_rate = vi->rate;
+
+      _last_seek = 0.0;
+      _samples_read = 0;
       return;
     }
   }
+  if (result != 0) {
+    movies_cat.error()
+      << "Seek failed.  Ogg Vorbis stream may not be seekable.\n";
+  }
 
   _last_seek = ov_time_tell(&_ov);
   _samples_read = 0;
@@ -199,6 +226,22 @@ cb_seek_func(void *datasource, ogg_int64_t offset, int whence) {
     break;
 
   case SEEK_CUR:
+    // Vorbis uses a seek with offset 0 to determine whether seeking is
+    // supported, but this is not good enough.  We seek to the end and back.
+    if (offset == 0) {
+      std::streambuf *buf = stream->rdbuf();
+      std::streampos pos = buf->pubseekoff(0, std::ios::cur, std::ios::in);
+      if (pos < 0) {
+        return -1;
+      }
+      if (buf->pubseekoff(0, std::ios::end, std::ios::in) >= 0) {
+        // It worked; seek back to the previous location.
+        buf->pubseekpos(pos, std::ios::in);
+        return 0;
+      } else {
+        return -1;
+      }
+    }
     stream->seekg(offset, std::ios::cur);
     break;
 

+ 41 - 7
panda/src/movies/wavAudioCursor.cxx

@@ -294,27 +294,61 @@ seek(double t) {
   t = std::max(t, 0.0);
   std::streampos pos = _data_start + (std::streampos) std::min((size_t) (t * _byte_rate), _data_size);
 
+  std::streambuf *buf = _stream->rdbuf();
+
   if (_can_seek_fast) {
-    _stream->seekg(pos);
-    if (_stream->tellg() != pos) {
+    if (buf->pubseekpos(pos, std::ios::in) != pos) {
       // Clearly, we can't seek fast.  Fall back to the case below.
       _can_seek_fast = false;
     }
   }
 
-  if (!_can_seek_fast) {
-    std::streampos current = _stream->tellg();
+  // Get the current position of the cursor in the file.
+  std::streampos current = buf->pubseekoff(0, std::ios::cur, std::ios::in);
 
+  if (!_can_seek_fast) {
     if (pos > current) {
       // It is ahead of our current position.  Skip ahead.
-      _reader.skip_bytes(pos - current);
+      _stream->ignore(pos - current);
+      current = pos;
 
     } else if (pos < current) {
-      // We'll have to reopen the file.  TODO
+      // Can we seek to the beginning?  Some streams, such as ZStream, let us
+      // rewind the stream.
+      if (buf->pubseekpos(0, std::ios::in) == 0) {
+        if (pos > _data_start && movies_cat.is_info()) {
+          Filename fn = get_source()->get_filename();
+          movies_cat.info()
+            << "Unable to seek backwards in " << fn.get_basename()
+            << "; seeking to beginning and skipping " << pos << " bytes.\n";
+        }
+        _stream->ignore(pos);
+        current = pos;
+      } else {
+        // No; close and reopen the file.
+        Filename fn = get_source()->get_filename();
+        movies_cat.warning()
+          << "Unable to seek backwards in " << fn.get_basename()
+          << "; reopening and skipping " << pos << " bytes.\n";
+
+        VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+        std::istream *stream = vfs->open_read_file(get_source()->get_filename(), true);
+        if (stream != nullptr) {
+          vfs->close_read_file(_stream);
+          stream->ignore(pos);
+          _stream = stream;
+          _reader = StreamReader(stream, false);
+          current = pos;
+        } else {
+          movies_cat.error()
+            << "Unable to reopen " << fn << ".\n";
+          _can_seek = false;
+        }
+      }
     }
   }
 
-  _data_pos = _stream->tellg() - _data_start;
+  _data_pos = (size_t)current - _data_start;
   _last_seek = _data_pos / _byte_rate;
   _samples_read = 0;
 }

+ 1 - 0
panda/src/ode/odeBody.h

@@ -133,6 +133,7 @@ PUBLISHED:
   OdeJoint get_joint(int index) const;
   MAKE_SEQ(get_joints, get_num_joints, get_joint);
   EXTENSION(INLINE PyObject *get_converted_joint(int i) const);
+  MAKE_SEQ_PROPERTY(joints, get_num_joints, get_converted_joint);
 
   INLINE void enable();
   INLINE void disable();

+ 1 - 1
panda/src/ode/odeJoint.h

@@ -83,7 +83,7 @@ PUBLISHED:
   INLINE void set_feedback(bool flag = true);
   INLINE OdeJointFeedback *get_feedback();
 
-  EXTENSION(void attach(const OdeBody *body1, const OdeBody *body2));
+  EXTENSION(void attach(PyObject *body1, PyObject *body2));
   void attach_bodies(const OdeBody &body1, const OdeBody &body2);
   void attach_body(const OdeBody &body, int index);
   void detach();

+ 18 - 1
panda/src/ode/odeJoint_ext.cxx

@@ -29,6 +29,7 @@
 #include "odePlane2dJoint.h"
 
 #ifndef CPPPARSER
+extern Dtool_PyTypedObject Dtool_OdeBody;
 extern Dtool_PyTypedObject Dtool_OdeJoint;
 extern Dtool_PyTypedObject Dtool_OdeBallJoint;
 extern Dtool_PyTypedObject Dtool_OdeHingeJoint;
@@ -48,7 +49,23 @@ extern Dtool_PyTypedObject Dtool_OdePlane2dJoint;
  * attached to the environment.
  */
 void Extension<OdeJoint>::
-attach(const OdeBody *body1, const OdeBody *body2) {
+attach(PyObject *param1, PyObject *param2) {
+  const OdeBody *body1 = nullptr;
+  if (param1 != Py_None) {
+    body1 = (const OdeBody *)DTOOL_Call_GetPointerThisClass(param1, &Dtool_OdeBody, 1, "OdeJoint.attach", true, true);
+    if (body1 == nullptr) {
+      return;
+    }
+  }
+
+  const OdeBody *body2 = nullptr;
+  if (param2 != Py_None) {
+    body2 = (const OdeBody *)DTOOL_Call_GetPointerThisClass(param2, &Dtool_OdeBody, 2, "OdeJoint.attach", true, true);
+    if (body2 == nullptr) {
+      return;
+    }
+  }
+
   if (body1 && body2) {
     _this->attach_bodies(*body1, *body2);
 

+ 1 - 1
panda/src/ode/odeJoint_ext.h

@@ -30,7 +30,7 @@
 template<>
 class Extension<OdeJoint> : public ExtensionBase<OdeJoint> {
 public:
-  void attach(const OdeBody *body1, const OdeBody *body2);
+  void attach(PyObject *body1, PyObject *body2);
 
   PyObject *convert() const;
 };

+ 7 - 0
tests/ode/conftest.py

@@ -0,0 +1,7 @@
+import pytest
+
+
[email protected]
+def world():
+    ode = pytest.importorskip("panda3d.ode")
+    return ode.OdeWorld()

+ 43 - 0
tests/ode/test_ode_joints.py

@@ -0,0 +1,43 @@
+import pytest
+
+
+def test_odejoint_attach_both(world):
+    from panda3d import ode
+
+    body1 = ode.OdeBody(world)
+    body2 = ode.OdeBody(world)
+
+    assert len(body1.joints) == 0
+    assert len(body2.joints) == 0
+
+    joint = ode.OdeBallJoint(world)
+    joint.attach(body1, body2)
+
+    assert tuple(body1.joints) == (joint,)
+    assert tuple(body2.joints) == (joint,)
+
+
+def test_odejoint_attach_0(world):
+    from panda3d import ode
+
+    body = ode.OdeBody(world)
+
+    assert len(body.joints) == 0
+
+    joint = ode.OdeBallJoint(world)
+    joint.attach(body, None)
+
+    assert tuple(body.joints) == (joint,)
+
+
+def test_odejoint_attach_1(world):
+    from panda3d import ode
+
+    body = ode.OdeBody(world)
+
+    assert len(body.joints) == 0
+
+    joint = ode.OdeBallJoint(world)
+    joint.attach(None, body)
+
+    assert tuple(body.joints) == (joint,)