mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
Merge branch 'release/1.10.x' into incoming
This commit is contained in:
commit
1723fae158
@ -2325,7 +2325,6 @@ DTOOL_CONFIG=[
|
|||||||
("COMPILE_IN_DEFAULT_FONT", '1', '1'),
|
("COMPILE_IN_DEFAULT_FONT", '1', '1'),
|
||||||
("STDFLOAT_DOUBLE", 'UNDEF', 'UNDEF'),
|
("STDFLOAT_DOUBLE", 'UNDEF', 'UNDEF'),
|
||||||
("HAVE_MAYA", '1', '1'),
|
("HAVE_MAYA", '1', '1'),
|
||||||
("HAVE_SOFTIMAGE", 'UNDEF', 'UNDEF'),
|
|
||||||
("REPORT_OPENSSL_ERRORS", '1', '1'),
|
("REPORT_OPENSSL_ERRORS", '1', '1'),
|
||||||
("USE_PANDAFILESTREAM", '1', '1'),
|
("USE_PANDAFILESTREAM", '1', '1'),
|
||||||
("USE_DELETED_CHAIN", '1', '1'),
|
("USE_DELETED_CHAIN", '1', '1'),
|
||||||
|
@ -61,6 +61,9 @@ LinuxInputDeviceManager() {
|
|||||||
|
|
||||||
// We'll want to sort the devices by index, since the order may be
|
// We'll want to sort the devices by index, since the order may be
|
||||||
// meaningful (eg. for the Xbox wireless receiver).
|
// meaningful (eg. for the Xbox wireless receiver).
|
||||||
|
if (indices.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
std::sort(indices.begin(), indices.end());
|
std::sort(indices.begin(), indices.end());
|
||||||
_evdev_devices.resize(indices.back() + 1, nullptr);
|
_evdev_devices.resize(indices.back() + 1, nullptr);
|
||||||
|
|
||||||
|
@ -202,8 +202,8 @@ seekoff(streamoff off, ios_seekdir dir, ios_openmode which) {
|
|||||||
|
|
||||||
gbump(n);
|
gbump(n);
|
||||||
|
|
||||||
_source->seekg(0, ios::beg);
|
if (_source->rdbuf()->pubseekpos(0, ios::in) == (streampos)0) {
|
||||||
if (_source->tellg() == (streampos)0) {
|
_source->clear();
|
||||||
_z_source.next_in = Z_NULL;
|
_z_source.next_in = Z_NULL;
|
||||||
_z_source.avail_in = 0;
|
_z_source.avail_in = 0;
|
||||||
_z_source.next_out = Z_NULL;
|
_z_source.next_out = Z_NULL;
|
||||||
|
@ -31,6 +31,12 @@ PT(MovieAudio) MovieTypeRegistry::
|
|||||||
make_audio(const Filename &name) {
|
make_audio(const Filename &name) {
|
||||||
string ext = downcase(name.get_extension());
|
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();
|
_audio_lock.lock();
|
||||||
|
|
||||||
// Make sure that the list of audio types has been read in.
|
// Make sure that the list of audio types has been read in.
|
||||||
@ -154,6 +160,12 @@ PT(MovieVideo) MovieTypeRegistry::
|
|||||||
make_video(const Filename &name) {
|
make_video(const Filename &name) {
|
||||||
string ext = downcase(name.get_extension());
|
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();
|
_video_lock.lock();
|
||||||
|
|
||||||
// Make sure that the list of video types has been read in.
|
// Make sure that the list of video types has been read in.
|
||||||
|
@ -56,6 +56,22 @@ int cb_seek(void *stream, opus_int64 offset, int whence) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SEEK_CUR:
|
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);
|
in->seekg(offset, std::ios::cur);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -91,19 +91,46 @@ seek(double t) {
|
|||||||
t = std::max(t, 0.0);
|
t = std::max(t, 0.0);
|
||||||
|
|
||||||
// Use ov_time_seek_lap if cross-lapping is enabled.
|
// Use ov_time_seek_lap if cross-lapping is enabled.
|
||||||
|
int result;
|
||||||
if (vorbis_seek_lap) {
|
if (vorbis_seek_lap) {
|
||||||
if (ov_time_seek_lap(&_ov, t) != 0) {
|
result = ov_time_seek_lap(&_ov, t);
|
||||||
movies_cat.error()
|
|
||||||
<< "Seek failed. Ogg Vorbis stream may not be seekable.\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (ov_time_seek(&_ov, t) != 0) {
|
result = ov_time_seek(&_ov, t);
|
||||||
movies_cat.error()
|
}
|
||||||
<< "Seek failed. Ogg Vorbis stream may not be seekable.\n";
|
|
||||||
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (result != 0) {
|
||||||
|
movies_cat.error()
|
||||||
|
<< "Seek failed. Ogg Vorbis stream may not be seekable.\n";
|
||||||
|
}
|
||||||
|
|
||||||
_last_seek = ov_time_tell(&_ov);
|
_last_seek = ov_time_tell(&_ov);
|
||||||
_samples_read = 0;
|
_samples_read = 0;
|
||||||
@ -199,6 +226,22 @@ cb_seek_func(void *datasource, ogg_int64_t offset, int whence) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SEEK_CUR:
|
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);
|
stream->seekg(offset, std::ios::cur);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -294,27 +294,61 @@ seek(double t) {
|
|||||||
t = std::max(t, 0.0);
|
t = std::max(t, 0.0);
|
||||||
std::streampos pos = _data_start + (std::streampos) std::min((size_t) (t * _byte_rate), _data_size);
|
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) {
|
if (_can_seek_fast) {
|
||||||
_stream->seekg(pos);
|
if (buf->pubseekpos(pos, std::ios::in) != pos) {
|
||||||
if (_stream->tellg() != pos) {
|
|
||||||
// Clearly, we can't seek fast. Fall back to the case below.
|
// Clearly, we can't seek fast. Fall back to the case below.
|
||||||
_can_seek_fast = false;
|
_can_seek_fast = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_can_seek_fast) {
|
// Get the current position of the cursor in the file.
|
||||||
std::streampos current = _stream->tellg();
|
std::streampos current = buf->pubseekoff(0, std::ios::cur, std::ios::in);
|
||||||
|
|
||||||
|
if (!_can_seek_fast) {
|
||||||
if (pos > current) {
|
if (pos > current) {
|
||||||
// It is ahead of our current position. Skip ahead.
|
// It is ahead of our current position. Skip ahead.
|
||||||
_reader.skip_bytes(pos - current);
|
_stream->ignore(pos - current);
|
||||||
|
current = pos;
|
||||||
|
|
||||||
} else if (pos < current) {
|
} 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;
|
_last_seek = _data_pos / _byte_rate;
|
||||||
_samples_read = 0;
|
_samples_read = 0;
|
||||||
}
|
}
|
||||||
|
@ -133,6 +133,7 @@ PUBLISHED:
|
|||||||
OdeJoint get_joint(int index) const;
|
OdeJoint get_joint(int index) const;
|
||||||
MAKE_SEQ(get_joints, get_num_joints, get_joint);
|
MAKE_SEQ(get_joints, get_num_joints, get_joint);
|
||||||
EXTENSION(INLINE PyObject *get_converted_joint(int i) const);
|
EXTENSION(INLINE PyObject *get_converted_joint(int i) const);
|
||||||
|
MAKE_SEQ_PROPERTY(joints, get_num_joints, get_converted_joint);
|
||||||
|
|
||||||
INLINE void enable();
|
INLINE void enable();
|
||||||
INLINE void disable();
|
INLINE void disable();
|
||||||
|
@ -83,7 +83,7 @@ PUBLISHED:
|
|||||||
INLINE void set_feedback(bool flag = true);
|
INLINE void set_feedback(bool flag = true);
|
||||||
INLINE OdeJointFeedback *get_feedback();
|
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_bodies(const OdeBody &body1, const OdeBody &body2);
|
||||||
void attach_body(const OdeBody &body, int index);
|
void attach_body(const OdeBody &body, int index);
|
||||||
void detach();
|
void detach();
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "odePlane2dJoint.h"
|
#include "odePlane2dJoint.h"
|
||||||
|
|
||||||
#ifndef CPPPARSER
|
#ifndef CPPPARSER
|
||||||
|
extern Dtool_PyTypedObject Dtool_OdeBody;
|
||||||
extern Dtool_PyTypedObject Dtool_OdeJoint;
|
extern Dtool_PyTypedObject Dtool_OdeJoint;
|
||||||
extern Dtool_PyTypedObject Dtool_OdeBallJoint;
|
extern Dtool_PyTypedObject Dtool_OdeBallJoint;
|
||||||
extern Dtool_PyTypedObject Dtool_OdeHingeJoint;
|
extern Dtool_PyTypedObject Dtool_OdeHingeJoint;
|
||||||
@ -48,7 +49,23 @@ extern Dtool_PyTypedObject Dtool_OdePlane2dJoint;
|
|||||||
* attached to the environment.
|
* attached to the environment.
|
||||||
*/
|
*/
|
||||||
void Extension<OdeJoint>::
|
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) {
|
if (body1 && body2) {
|
||||||
_this->attach_bodies(*body1, *body2);
|
_this->attach_bodies(*body1, *body2);
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
template<>
|
template<>
|
||||||
class Extension<OdeJoint> : public ExtensionBase<OdeJoint> {
|
class Extension<OdeJoint> : public ExtensionBase<OdeJoint> {
|
||||||
public:
|
public:
|
||||||
void attach(const OdeBody *body1, const OdeBody *body2);
|
void attach(PyObject *body1, PyObject *body2);
|
||||||
|
|
||||||
PyObject *convert() const;
|
PyObject *convert() const;
|
||||||
};
|
};
|
||||||
|
7
tests/ode/conftest.py
Normal file
7
tests/ode/conftest.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def world():
|
||||||
|
ode = pytest.importorskip("panda3d.ode")
|
||||||
|
return ode.OdeWorld()
|
43
tests/ode/test_ode_joints.py
Normal file
43
tests/ode/test_ode_joints.py
Normal file
@ -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,)
|
Loading…
x
Reference in New Issue
Block a user