Merge remote-tracking branch 'origin/release/1.10.x'

This commit is contained in:
rdb 2020-09-01 11:09:29 +02:00
commit 707ea089cb
14 changed files with 183 additions and 88 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;
}
}
}

View File

@ -203,11 +203,6 @@ press(const MouseWatcherParameter &param, 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 &param, 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()) {

View File

@ -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;
}

View File

@ -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;

View 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)}