mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-29 16:20:11 -04:00
Merge remote-tracking branch 'origin/release/1.10.x'
This commit is contained in:
commit
707ea089cb
@ -769,7 +769,7 @@ enquote_string(ostream &out, char quote_mark, const string &str) {
|
||||
if ((*pi) == quote_mark || (*pi) == '\\') {
|
||||
out << '\\' << (*pi);
|
||||
|
||||
} else if (!isprint(*pi)) {
|
||||
} else if (!isprint(*pi) || (*pi) == '\t') {
|
||||
char buffer[10];
|
||||
sprintf(buffer, "%02x", (unsigned char)(*pi));
|
||||
out << "\\x" << buffer;
|
||||
|
@ -33,15 +33,13 @@ class State(DirectObject):
|
||||
if enterFunc.__func__ == oldFunction:
|
||||
# print 'found: ', enterFunc, oldFunction
|
||||
state.setEnterFunc(types.MethodType(newFunction,
|
||||
enterFunc.__self__,
|
||||
enterFunc.__self__.__class__))
|
||||
enterFunc.__self__))
|
||||
count += 1
|
||||
if type(exitFunc) == types.MethodType:
|
||||
if exitFunc.__func__ == oldFunction:
|
||||
# print 'found: ', exitFunc, oldFunction
|
||||
state.setExitFunc(types.MethodType(newFunction,
|
||||
exitFunc.__self__,
|
||||
exitFunc.__self__.__class__))
|
||||
exitFunc.__self__))
|
||||
count += 1
|
||||
return count
|
||||
|
||||
@ -215,18 +213,3 @@ class State(DirectObject):
|
||||
def __str__(self):
|
||||
return "State: name = %s, enter = %s, exit = %s, trans = %s, children = %s" %\
|
||||
(self.__name, self.__enterFunc, self.__exitFunc, self.__transitions, self.__FSMList)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -37,8 +37,7 @@ class FunctionInterval(Interval.Interval):
|
||||
if ival.function.__func__ == oldFunction:
|
||||
# print 'found: ', ival.function, oldFunction
|
||||
ival.function = types.MethodType(newFunction,
|
||||
ival.function.__self__,
|
||||
ival.function.__self__.__class__)
|
||||
ival.function.__self__)
|
||||
count += 1
|
||||
return count
|
||||
|
||||
|
@ -464,8 +464,7 @@ class Messenger:
|
||||
# 'oldMethod: ' + repr(oldMethod) + '\n' +
|
||||
# 'newFunction: ' + repr(newFunction) + '\n')
|
||||
if (function == oldMethod):
|
||||
newMethod = types.MethodType(
|
||||
newFunction, method.__self__, method.__self__.__class__)
|
||||
newMethod = types.MethodType(newFunction, method.__self__)
|
||||
params[0] = newMethod
|
||||
# Found it retrun true
|
||||
retFlag += 1
|
||||
|
@ -1561,7 +1561,7 @@ def appendStr(obj, st):
|
||||
return s
|
||||
oldStr = Functor(stringer, str(obj))
|
||||
stringer = None
|
||||
obj.__str__ = types.MethodType(Functor(appendedStr, oldStr, st), obj, obj.__class__)
|
||||
obj.__str__ = types.MethodType(Functor(appendedStr, oldStr, st), obj)
|
||||
appendedStr = None
|
||||
return obj
|
||||
|
||||
|
@ -593,9 +593,7 @@ class TaskManager:
|
||||
else:
|
||||
function = method
|
||||
if (function == oldMethod):
|
||||
newMethod = types.MethodType(newFunction,
|
||||
method.__self__,
|
||||
method.__self__.__class__)
|
||||
newMethod = types.MethodType(newFunction, method.__self__)
|
||||
task.setFunction(newMethod)
|
||||
# Found a match
|
||||
return 1
|
||||
|
@ -8047,6 +8047,10 @@ output_quoted(ostream &out, int indent_level, const std::string &str,
|
||||
<< '"';
|
||||
continue;
|
||||
|
||||
case '\t':
|
||||
out << "\\t";
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!isprint(*si)) {
|
||||
out << "\\" << oct << std::setw(3) << std::setfill('0') << (unsigned int)(*si)
|
||||
|
@ -93,10 +93,13 @@ output_c_string(std::ostream &out, const string &string_name,
|
||||
last_nl = false;
|
||||
}
|
||||
|
||||
if (isprint(data_ptr[i])) {
|
||||
if (data_ptr[i] == '\t') {
|
||||
out << "\\t";
|
||||
}
|
||||
else if (isprint(data_ptr[i])) {
|
||||
out << data_ptr[i];
|
||||
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
out << "\\x" << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< (unsigned int)(unsigned char)data_ptr[i] << std::dec;
|
||||
}
|
||||
|
@ -123,50 +123,62 @@ FmodAudioSound(AudioManager *manager, VirtualFile *file, bool positional) {
|
||||
<< "Reading " << _file_name << " into memory (" << sound_info.length
|
||||
<< " bytes)\n";
|
||||
}
|
||||
|
||||
} else if (file->get_system_info(info)) {
|
||||
// The file exists on disk (or it's part of a multifile that exists on
|
||||
// disk), so we can have FMod read the file directly. This is also
|
||||
// safe, because FMod uses its own IO operations that don't involve
|
||||
// Panda, so this can safely happen in an FMod thread.
|
||||
os_filename = info.get_filename().to_os_specific();
|
||||
name_or_data = os_filename.c_str();
|
||||
sound_info.fileoffset = (unsigned int)info.get_start();
|
||||
sound_info.length = (unsigned int)info.get_size();
|
||||
flags |= FMOD_CREATESTREAM;
|
||||
if (fmodAudio_cat.is_debug()) {
|
||||
fmodAudio_cat.debug()
|
||||
<< "Streaming " << _file_name << " from disk (" << name_or_data
|
||||
<< ", " << sound_info.fileoffset << ", " << sound_info.length << ")\n";
|
||||
}
|
||||
|
||||
} else {
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
// Otherwise, if the Panda threading system is compiled in, we can
|
||||
// assign callbacks to read the file through the VFS.
|
||||
name_or_data = (const char *)file;
|
||||
sound_info.length = (unsigned int)info.get_size();
|
||||
sound_info.useropen = open_callback;
|
||||
sound_info.userclose = close_callback;
|
||||
sound_info.userread = read_callback;
|
||||
sound_info.userseek = seek_callback;
|
||||
flags |= FMOD_CREATESTREAM;
|
||||
if (fmodAudio_cat.is_debug()) {
|
||||
fmodAudio_cat.debug()
|
||||
<< "Streaming " << _file_name << " from disk using callbacks\n";
|
||||
}
|
||||
|
||||
#else // HAVE_THREADS && !SIMPLE_THREADS
|
||||
// Without threads, we can't safely read this file.
|
||||
name_or_data = "";
|
||||
|
||||
fmodAudio_cat.warning()
|
||||
<< "Cannot stream " << _file_name << "; file is not literally on disk.\n";
|
||||
#endif
|
||||
result =
|
||||
_manager->_system->createSound(name_or_data, flags, &sound_info, &_sound);
|
||||
}
|
||||
else {
|
||||
result = FMOD_ERR_FILE_BAD;
|
||||
|
||||
result =
|
||||
_manager->_system->createSound(name_or_data, flags, &sound_info, &_sound);
|
||||
if (file->get_system_info(info)) {
|
||||
// The file exists on disk (or it's part of a multifile that exists on
|
||||
// disk), so we can have FMod read the file directly. This is also
|
||||
// safe, because FMod uses its own IO operations that don't involve
|
||||
// Panda, so this can safely happen in an FMod thread.
|
||||
os_filename = info.get_filename().to_os_specific();
|
||||
name_or_data = os_filename.c_str();
|
||||
sound_info.fileoffset = (unsigned int)info.get_start();
|
||||
sound_info.length = (unsigned int)info.get_size();
|
||||
flags |= FMOD_CREATESTREAM;
|
||||
if (fmodAudio_cat.is_debug()) {
|
||||
fmodAudio_cat.debug()
|
||||
<< "Streaming " << _file_name << " from disk (" << name_or_data
|
||||
<< ", " << sound_info.fileoffset << ", " << sound_info.length << ")\n";
|
||||
}
|
||||
|
||||
result =
|
||||
_manager->_system->createSound(name_or_data, flags, &sound_info, &_sound);
|
||||
}
|
||||
|
||||
// If FMOD can't directly read the file (eg. if Panda is locking it for
|
||||
// write, or it's compressed) we have to use the callback interface.
|
||||
if (result == FMOD_ERR_FILE_BAD) {
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
// Otherwise, if the Panda threading system is compiled in, we can
|
||||
// assign callbacks to read the file through the VFS.
|
||||
name_or_data = (const char *)file;
|
||||
sound_info.fileoffset = 0;
|
||||
sound_info.length = (unsigned int)info.get_size();
|
||||
sound_info.useropen = open_callback;
|
||||
sound_info.userclose = close_callback;
|
||||
sound_info.userread = read_callback;
|
||||
sound_info.userseek = seek_callback;
|
||||
flags |= FMOD_CREATESTREAM;
|
||||
if (fmodAudio_cat.is_debug()) {
|
||||
fmodAudio_cat.debug()
|
||||
<< "Streaming " << _file_name << " from disk using callbacks\n";
|
||||
}
|
||||
result =
|
||||
_manager->_system->createSound(name_or_data, flags, &sound_info, &_sound);
|
||||
|
||||
#else // HAVE_THREADS && !SIMPLE_THREADS
|
||||
// Without threads, we can't safely read this file.
|
||||
name_or_data = "";
|
||||
|
||||
fmodAudio_cat.warning()
|
||||
<< "Cannot stream " << _file_name << "; file is not literally on disk.\n";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result != FMOD_OK) {
|
||||
|
@ -150,11 +150,7 @@ triangulate() {
|
||||
}
|
||||
*/
|
||||
|
||||
int attempts = 0;
|
||||
|
||||
while (construct_trapezoids(num_segments) != 0) {
|
||||
nassertv_always(attempts++ < 100);
|
||||
|
||||
// If there's an error, re-shuffle the index and try again.
|
||||
Randomizer randomizer;
|
||||
for (i = 0; i < num_segments; ++i) {
|
||||
@ -263,7 +259,7 @@ cleanup_polygon_indices(vector_int &polygon) {
|
||||
++pi;
|
||||
} else {
|
||||
// This index is out-of-bounds; remove it.
|
||||
polygon.erase(_polygon.begin() + pi);
|
||||
polygon.erase(polygon.begin() + pi);
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,14 +271,46 @@ cleanup_polygon_indices(vector_int &polygon) {
|
||||
++pi;
|
||||
} else {
|
||||
// This vertex repeats the previous one; remove it.
|
||||
polygon.erase(_polygon.begin() + pi);
|
||||
polygon.erase(polygon.begin() + pi);
|
||||
}
|
||||
}
|
||||
|
||||
if (polygon.size() > 1 && _vertices[polygon.back()] == _vertices[_polygon.front()]) {
|
||||
if (polygon.size() > 1 && _vertices[polygon.back()] == _vertices[polygon.front()]) {
|
||||
// The last vertex repeats the first one; remove it.
|
||||
polygon.pop_back();
|
||||
}
|
||||
|
||||
// Another pass over the polygons, this time removing any "tails".
|
||||
while (polygon.size() >= 3) {
|
||||
bool removed_any = false;
|
||||
|
||||
int prevprev = polygon[polygon.size() - 2];
|
||||
int prev = polygon[polygon.size() - 1];
|
||||
|
||||
for (size_t i = 0; i < polygon.size(); ++i) {
|
||||
int cur = polygon[i];
|
||||
if (_vertices[prevprev] == _vertices[cur]) {
|
||||
// Cut off the tail.
|
||||
removed_any = true;
|
||||
polygon.erase(polygon.begin() + i);
|
||||
if (i == 0) {
|
||||
polygon.pop_back();
|
||||
} else {
|
||||
polygon.erase(polygon.begin() + i - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
prevprev = prev;
|
||||
prev = cur;
|
||||
}
|
||||
|
||||
// This might have been the tip of a longer tail, so if we removed
|
||||
// something, go again.
|
||||
if (!removed_any) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -203,11 +203,6 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
||||
|
||||
ButtonHandle button = param.get_button();
|
||||
|
||||
if (button == KeyboardButton::tab()) {
|
||||
// Tab. Ignore the entry.
|
||||
return;
|
||||
}
|
||||
|
||||
if (button == MouseButton::one() ||
|
||||
button == MouseButton::two() ||
|
||||
button == MouseButton::three() ||
|
||||
@ -326,7 +321,7 @@ keystroke(const MouseWatcherParameter ¶m, bool background) {
|
||||
|
||||
int keycode = param.get_keycode();
|
||||
|
||||
if (!isascii(keycode) || isprint(keycode)) {
|
||||
if ((!isascii(keycode) || isprint(keycode)) && keycode != '\t') {
|
||||
// A normal visible character. Add a new character to the text entry,
|
||||
// if there's room.
|
||||
if (!_candidate_wtext.empty()) {
|
||||
|
@ -519,8 +519,8 @@ describe_compound_attribute(MObject &node) {
|
||||
for (size_t i = 0; i < comp_attr.numChildren(); i++) {
|
||||
MObject child = comp_attr.child(i, &status);
|
||||
if (child.apiType() == MFn::kAttribute3Float){
|
||||
LRGBColor color;
|
||||
/*
|
||||
LRGBColor color;
|
||||
if (get_vec3_attribute(child, "color", color)) {
|
||||
maya_cat.info() << "color: " << color << endl;
|
||||
}
|
||||
|
@ -1572,7 +1572,8 @@ void MayaEggLoader::TraverseEggNode(EggNode *node, EggGroup *context, string del
|
||||
mayaloader_cat.debug() << delim+delstring << "found an EggTable: " << node->get_name() << endl;
|
||||
}
|
||||
} else if (node->is_of_type(EggXfmSAnim::get_class_type())) {
|
||||
//MayaAnim *anim = GetAnim(DCAST(EggXfmSAnim, node));
|
||||
// Create a MayaAnim equivalent of the EggXfmSAnim
|
||||
GetAnim(DCAST(EggXfmSAnim, node));
|
||||
//anim->PrintData();
|
||||
if (mayaloader_cat.is_debug()) {
|
||||
mayaloader_cat.debug() << delim+delstring << "found an EggXfmSAnim: " << node->get_name() << endl;
|
||||
|
73
tests/mathutil/test_triangulator.py
Normal file
73
tests/mathutil/test_triangulator.py
Normal file
@ -0,0 +1,73 @@
|
||||
from panda3d.core import Triangulator
|
||||
|
||||
|
||||
def triangulate(vertices):
|
||||
t = Triangulator()
|
||||
for i, v in enumerate(vertices):
|
||||
t.add_vertex(v)
|
||||
t.add_polygon_vertex(i)
|
||||
|
||||
t.triangulate()
|
||||
|
||||
# Make sure that the result is consistent by starting each triangle with
|
||||
# the lowest index value. That makes it easier to use predetermined values
|
||||
# in the test cases.
|
||||
result = set()
|
||||
|
||||
for n in range(t.get_num_triangles()):
|
||||
# Switch to lowest matching index value in case of duplicates.
|
||||
v0 = vertices.index(vertices[t.get_triangle_v0(n)])
|
||||
v1 = vertices.index(vertices[t.get_triangle_v1(n)])
|
||||
v2 = vertices.index(vertices[t.get_triangle_v2(n)])
|
||||
if v1 < v0:
|
||||
v0, v1, v2 = v1, v2, v0
|
||||
if v1 < v0:
|
||||
v0, v1, v2 = v1, v2, v0
|
||||
result.add((v0, v1, v2))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def test_triangulator_degenerate():
|
||||
assert not triangulate([])
|
||||
assert not triangulate([(0, 0)])
|
||||
assert not triangulate([(0, 0), (0, 0)])
|
||||
assert not triangulate([(0, 0), (1, 0)])
|
||||
assert not triangulate([(0, 0), (0, 0), (0, 0)])
|
||||
assert not triangulate([(0, 0), (1, 0), (1, 0)])
|
||||
assert not triangulate([(1, 0), (1, 0), (1, 0)])
|
||||
assert not triangulate([(1, 0), (0, 0), (1, 0)])
|
||||
assert not triangulate([(0, 0), (0, 0), (0, 0), (0, 0)])
|
||||
|
||||
|
||||
def test_triangulator_triangle():
|
||||
assert triangulate([(0, 0), (1, 0), (1, 1)]) == {(0, 1, 2)}
|
||||
|
||||
|
||||
def test_triangulator_tail():
|
||||
# This triangle has a long "tail" where the polygon retraces its vertices.
|
||||
assert triangulate([
|
||||
(0, -1),
|
||||
(0, 1),
|
||||
(1, 0),
|
||||
(2, 0),
|
||||
(3, 1),
|
||||
(4, 0),
|
||||
(5, 0),
|
||||
(4, 0),
|
||||
(3, 1),
|
||||
(2, 0),
|
||||
(1, 0),
|
||||
]) == {(0, 2, 1)}
|
||||
|
||||
|
||||
def test_triangulator_hourglass():
|
||||
# Two triangles with touching tips, effectively.
|
||||
assert triangulate([
|
||||
(-1, 1),
|
||||
(-1, -1),
|
||||
(0, 0),
|
||||
(1, -1),
|
||||
(1, 1),
|
||||
(0, 0),
|
||||
]) == {(0, 1, 2), (2, 3, 4)}
|
Loading…
x
Reference in New Issue
Block a user