mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 08:44:19 -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) == '\\') {
|
if ((*pi) == quote_mark || (*pi) == '\\') {
|
||||||
out << '\\' << (*pi);
|
out << '\\' << (*pi);
|
||||||
|
|
||||||
} else if (!isprint(*pi)) {
|
} else if (!isprint(*pi) || (*pi) == '\t') {
|
||||||
char buffer[10];
|
char buffer[10];
|
||||||
sprintf(buffer, "%02x", (unsigned char)(*pi));
|
sprintf(buffer, "%02x", (unsigned char)(*pi));
|
||||||
out << "\\x" << buffer;
|
out << "\\x" << buffer;
|
||||||
|
@ -33,15 +33,13 @@ class State(DirectObject):
|
|||||||
if enterFunc.__func__ == oldFunction:
|
if enterFunc.__func__ == oldFunction:
|
||||||
# print 'found: ', enterFunc, oldFunction
|
# print 'found: ', enterFunc, oldFunction
|
||||||
state.setEnterFunc(types.MethodType(newFunction,
|
state.setEnterFunc(types.MethodType(newFunction,
|
||||||
enterFunc.__self__,
|
enterFunc.__self__))
|
||||||
enterFunc.__self__.__class__))
|
|
||||||
count += 1
|
count += 1
|
||||||
if type(exitFunc) == types.MethodType:
|
if type(exitFunc) == types.MethodType:
|
||||||
if exitFunc.__func__ == oldFunction:
|
if exitFunc.__func__ == oldFunction:
|
||||||
# print 'found: ', exitFunc, oldFunction
|
# print 'found: ', exitFunc, oldFunction
|
||||||
state.setExitFunc(types.MethodType(newFunction,
|
state.setExitFunc(types.MethodType(newFunction,
|
||||||
exitFunc.__self__,
|
exitFunc.__self__))
|
||||||
exitFunc.__self__.__class__))
|
|
||||||
count += 1
|
count += 1
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@ -215,18 +213,3 @@ class State(DirectObject):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "State: name = %s, enter = %s, exit = %s, trans = %s, children = %s" %\
|
return "State: name = %s, enter = %s, exit = %s, trans = %s, children = %s" %\
|
||||||
(self.__name, self.__enterFunc, self.__exitFunc, self.__transitions, self.__FSMList)
|
(self.__name, self.__enterFunc, self.__exitFunc, self.__transitions, self.__FSMList)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,8 +37,7 @@ class FunctionInterval(Interval.Interval):
|
|||||||
if ival.function.__func__ == oldFunction:
|
if ival.function.__func__ == oldFunction:
|
||||||
# print 'found: ', ival.function, oldFunction
|
# print 'found: ', ival.function, oldFunction
|
||||||
ival.function = types.MethodType(newFunction,
|
ival.function = types.MethodType(newFunction,
|
||||||
ival.function.__self__,
|
ival.function.__self__)
|
||||||
ival.function.__self__.__class__)
|
|
||||||
count += 1
|
count += 1
|
||||||
return count
|
return count
|
||||||
|
|
||||||
|
@ -464,8 +464,7 @@ class Messenger:
|
|||||||
# 'oldMethod: ' + repr(oldMethod) + '\n' +
|
# 'oldMethod: ' + repr(oldMethod) + '\n' +
|
||||||
# 'newFunction: ' + repr(newFunction) + '\n')
|
# 'newFunction: ' + repr(newFunction) + '\n')
|
||||||
if (function == oldMethod):
|
if (function == oldMethod):
|
||||||
newMethod = types.MethodType(
|
newMethod = types.MethodType(newFunction, method.__self__)
|
||||||
newFunction, method.__self__, method.__self__.__class__)
|
|
||||||
params[0] = newMethod
|
params[0] = newMethod
|
||||||
# Found it retrun true
|
# Found it retrun true
|
||||||
retFlag += 1
|
retFlag += 1
|
||||||
|
@ -1561,7 +1561,7 @@ def appendStr(obj, st):
|
|||||||
return s
|
return s
|
||||||
oldStr = Functor(stringer, str(obj))
|
oldStr = Functor(stringer, str(obj))
|
||||||
stringer = None
|
stringer = None
|
||||||
obj.__str__ = types.MethodType(Functor(appendedStr, oldStr, st), obj, obj.__class__)
|
obj.__str__ = types.MethodType(Functor(appendedStr, oldStr, st), obj)
|
||||||
appendedStr = None
|
appendedStr = None
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
@ -593,9 +593,7 @@ class TaskManager:
|
|||||||
else:
|
else:
|
||||||
function = method
|
function = method
|
||||||
if (function == oldMethod):
|
if (function == oldMethod):
|
||||||
newMethod = types.MethodType(newFunction,
|
newMethod = types.MethodType(newFunction, method.__self__)
|
||||||
method.__self__,
|
|
||||||
method.__self__.__class__)
|
|
||||||
task.setFunction(newMethod)
|
task.setFunction(newMethod)
|
||||||
# Found a match
|
# Found a match
|
||||||
return 1
|
return 1
|
||||||
|
@ -8047,6 +8047,10 @@ output_quoted(ostream &out, int indent_level, const std::string &str,
|
|||||||
<< '"';
|
<< '"';
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
case '\t':
|
||||||
|
out << "\\t";
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (!isprint(*si)) {
|
if (!isprint(*si)) {
|
||||||
out << "\\" << oct << std::setw(3) << std::setfill('0') << (unsigned int)(*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;
|
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];
|
out << data_ptr[i];
|
||||||
|
}
|
||||||
} else {
|
else {
|
||||||
out << "\\x" << std::hex << std::setw(2) << std::setfill('0')
|
out << "\\x" << std::hex << std::setw(2) << std::setfill('0')
|
||||||
<< (unsigned int)(unsigned char)data_ptr[i] << std::dec;
|
<< (unsigned int)(unsigned char)data_ptr[i] << std::dec;
|
||||||
}
|
}
|
||||||
|
@ -123,8 +123,13 @@ FmodAudioSound(AudioManager *manager, VirtualFile *file, bool positional) {
|
|||||||
<< "Reading " << _file_name << " into memory (" << sound_info.length
|
<< "Reading " << _file_name << " into memory (" << sound_info.length
|
||||||
<< " bytes)\n";
|
<< " bytes)\n";
|
||||||
}
|
}
|
||||||
|
result =
|
||||||
|
_manager->_system->createSound(name_or_data, flags, &sound_info, &_sound);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = FMOD_ERR_FILE_BAD;
|
||||||
|
|
||||||
} else if (file->get_system_info(info)) {
|
if (file->get_system_info(info)) {
|
||||||
// The file exists on disk (or it's part of a multifile that exists on
|
// 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
|
// 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
|
// safe, because FMod uses its own IO operations that don't involve
|
||||||
@ -140,11 +145,18 @@ FmodAudioSound(AudioManager *manager, VirtualFile *file, bool positional) {
|
|||||||
<< ", " << sound_info.fileoffset << ", " << sound_info.length << ")\n";
|
<< ", " << sound_info.fileoffset << ", " << sound_info.length << ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
result =
|
||||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
_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
|
// Otherwise, if the Panda threading system is compiled in, we can
|
||||||
// assign callbacks to read the file through the VFS.
|
// assign callbacks to read the file through the VFS.
|
||||||
name_or_data = (const char *)file;
|
name_or_data = (const char *)file;
|
||||||
|
sound_info.fileoffset = 0;
|
||||||
sound_info.length = (unsigned int)info.get_size();
|
sound_info.length = (unsigned int)info.get_size();
|
||||||
sound_info.useropen = open_callback;
|
sound_info.useropen = open_callback;
|
||||||
sound_info.userclose = close_callback;
|
sound_info.userclose = close_callback;
|
||||||
@ -155,18 +167,18 @@ FmodAudioSound(AudioManager *manager, VirtualFile *file, bool positional) {
|
|||||||
fmodAudio_cat.debug()
|
fmodAudio_cat.debug()
|
||||||
<< "Streaming " << _file_name << " from disk using callbacks\n";
|
<< "Streaming " << _file_name << " from disk using callbacks\n";
|
||||||
}
|
}
|
||||||
|
result =
|
||||||
|
_manager->_system->createSound(name_or_data, flags, &sound_info, &_sound);
|
||||||
|
|
||||||
#else // HAVE_THREADS && !SIMPLE_THREADS
|
#else // HAVE_THREADS && !SIMPLE_THREADS
|
||||||
// Without threads, we can't safely read this file.
|
// Without threads, we can't safely read this file.
|
||||||
name_or_data = "";
|
name_or_data = "";
|
||||||
|
|
||||||
fmodAudio_cat.warning()
|
fmodAudio_cat.warning()
|
||||||
<< "Cannot stream " << _file_name << "; file is not literally on disk.\n";
|
<< "Cannot stream " << _file_name << "; file is not literally on disk.\n";
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result =
|
|
||||||
_manager->_system->createSound(name_or_data, flags, &sound_info, &_sound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != FMOD_OK) {
|
if (result != FMOD_OK) {
|
||||||
|
@ -150,11 +150,7 @@ triangulate() {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int attempts = 0;
|
|
||||||
|
|
||||||
while (construct_trapezoids(num_segments) != 0) {
|
while (construct_trapezoids(num_segments) != 0) {
|
||||||
nassertv_always(attempts++ < 100);
|
|
||||||
|
|
||||||
// If there's an error, re-shuffle the index and try again.
|
// If there's an error, re-shuffle the index and try again.
|
||||||
Randomizer randomizer;
|
Randomizer randomizer;
|
||||||
for (i = 0; i < num_segments; ++i) {
|
for (i = 0; i < num_segments; ++i) {
|
||||||
@ -263,7 +259,7 @@ cleanup_polygon_indices(vector_int &polygon) {
|
|||||||
++pi;
|
++pi;
|
||||||
} else {
|
} else {
|
||||||
// This index is out-of-bounds; remove it.
|
// 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;
|
++pi;
|
||||||
} else {
|
} else {
|
||||||
// This vertex repeats the previous one; remove it.
|
// 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.
|
// The last vertex repeats the first one; remove it.
|
||||||
polygon.pop_back();
|
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();
|
ButtonHandle button = param.get_button();
|
||||||
|
|
||||||
if (button == KeyboardButton::tab()) {
|
|
||||||
// Tab. Ignore the entry.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (button == MouseButton::one() ||
|
if (button == MouseButton::one() ||
|
||||||
button == MouseButton::two() ||
|
button == MouseButton::two() ||
|
||||||
button == MouseButton::three() ||
|
button == MouseButton::three() ||
|
||||||
@ -326,7 +321,7 @@ keystroke(const MouseWatcherParameter ¶m, bool background) {
|
|||||||
|
|
||||||
int keycode = param.get_keycode();
|
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,
|
// A normal visible character. Add a new character to the text entry,
|
||||||
// if there's room.
|
// if there's room.
|
||||||
if (!_candidate_wtext.empty()) {
|
if (!_candidate_wtext.empty()) {
|
||||||
|
@ -519,8 +519,8 @@ describe_compound_attribute(MObject &node) {
|
|||||||
for (size_t i = 0; i < comp_attr.numChildren(); i++) {
|
for (size_t i = 0; i < comp_attr.numChildren(); i++) {
|
||||||
MObject child = comp_attr.child(i, &status);
|
MObject child = comp_attr.child(i, &status);
|
||||||
if (child.apiType() == MFn::kAttribute3Float){
|
if (child.apiType() == MFn::kAttribute3Float){
|
||||||
LRGBColor color;
|
|
||||||
/*
|
/*
|
||||||
|
LRGBColor color;
|
||||||
if (get_vec3_attribute(child, "color", color)) {
|
if (get_vec3_attribute(child, "color", color)) {
|
||||||
maya_cat.info() << "color: " << color << endl;
|
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;
|
mayaloader_cat.debug() << delim+delstring << "found an EggTable: " << node->get_name() << endl;
|
||||||
}
|
}
|
||||||
} else if (node->is_of_type(EggXfmSAnim::get_class_type())) {
|
} 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();
|
//anim->PrintData();
|
||||||
if (mayaloader_cat.is_debug()) {
|
if (mayaloader_cat.is_debug()) {
|
||||||
mayaloader_cat.debug() << delim+delstring << "found an EggXfmSAnim: " << node->get_name() << endl;
|
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