From 147bac69a76817097ffc65bd01de3709ca7c6fb0 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 13 Dec 2018 09:30:05 +0100 Subject: [PATCH 1/7] travis: encrypt IRC channel name to prevent fork spam in IRC [skip ci] --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 64cc557d5b..2c4efe8a65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,7 +49,7 @@ script: notifications: irc: channels: - - "chat.freenode.net#panda3d" + - secure: "jfwHT9RHAVOGRGTMY8TpYKJI6rq8nFoIj41Y0soZdJQNWtSSFEK9AyzZeMY+2dHga7cR/X+/0NWZ2ehhedTnd9FvlzOnMWWC3K0I/b3XWbEdVEqIZnggFkKGqs82Gy3omguRC63yWupeJCcSCckIhoWbLzWy6xV8lF5WC80iXi8=" on_success: change on_failure: always use_notice: true From b11debcf3dcb7471533efb6c5fd8611e43904857 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 16 Dec 2018 11:49:38 +0100 Subject: [PATCH 2/7] pfreeze: fixes for Python 3.7 See python/cpython#5432 - imp module now has the proper name The DL_IMPORT and DL_EXPORT macros seem to have been removed. --- direct/src/showutil/FreezeTool.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/direct/src/showutil/FreezeTool.py b/direct/src/showutil/FreezeTool.py index aafbc24124..6114692092 100644 --- a/direct/src/showutil/FreezeTool.py +++ b/direct/src/showutil/FreezeTool.py @@ -42,10 +42,11 @@ builtinInitFuncs = { '__builtin__': None, 'sys': None, 'exceptions': None, - '_imp': 'PyInit_imp', '_warnings': '_PyWarnings_Init', 'marshal': 'PyMarshal_Init', } +if sys.version_info < (3, 7): + builtinInitFuncs['_imp'] = 'PyInit_imp' # These are missing modules that we've reported already this session. reportedMissing = {} @@ -256,7 +257,7 @@ frozenMainCode = """ extern void PyWinFreeze_ExeInit(void); extern void PyWinFreeze_ExeTerm(void); -extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab); +extern PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab); #endif /* Main program */ @@ -1394,7 +1395,7 @@ class Freezer: libName = module.split('.')[-1] initFunc = builtinInitFuncs.get(module, 'PyInit_' + libName) if initFunc: - text += 'extern DL_IMPORT(PyObject) *%s(void);\n' % (initFunc) + text += 'extern PyAPI_FUNC(PyObject) *%s(void);\n' % (initFunc) text += '\n' if sys.platform == "win32": @@ -1417,7 +1418,7 @@ class Freezer: libName = module.split('.')[-1] initFunc = builtinInitFuncs.get(module, 'init' + libName) if initFunc: - text += 'extern DL_IMPORT(void) %s(void);\n' % (initFunc) + text += 'extern PyAPI_FUNC(void) %s(void);\n' % (initFunc) text += '\n' if sys.platform == "win32": From 3a3cb01148820ffd396a5903dbe5d4a680684372 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 16 Dec 2018 18:43:31 +0100 Subject: [PATCH 3/7] showbase: return Transitions fade to aspect2d, fix focus issue This implements a slightly different solution for #311 that maintains the behaviour for the fade screen to prevent clicks from propagating to the geometry below it. Fixes #475 Fixes #311 --- direct/src/showbase/Transitions.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/direct/src/showbase/Transitions.py b/direct/src/showbase/Transitions.py index 9e05daad3e..54d7bd2baa 100644 --- a/direct/src/showbase/Transitions.py +++ b/direct/src/showbase/Transitions.py @@ -89,6 +89,8 @@ class Transitions: self.fade.setBin('unsorted', 0) self.fade.setColor(0,0,0,0) + self.fade.setScale(max(base.a2dRight, base.a2dTop)) + def getFadeInIval(self, t=0.5, finishIval=None, blendType='noBlend'): """ Returns an interval without starting it. This is particularly useful in @@ -97,8 +99,7 @@ class Transitions: #self.noTransitions() masad: this creates a one frame pop, is it necessary? self.loadFade() - parent = aspect2d if self.fadeModel else render2d - transitionIval = Sequence(Func(self.fade.reparentTo, parent, DGG.FADE_SORT_INDEX), + transitionIval = Sequence(Func(self.fade.reparentTo, aspect2d, DGG.FADE_SORT_INDEX), Func(self.fade.showThrough), # in case aspect2d is hidden for some reason self.lerpFunc(self.fade, t, self.alphaOff, @@ -120,8 +121,7 @@ class Transitions: self.noTransitions() self.loadFade() - parent = aspect2d if self.fadeModel else render2d - transitionIval = Sequence(Func(self.fade.reparentTo, parent, DGG.FADE_SORT_INDEX), + transitionIval = Sequence(Func(self.fade.reparentTo, aspect2d, DGG.FADE_SORT_INDEX), Func(self.fade.showThrough), # in case aspect2d is hidden for some reason self.lerpFunc(self.fade, t, self.alphaOn, @@ -181,8 +181,7 @@ class Transitions: self.noTransitions() self.loadFade() - parent = aspect2d if self.fadeModel else render2d - self.fade.reparentTo(parent, DGG.FADE_SORT_INDEX) + self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(self.alphaOn) elif ConfigVariableBool('no-loading-screen', False): if finishIval: @@ -215,8 +214,7 @@ class Transitions: self.noTransitions() self.loadFade() - parent = aspect2d if self.fadeModel else render2d - self.fade.reparentTo(parent, DGG.FADE_SORT_INDEX) + self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(self.alphaOn[0], self.alphaOn[1], self.alphaOn[2], @@ -232,8 +230,7 @@ class Transitions: self.noTransitions() self.loadFade() - parent = aspect2d if self.fadeModel else render2d - self.fade.reparentTo(parent, DGG.FADE_SORT_INDEX) + self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(color) def noFade(self): From 7995d483abbb84af56d22b20adab7ab3cbe1fd1c Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 16 Dec 2018 18:46:11 +0100 Subject: [PATCH 4/7] py_panda: make standard_type_members static and internal --- dtool/src/interrogatedb/dtool_super_base.cxx | 10 ++++++++++ dtool/src/interrogatedb/py_panda.cxx | 10 ---------- dtool/src/interrogatedb/py_panda.h | 3 --- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/dtool/src/interrogatedb/dtool_super_base.cxx b/dtool/src/interrogatedb/dtool_super_base.cxx index 01dcdef077..9422084299 100644 --- a/dtool/src/interrogatedb/dtool_super_base.cxx +++ b/dtool/src/interrogatedb/dtool_super_base.cxx @@ -15,6 +15,16 @@ #ifdef HAVE_PYTHON +static PyMemberDef standard_type_members[] = { + {(char *)"this", (sizeof(void*) == sizeof(int)) ? T_UINT : T_ULONGLONG, offsetof(Dtool_PyInstDef, _ptr_to_object), READONLY, (char *)"C++ 'this' pointer, if any"}, + {(char *)"this_ownership", T_BOOL, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"}, + {(char *)"this_const", T_BOOL, offsetof(Dtool_PyInstDef, _is_const), READONLY, (char *)"C++ 'this' const flag"}, +// {(char *)"this_signature", T_INT, offsetof(Dtool_PyInstDef, _signature), +// READONLY, (char *)"A type check signature"}, + {(char *)"this_metatype", T_OBJECT, offsetof(Dtool_PyInstDef, _My_Type), READONLY, (char *)"The dtool meta object"}, + {nullptr} /* Sentinel */ +}; + static PyObject *GetSuperBase(PyObject *self) { Dtool_PyTypedObject *super_base = Dtool_GetSuperBase(); Py_XINCREF((PyTypeObject *)super_base); // order is important .. this is used for static functions diff --git a/dtool/src/interrogatedb/py_panda.cxx b/dtool/src/interrogatedb/py_panda.cxx index bb7b5717f4..0c8b2416d7 100644 --- a/dtool/src/interrogatedb/py_panda.cxx +++ b/dtool/src/interrogatedb/py_panda.cxx @@ -12,16 +12,6 @@ using std::string; -PyMemberDef standard_type_members[] = { - {(char *)"this", (sizeof(void*) == sizeof(int)) ? T_UINT : T_ULONGLONG, offsetof(Dtool_PyInstDef, _ptr_to_object), READONLY, (char *)"C++ 'this' pointer, if any"}, - {(char *)"this_ownership", T_BOOL, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"}, - {(char *)"this_const", T_BOOL, offsetof(Dtool_PyInstDef, _is_const), READONLY, (char *)"C++ 'this' const flag"}, -// {(char *)"this_signature", T_INT, offsetof(Dtool_PyInstDef, _signature), -// READONLY, (char *)"A type check signature"}, - {(char *)"this_metatype", T_OBJECT, offsetof(Dtool_PyInstDef, _My_Type), READONLY, (char *)"The dtool meta object"}, - {nullptr} /* Sentinel */ -}; - /** */ diff --git a/dtool/src/interrogatedb/py_panda.h b/dtool/src/interrogatedb/py_panda.h index fa7981697b..ec2765e77a 100644 --- a/dtool/src/interrogatedb/py_panda.h +++ b/dtool/src/interrogatedb/py_panda.h @@ -67,9 +67,6 @@ struct Dtool_PyInstDef { bool _is_const; }; -// A Offset Dictionary Defining How to read the Above Object.. -extern PyMemberDef standard_type_members[]; - // The Class Definition Structor For a Dtool python type. struct Dtool_PyTypedObject { // Standard Python Features.. From 73452957eee582a882b9b03d97c8dd1a9bd4ed8f Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 16 Dec 2018 20:36:22 +0100 Subject: [PATCH 5/7] gobj: better handle NaNs in vertex data when calculating bounds --- panda/src/gobj/geom.cxx | 12 ++--- panda/src/gobj/geomPrimitive.cxx | 76 +++++++++++++++++++------------- tests/gobj/test_geom.py | 42 ++++++++++++++++++ 3 files changed, 94 insertions(+), 36 deletions(-) diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 8bede7327b..3b6dee026a 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -1338,7 +1338,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { // Now actually compute the bounding volume. We do this by using // calc_tight_bounds to determine our box first. LPoint3 pmin, pmax; - PN_stdfloat sq_center_dist; + PN_stdfloat sq_center_dist = 0.0f; bool found_any = false; do_calc_tight_bounds(pmin, pmax, sq_center_dist, found_any, vertex_data, false, LMatrix4::ident_mat(), @@ -1379,7 +1379,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { LPoint3 aabb_center = (pmin + pmax) * 0.5f; PN_stdfloat best_sq_radius = (pmax - aabb_center).length_squared(); - if (btype != BoundingVolume::BT_fastest && + if (btype != BoundingVolume::BT_fastest && best_sq_radius > 0.0f && aabb_center.length_squared() / best_sq_radius >= (0.2f * 0.2f)) { // Hmm, this is an off-center model. Maybe we can do a better job // by calculating the bounding sphere from the AABB center. @@ -1389,7 +1389,8 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { do_calc_sphere_radius(aabb_center, better_sq_radius, found_any, vertex_data, cdata, current_thread); - if (found_any && better_sq_radius <= best_sq_radius) { + if (found_any && better_sq_radius > 0.0f && + better_sq_radius <= best_sq_radius) { // Great. This is as good a sphere as we're going to get. if (btype == BoundingVolume::BT_best && avg_box_area < better_sq_radius * MathNumbers::pi) { @@ -1409,7 +1410,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { cdata->_internal_bounds = new BoundingBox(pmin, pmax); break; - } else if (sq_center_dist <= best_sq_radius) { + } else if (sq_center_dist >= 0.0f && sq_center_dist <= best_sq_radius) { // No, but a sphere centered on the origin is apparently still // better than a sphere around the bounding box. cdata->_internal_bounds = @@ -1420,7 +1421,8 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { // This is the worst sphere we can make, which is why we will only // do it when the user specifically requests a sphere. cdata->_internal_bounds = - new BoundingSphere(aabb_center, csqrt(best_sq_radius)); + new BoundingSphere(aabb_center, + (best_sq_radius > 0.0f) ? csqrt(best_sq_radius) : 0.0f); break; } } diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index 2cd5e2739a..6fa66329ba 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -1607,13 +1607,16 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, } if (got_mat) { - if (!found_any) { - reader.set_row_unsafe(cdata->_first_vertex); + // Find the first non-NaN vertex. + while (!found_any && i < cdata->_num_vertices) { + reader.set_row(cdata->_first_vertex + i); LPoint3 first_vertex = mat.xform_point(reader.get_data3()); - min_point = first_vertex; - max_point = first_vertex; - sq_center_dist = first_vertex.length_squared(); - found_any = true; + if (!first_vertex.is_nan()) { + min_point = first_vertex; + max_point = first_vertex; + sq_center_dist = first_vertex.length_squared(); + found_any = true; + } ++i; } @@ -1630,13 +1633,16 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, sq_center_dist = max(sq_center_dist, vertex.length_squared()); } } else { - if (!found_any) { - reader.set_row_unsafe(cdata->_first_vertex); - const LVecBase3 &first_vertex = reader.get_data3(); - min_point = first_vertex; - max_point = first_vertex; - sq_center_dist = first_vertex.length_squared(); - found_any = true; + // Find the first non-NaN vertex. + while (!found_any && i < cdata->_num_vertices) { + reader.set_row(cdata->_first_vertex + i); + LPoint3 first_vertex = reader.get_data3(); + if (!first_vertex.is_nan()) { + min_point = first_vertex; + max_point = first_vertex; + sq_center_dist = first_vertex.length_squared(); + found_any = true; + } ++i; } @@ -1664,15 +1670,19 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, int strip_cut_index = get_strip_cut_index(cdata->_index_type); if (got_mat) { - if (!found_any) { - int first_index = index.get_data1i(); - nassertv(first_index != strip_cut_index); - reader.set_row_unsafe(first_index); - LPoint3 first_vertex = mat.xform_point(reader.get_data3()); - min_point = first_vertex; - max_point = first_vertex; - sq_center_dist = first_vertex.length_squared(); - found_any = true; + // Find the first non-NaN vertex. + while (!found_any && !index.is_at_end()) { + int ii = index.get_data1i(); + if (ii != strip_cut_index) { + reader.set_row(ii); + LPoint3 first_vertex = mat.xform_point(reader.get_data3()); + if (!first_vertex.is_nan()) { + min_point = first_vertex; + max_point = first_vertex; + sq_center_dist = first_vertex.length_squared(); + found_any = true; + } + } } while (!index.is_at_end()) { @@ -1692,15 +1702,19 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, sq_center_dist = max(sq_center_dist, vertex.length_squared()); } } else { - if (!found_any) { - int first_index = index.get_data1i(); - nassertv(first_index != strip_cut_index); - reader.set_row_unsafe(first_index); - const LVecBase3 &first_vertex = reader.get_data3(); - min_point = first_vertex; - max_point = first_vertex; - sq_center_dist = first_vertex.length_squared(); - found_any = true; + // Find the first non-NaN vertex. + while (!found_any && !index.is_at_end()) { + int ii = index.get_data1i(); + if (ii != strip_cut_index) { + reader.set_row(ii); + LVecBase3 first_vertex = reader.get_data3(); + if (!first_vertex.is_nan()) { + min_point = first_vertex; + max_point = first_vertex; + sq_center_dist = first_vertex.length_squared(); + found_any = true; + } + } } while (!index.is_at_end()) { diff --git a/tests/gobj/test_geom.py b/tests/gobj/test_geom.py index 2a5a462659..24eeab852f 100644 --- a/tests/gobj/test_geom.py +++ b/tests/gobj/test_geom.py @@ -40,3 +40,45 @@ def test_geom_decompose(): # Old primitive should still be unchanged assert prim == geom.get_primitive(0) + + +def test_geom_calc_sphere_bounds(): + # Ensure that it ignores NaN + data = core.GeomVertexData("", core.GeomVertexFormat.get_v3(), core.Geom.UH_static) + vertex = core.GeomVertexWriter(data, "vertex") + vertex.add_data3((float("NaN"), 0, 0)) + vertex.add_data3((1, 1, 1)) + vertex.add_data3((1, 1, 2)) + + prim = core.GeomPoints(core.Geom.UH_static) + prim.add_next_vertices(3) + + geom = core.Geom(data) + geom.add_primitive(prim) + geom.set_bounds_type(core.BoundingVolume.BT_sphere) + + bounds = geom.get_bounds() + assert isinstance(bounds, core.BoundingSphere) + assert bounds.get_center() == (1, 1, 1.5) + assert bounds.get_radius() == 0.5 + + +def test_geom_calc_box_bounds(): + # Ensure that it ignores NaN + data = core.GeomVertexData("", core.GeomVertexFormat.get_v3(), core.Geom.UH_static) + vertex = core.GeomVertexWriter(data, "vertex") + vertex.add_data3((float("NaN"), 0, 0)) + vertex.add_data3((1, 1, 1)) + vertex.add_data3((1, 1, 2)) + + prim = core.GeomPoints(core.Geom.UH_static) + prim.add_next_vertices(3) + + geom = core.Geom(data) + geom.add_primitive(prim) + geom.set_bounds_type(core.BoundingVolume.BT_box) + + bounds = geom.get_bounds() + assert isinstance(bounds, core.BoundingBox) + assert bounds.get_min() == (1, 1, 1) + assert bounds.get_max() == (1, 1, 2) From 65a86d1b3fa5127acd345d0d2b5b29a6e4a0fced Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 16 Dec 2018 21:01:38 +0100 Subject: [PATCH 6/7] shader: warn if GLSL shader does not contain #version line Shaders without #version line (which are supposed to indicate GLSL 1.10) will be interpreted differently by different drivers, so this is almost certainly a mistake. In the future, we can forbid this altogether or insert #version 110 automatically. --- panda/src/gobj/shader.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/panda/src/gobj/shader.cxx b/panda/src/gobj/shader.cxx index 4a1092eb9c..fde084aa18 100644 --- a/panda/src/gobj/shader.cxx +++ b/panda/src/gobj/shader.cxx @@ -2750,6 +2750,7 @@ r_preprocess_source(ostream &out, istream &in, const Filename &fn, int ext_google_include = 0; // 1 = warn, 2 = enable int ext_google_line = 0; bool had_include = false; + bool had_version = false; int lineno = 0; bool write_line_directive = (fileno != 0); @@ -2920,6 +2921,9 @@ r_preprocess_source(ostream &out, istream &in, const Filename &fn, write_line_directive = true; } + } else if (strcmp(directive, "version") == 0) { + had_version = true; + } else if (strcmp(directive, "extension") == 0) { // Check for special preprocessing extensions. char extension[256]; @@ -3047,6 +3051,11 @@ r_preprocess_source(ostream &out, istream &in, const Filename &fn, out << line << "\n"; } + if (fileno == 0 && !had_version) { + shader_cat.warning() + << "GLSL shader " << fn << " does not contain a #version line!\n"; + } + return true; } From 6b8814f9c9d341d2a43f4f25f44481c136650846 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 16 Dec 2018 21:03:43 +0100 Subject: [PATCH 7/7] mathutil: add some properties for bounding volumes --- panda/src/mathutil/boundingSphere.h | 2 ++ panda/src/mathutil/finiteBoundingVolume.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/panda/src/mathutil/boundingSphere.h b/panda/src/mathutil/boundingSphere.h index 8c105daa01..2e63fb3396 100644 --- a/panda/src/mathutil/boundingSphere.h +++ b/panda/src/mathutil/boundingSphere.h @@ -47,6 +47,8 @@ PUBLISHED: INLINE_MATHUTIL void set_center(const LPoint3 ¢er); INLINE_MATHUTIL void set_radius(PN_stdfloat radius); + MAKE_PROPERTY(center, get_center, set_center); + MAKE_PROPERTY(radius, get_radius, set_radius); public: virtual const BoundingSphere *as_bounding_sphere() const; diff --git a/panda/src/mathutil/finiteBoundingVolume.h b/panda/src/mathutil/finiteBoundingVolume.h index e344151685..e527faa88b 100644 --- a/panda/src/mathutil/finiteBoundingVolume.h +++ b/panda/src/mathutil/finiteBoundingVolume.h @@ -30,6 +30,10 @@ PUBLISHED: virtual LPoint3 get_max() const=0; virtual PN_stdfloat get_volume() const; + MAKE_PROPERTY(min, get_min); + MAKE_PROPERTY(max, get_max); + MAKE_PROPERTY(volume, get_volume); + public: virtual const FiniteBoundingVolume *as_finite_bounding_volume() const;