From 6105953b40d424e932a8f4a8446b0ecca19dd6b7 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 14 Aug 2018 17:23:48 -0600 Subject: [PATCH 01/17] general: Add forgotten include --- panda/src/collide/collisionBox.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/panda/src/collide/collisionBox.cxx b/panda/src/collide/collisionBox.cxx index 119284f905..a8af257456 100644 --- a/panda/src/collide/collisionBox.cxx +++ b/panda/src/collide/collisionBox.cxx @@ -16,6 +16,7 @@ #include "collisionRay.h" #include "collisionSphere.h" #include "collisionSegment.h" +#include "collisionTube.h" #include "collisionHandler.h" #include "collisionEntry.h" #include "config_collide.h" From 06f7da521548609f2e32b549b6728253c81c5162 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 14 Aug 2018 21:56:52 -0600 Subject: [PATCH 02/17] express: Fix misclassified EXPCL_PANDA_ macro --- panda/src/express/zStreamBuf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/express/zStreamBuf.h b/panda/src/express/zStreamBuf.h index 35446090db..3dadd1543d 100644 --- a/panda/src/express/zStreamBuf.h +++ b/panda/src/express/zStreamBuf.h @@ -24,7 +24,7 @@ /** * The streambuf object that implements IDecompressStream and OCompressStream. */ -class EXPCL_PANDA_DOWNLOADER ZStreamBuf : public std::streambuf { +class EXPCL_PANDA_EXPRESS ZStreamBuf : public std::streambuf { public: ZStreamBuf(); virtual ~ZStreamBuf(); From 97d6d84adef4f072e6273d5a1b05c41f612fe228 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Wed, 15 Aug 2018 20:38:00 -0600 Subject: [PATCH 03/17] dcparser: Add BUILDING_DIRECT_DCPARSER switch Resolves GH #342. --- direct/src/dcparser/dcArrayParameter.h | 2 +- direct/src/dcparser/dcAtomicField.h | 2 +- direct/src/dcparser/dcClass.h | 2 +- direct/src/dcparser/dcClassParameter.h | 2 +- direct/src/dcparser/dcDeclaration.h | 2 +- direct/src/dcparser/dcField.h | 2 +- direct/src/dcparser/dcFile.h | 2 +- direct/src/dcparser/dcKeyword.h | 2 +- direct/src/dcparser/dcKeywordList.h | 2 +- direct/src/dcparser/dcMolecularField.h | 2 +- direct/src/dcparser/dcNumericRange.h | 2 +- direct/src/dcparser/dcPackData.h | 2 +- direct/src/dcparser/dcPacker.h | 2 +- direct/src/dcparser/dcPackerCatalog.h | 2 +- direct/src/dcparser/dcPackerInterface.h | 2 +- direct/src/dcparser/dcParameter.h | 2 +- direct/src/dcparser/dcParserDefs.h | 2 +- direct/src/dcparser/dcSimpleParameter.h | 2 +- direct/src/dcparser/dcSwitch.h | 2 +- direct/src/dcparser/dcSwitchParameter.h | 2 +- direct/src/dcparser/dcTypedef.h | 2 +- direct/src/dcparser/dcbase.h | 5 +++++ direct/src/dcparser/hashGenerator.h | 2 +- direct/src/dcparser/primeNumberGenerator.h | 2 +- direct/src/directbase/directsymbols.h | 9 +++++++++ 25 files changed, 37 insertions(+), 23 deletions(-) diff --git a/direct/src/dcparser/dcArrayParameter.h b/direct/src/dcparser/dcArrayParameter.h index fd5008fb97..97fb32bdf0 100644 --- a/direct/src/dcparser/dcArrayParameter.h +++ b/direct/src/dcparser/dcArrayParameter.h @@ -23,7 +23,7 @@ * parameter type accepts an arbitrary (or possibly fixed) number of nested * fields, all of which are of the same type. */ -class DCArrayParameter : public DCParameter { +class EXPCL_DIRECT_DCPARSER DCArrayParameter : public DCParameter { public: DCArrayParameter(DCParameter *element_type, const DCUnsignedIntRange &size = DCUnsignedIntRange()); diff --git a/direct/src/dcparser/dcAtomicField.h b/direct/src/dcparser/dcAtomicField.h index e0d7cee58e..9eb92e2527 100644 --- a/direct/src/dcparser/dcAtomicField.h +++ b/direct/src/dcparser/dcAtomicField.h @@ -27,7 +27,7 @@ * This defines an interface to the Distributed Class, and is always * implemented as a remote procedure method. */ -class DCAtomicField : public DCField { +class EXPCL_DIRECT_DCPARSER DCAtomicField : public DCField { public: DCAtomicField(const std::string &name, DCClass *dclass, bool bogus_field); virtual ~DCAtomicField(); diff --git a/direct/src/dcparser/dcClass.h b/direct/src/dcparser/dcClass.h index 9f7945b372..cd69716470 100644 --- a/direct/src/dcparser/dcClass.h +++ b/direct/src/dcparser/dcClass.h @@ -41,7 +41,7 @@ class DCParameter; /** * Defines a particular DistributedClass as read from an input .dc file. */ -class DCClass : public DCDeclaration { +class EXPCL_DIRECT_DCPARSER DCClass : public DCDeclaration { public: DCClass(DCFile *dc_file, const std::string &name, bool is_struct, bool bogus_class); diff --git a/direct/src/dcparser/dcClassParameter.h b/direct/src/dcparser/dcClassParameter.h index 3657190bf9..05b84e84c3 100644 --- a/direct/src/dcparser/dcClassParameter.h +++ b/direct/src/dcparser/dcClassParameter.h @@ -23,7 +23,7 @@ class DCClass; * This represents a class (or struct) object used as a parameter itself. * This means that all the fields of the class get packed into the message. */ -class DCClassParameter : public DCParameter { +class EXPCL_DIRECT_DCPARSER DCClassParameter : public DCParameter { public: DCClassParameter(const DCClass *dclass); DCClassParameter(const DCClassParameter ©); diff --git a/direct/src/dcparser/dcDeclaration.h b/direct/src/dcparser/dcDeclaration.h index 0fd4392ca6..c6b8b7dd54 100644 --- a/direct/src/dcparser/dcDeclaration.h +++ b/direct/src/dcparser/dcDeclaration.h @@ -26,7 +26,7 @@ class DCSwitch; * only purpose is so that classes and typedefs can be stored in one list * together so they can be ordered correctly on output. */ -class DCDeclaration { +class EXPCL_DIRECT_DCPARSER DCDeclaration { public: virtual ~DCDeclaration(); diff --git a/direct/src/dcparser/dcField.h b/direct/src/dcparser/dcField.h index 6744ea93d4..dc06ff76f2 100644 --- a/direct/src/dcparser/dcField.h +++ b/direct/src/dcparser/dcField.h @@ -34,7 +34,7 @@ class HashGenerator; /** * A single field of a Distributed Class, either atomic or molecular. */ -class DCField : public DCPackerInterface, public DCKeywordList { +class EXPCL_DIRECT_DCPARSER DCField : public DCPackerInterface, public DCKeywordList { public: DCField(); DCField(const std::string &name, DCClass *dclass); diff --git a/direct/src/dcparser/dcFile.h b/direct/src/dcparser/dcFile.h index 7d7550804f..37ebbe9181 100644 --- a/direct/src/dcparser/dcFile.h +++ b/direct/src/dcparser/dcFile.h @@ -29,7 +29,7 @@ class DCDeclaration; * Represents the complete list of Distributed Class descriptions as read from * a .dc file. */ -class DCFile { +class EXPCL_DIRECT_DCPARSER DCFile { PUBLISHED: DCFile(); ~DCFile(); diff --git a/direct/src/dcparser/dcKeyword.h b/direct/src/dcparser/dcKeyword.h index a82bd1ef0f..7447b6ed78 100644 --- a/direct/src/dcparser/dcKeyword.h +++ b/direct/src/dcparser/dcKeyword.h @@ -25,7 +25,7 @@ class HashGenerator; * define a communication property associated with a field, for instance * "broadcast" or "airecv". */ -class DCKeyword : public DCDeclaration { +class EXPCL_DIRECT_DCPARSER DCKeyword : public DCDeclaration { public: DCKeyword(const std::string &name, int historical_flag = ~0); virtual ~DCKeyword(); diff --git a/direct/src/dcparser/dcKeywordList.h b/direct/src/dcparser/dcKeywordList.h index d9905c64db..ac0ed574fe 100644 --- a/direct/src/dcparser/dcKeywordList.h +++ b/direct/src/dcparser/dcKeywordList.h @@ -23,7 +23,7 @@ class HashGenerator; * This is a list of keywords (see DCKeyword) that may be set on a particular * field. */ -class DCKeywordList { +class EXPCL_DIRECT_DCPARSER DCKeywordList { public: DCKeywordList(); DCKeywordList(const DCKeywordList ©); diff --git a/direct/src/dcparser/dcMolecularField.h b/direct/src/dcparser/dcMolecularField.h index db7d850e00..8983eddab0 100644 --- a/direct/src/dcparser/dcMolecularField.h +++ b/direct/src/dcparser/dcMolecularField.h @@ -25,7 +25,7 @@ class DCParameter; * This represents a combination of two or more related atomic fields, that * will often be treated as a unit. */ -class DCMolecularField : public DCField { +class EXPCL_DIRECT_DCPARSER DCMolecularField : public DCField { public: DCMolecularField(const std::string &name, DCClass *dclass); diff --git a/direct/src/dcparser/dcNumericRange.h b/direct/src/dcparser/dcNumericRange.h index b3450f89e4..f751323b01 100644 --- a/direct/src/dcparser/dcNumericRange.h +++ b/direct/src/dcparser/dcNumericRange.h @@ -23,7 +23,7 @@ * to constrain simple numeric types, as well as array sizes. */ template -class DCNumericRange { +class EXPCL_DIRECT_DCPARSER DCNumericRange { public: typedef NUM Number; diff --git a/direct/src/dcparser/dcPackData.h b/direct/src/dcparser/dcPackData.h index 7f891a1d5d..e5a3b53e5d 100644 --- a/direct/src/dcparser/dcPackData.h +++ b/direct/src/dcparser/dcPackData.h @@ -19,7 +19,7 @@ /** * This is a block of data that receives the results of DCPacker. */ -class DCPackData { +class EXPCL_DIRECT_DCPARSER DCPackData { PUBLISHED: INLINE DCPackData(); INLINE ~DCPackData(); diff --git a/direct/src/dcparser/dcPacker.h b/direct/src/dcparser/dcPacker.h index 9de32ff2cd..68a01a5999 100644 --- a/direct/src/dcparser/dcPacker.h +++ b/direct/src/dcparser/dcPacker.h @@ -31,7 +31,7 @@ class DCSwitchParameter; * See also direct/src/doc/dcPacker.txt for a more complete description and * examples of using this class. */ -class DCPacker { +class EXPCL_DIRECT_DCPARSER DCPacker { PUBLISHED: DCPacker(); ~DCPacker(); diff --git a/direct/src/dcparser/dcPackerCatalog.h b/direct/src/dcparser/dcPackerCatalog.h index c03b1b5fc6..9a37f84a41 100644 --- a/direct/src/dcparser/dcPackerCatalog.h +++ b/direct/src/dcparser/dcPackerCatalog.h @@ -26,7 +26,7 @@ class DCSwitchParameter; * requested from a particular field; its ownership is retained by the field * so it must not be deleted. */ -class DCPackerCatalog { +class EXPCL_DIRECT_DCPARSER DCPackerCatalog { private: DCPackerCatalog(const DCPackerInterface *root); DCPackerCatalog(const DCPackerCatalog ©); diff --git a/direct/src/dcparser/dcPackerInterface.h b/direct/src/dcparser/dcPackerInterface.h index 171ed3f0ca..ef28b85647 100644 --- a/direct/src/dcparser/dcPackerInterface.h +++ b/direct/src/dcparser/dcPackerInterface.h @@ -64,7 +64,7 @@ END_PUBLISH * Normally these methods are called only by the DCPacker object; the user * wouldn't normally call these directly. */ -class DCPackerInterface { +class EXPCL_DIRECT_DCPARSER DCPackerInterface { public: DCPackerInterface(const std::string &name = std::string()); DCPackerInterface(const DCPackerInterface ©); diff --git a/direct/src/dcparser/dcParameter.h b/direct/src/dcparser/dcParameter.h index 59a34dc440..49e6df12fe 100644 --- a/direct/src/dcparser/dcParameter.h +++ b/direct/src/dcparser/dcParameter.h @@ -32,7 +32,7 @@ class HashGenerator; * This may also be a typedef reference to another type, which has the same * properties as the referenced type, but a different name. */ -class DCParameter : public DCField { +class EXPCL_DIRECT_DCPARSER DCParameter : public DCField { protected: DCParameter(); DCParameter(const DCParameter ©); diff --git a/direct/src/dcparser/dcParserDefs.h b/direct/src/dcparser/dcParserDefs.h index da1747ab15..28659a37e3 100644 --- a/direct/src/dcparser/dcParserDefs.h +++ b/direct/src/dcparser/dcParserDefs.h @@ -43,7 +43,7 @@ extern DCFile *dc_file; // that has member functions in a union), so we'll use a class instead. That // means we need to declare it externally, here. -class DCTokenType { +class EXPCL_DIRECT_DCPARSER DCTokenType { public: union U { int s_int; diff --git a/direct/src/dcparser/dcSimpleParameter.h b/direct/src/dcparser/dcSimpleParameter.h index b6da9a8bff..7b47773a3d 100644 --- a/direct/src/dcparser/dcSimpleParameter.h +++ b/direct/src/dcparser/dcSimpleParameter.h @@ -25,7 +25,7 @@ * divisor, which is meaningful only for the numeric type elements (and * represents a fixed-point numeric convention). */ -class DCSimpleParameter : public DCParameter { +class EXPCL_DIRECT_DCPARSER DCSimpleParameter : public DCParameter { public: DCSimpleParameter(DCSubatomicType type, unsigned int divisor = 1); DCSimpleParameter(const DCSimpleParameter ©); diff --git a/direct/src/dcparser/dcSwitch.h b/direct/src/dcparser/dcSwitch.h index 17e4e856a2..ac58f5439d 100644 --- a/direct/src/dcparser/dcSwitch.h +++ b/direct/src/dcparser/dcSwitch.h @@ -27,7 +27,7 @@ class DCField; * and represents two or more alternative unpacking schemes based on the first * field read. */ -class DCSwitch : public DCDeclaration { +class EXPCL_DIRECT_DCPARSER DCSwitch : public DCDeclaration { public: DCSwitch(const std::string &name, DCField *key_parameter); virtual ~DCSwitch(); diff --git a/direct/src/dcparser/dcSwitchParameter.h b/direct/src/dcparser/dcSwitchParameter.h index 51b8b673f6..7d123493aa 100644 --- a/direct/src/dcparser/dcSwitchParameter.h +++ b/direct/src/dcparser/dcSwitchParameter.h @@ -23,7 +23,7 @@ class DCSwitch; * This represents a switch object used as a parameter itself, which packs the * appropriate fields of the switch into the message. */ -class DCSwitchParameter : public DCParameter { +class EXPCL_DIRECT_DCPARSER DCSwitchParameter : public DCParameter { public: DCSwitchParameter(const DCSwitch *dswitch); DCSwitchParameter(const DCSwitchParameter ©); diff --git a/direct/src/dcparser/dcTypedef.h b/direct/src/dcparser/dcTypedef.h index 654c8998a8..769f1f129f 100644 --- a/direct/src/dcparser/dcTypedef.h +++ b/direct/src/dcparser/dcTypedef.h @@ -23,7 +23,7 @@ class DCParameter; * This represents a single typedef declaration in the dc file. It assigns a * particular type to a new name, just like a C typedef. */ -class DCTypedef : public DCDeclaration { +class EXPCL_DIRECT_DCPARSER DCTypedef : public DCDeclaration { public: DCTypedef(DCParameter *parameter, bool implicit = false); DCTypedef(const std::string &name); diff --git a/direct/src/dcparser/dcbase.h b/direct/src/dcparser/dcbase.h index 4f2712f148..64ef117158 100644 --- a/direct/src/dcparser/dcbase.h +++ b/direct/src/dcparser/dcbase.h @@ -70,6 +70,11 @@ #define END_PUBLISH #define BLOCKING +// These control the declspec(dllexport/dllimport) on Windows. When compiling +// outside of Panda, we assume we aren't part of a DLL. +#define EXPCL_DIRECT_DCPARSER +#define EXPTP_DIRECT_DCPARSER + // Panda defines some assert-type macros. We map those to the standard assert // macro outside of Panda. #define nassertr(condition, return_value) assert(condition) diff --git a/direct/src/dcparser/hashGenerator.h b/direct/src/dcparser/hashGenerator.h index 94031cd2f6..29ae1a6609 100644 --- a/direct/src/dcparser/hashGenerator.h +++ b/direct/src/dcparser/hashGenerator.h @@ -20,7 +20,7 @@ /** * This class generates an arbitrary hash number from a sequence of ints. */ -class HashGenerator { +class EXPCL_DIRECT_DCPARSER HashGenerator { public: HashGenerator(); diff --git a/direct/src/dcparser/primeNumberGenerator.h b/direct/src/dcparser/primeNumberGenerator.h index 8b24ae6b5c..7aa49e09a9 100644 --- a/direct/src/dcparser/primeNumberGenerator.h +++ b/direct/src/dcparser/primeNumberGenerator.h @@ -30,7 +30,7 @@ typedef std::vector vector_int; * For a given integer n, it will return the nth prime number. This will * involve a recompute step only if n is greater than any previous n. */ -class PrimeNumberGenerator { +class EXPCL_DIRECT_DCPARSER PrimeNumberGenerator { public: PrimeNumberGenerator(); diff --git a/direct/src/directbase/directsymbols.h b/direct/src/directbase/directsymbols.h index cdd07e1a0c..55fd2bd4e8 100644 --- a/direct/src/directbase/directsymbols.h +++ b/direct/src/directbase/directsymbols.h @@ -18,6 +18,7 @@ /* BUILDING_DIRECT is just a buildsystem shortcut for all of these: */ #ifdef BUILDING_DIRECT + #define BUILDING_DIRECT_DCPARSER #define BUILDING_DIRECT_DEADREC #define BUILDING_DIRECT_DIRECTD #define BUILDING_DIRECT_INTERVAL @@ -26,6 +27,14 @@ #define BUILDING_DIRECT_DISTRIBUTED #endif +#ifdef BUILDING_DIRECT_DCPARSER + #define EXPCL_DIRECT_DCPARSER EXPORT_CLASS + #define EXPTP_DIRECT_DCPARSER EXPORT_TEMPL +#else + #define EXPCL_DIRECT_DCPARSER IMPORT_CLASS + #define EXPTP_DIRECT_DCPARSER IMPORT_TEMPL +#endif + #ifdef BUILDING_DIRECT_DEADREC #define EXPCL_DIRECT_DEADREC EXPORT_CLASS #define EXPTP_DIRECT_DEADREC EXPORT_TEMPL From ba345d590fbeba5c0103b1458971f576461bd526 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Aug 2018 13:40:38 +0200 Subject: [PATCH 04/17] express: make Datagram.get_message() return bytes in Python 3 This is done using a Python extension function, which also happens to make the call more efficient as this avoids an extra copy. The C++ version still returns std::string as there is still a lot of C++ code that relies on that. Fixes #297 --- panda/src/express/datagram.I | 12 ---------- panda/src/express/datagram.h | 7 +++++- panda/src/express/datagram_ext.I | 35 ++++++++++++++++++++++++++++ panda/src/express/datagram_ext.h | 40 ++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 panda/src/express/datagram_ext.I create mode 100644 panda/src/express/datagram_ext.h diff --git a/panda/src/express/datagram.I b/panda/src/express/datagram.I index 98b71820e5..8c555c777d 100644 --- a/panda/src/express/datagram.I +++ b/panda/src/express/datagram.I @@ -316,18 +316,6 @@ get_message() const { } } -/** - * Returns the datagram's data as a bytes object. - */ -INLINE vector_uchar Datagram:: -__bytes__() const { - if (!_data.empty()) { - return vector_uchar(_data.v()); - } else { - return vector_uchar(); - } -} - /** * Returns a pointer to the beginning of the datagram's data. */ diff --git a/panda/src/express/datagram.h b/panda/src/express/datagram.h index 69dce69e31..b2a3acb363 100644 --- a/panda/src/express/datagram.h +++ b/panda/src/express/datagram.h @@ -85,11 +85,16 @@ PUBLISHED: void append_data(const void *data, size_t size); INLINE void append_data(const vector_uchar &data); +public: void assign(const void *data, size_t size); INLINE std::string get_message() const; - INLINE vector_uchar __bytes__() const; INLINE const void *get_data() const; + +PUBLISHED: + EXTENSION(INLINE PyObject *get_message() const); + EXTENSION(INLINE PyObject *__bytes__() const); + INLINE size_t get_length() const; INLINE void set_array(PTA_uchar data); diff --git a/panda/src/express/datagram_ext.I b/panda/src/express/datagram_ext.I new file mode 100644 index 0000000000..a35c5410b2 --- /dev/null +++ b/panda/src/express/datagram_ext.I @@ -0,0 +1,35 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file datagram_ext.I + * @author rdb + * @date 2018-08-19 + */ + +/** + * Returns the datagram's data as a bytes object. + */ +INLINE PyObject *Extension:: +get_message() const { + const char *data = (const char *)_this->get_data(); + size_t size = _this->get_length(); + +#if PY_MAJOR_VERSION >= 3 + return PyBytes_FromStringAndSize((char *)data, size); +#else + return PyString_FromStringAndSize((char *)data, size); +#endif +} + +/** + * Returns the datagram's data as a bytes object. + */ +PyObject *Extension:: +__bytes__() const { + return get_message(); +} diff --git a/panda/src/express/datagram_ext.h b/panda/src/express/datagram_ext.h new file mode 100644 index 0000000000..35f2e32bc6 --- /dev/null +++ b/panda/src/express/datagram_ext.h @@ -0,0 +1,40 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file datagram_ext.h + * @author rdb + * @date 2018-08-19 + */ + +#ifndef DATAGRAM_EXT_H +#define DATAGRAM_EXT_H + +#include "dtoolbase.h" + +#ifdef HAVE_PYTHON + +#include "extension.h" +#include "datagram.h" +#include "py_panda.h" + +/** + * This class defines the extension methods for Datagram, which are called + * instead of any C++ methods with the same prototype. + */ +template<> +class Extension : public ExtensionBase { +public: + INLINE PyObject *get_message() const; + INLINE PyObject *__bytes__() const; +}; + +#include "datagram_ext.I" + +#endif // HAVE_PYTHON + +#endif // DATAGRAM_EXT_H From 74442e41f14539504305b0f9d50e61f4af4af6ec Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Aug 2018 14:21:23 +0200 Subject: [PATCH 05/17] express: slight Datagram constructor cleanup --- panda/src/express/datagram.I | 29 ++--------------------------- panda/src/express/datagram.h | 9 +++++++-- 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/panda/src/express/datagram.I b/panda/src/express/datagram.I index 8c555c777d..350fa3d30c 100644 --- a/panda/src/express/datagram.I +++ b/panda/src/express/datagram.I @@ -11,30 +11,11 @@ * @date 2000-06-06 */ -/** - * Constructs an empty datagram. - */ -INLINE Datagram:: -Datagram() : -#ifdef STDFLOAT_DOUBLE - _stdfloat_double(true) -#else - _stdfloat_double(false) -#endif -{ -} - /** * Constructs a datagram from an existing block of data. */ INLINE Datagram:: -Datagram(const void *data, size_t size) : -#ifdef STDFLOAT_DOUBLE - _stdfloat_double(true) -#else - _stdfloat_double(false) -#endif -{ +Datagram(const void *data, size_t size) { append_data(data, size); } @@ -43,13 +24,7 @@ Datagram(const void *data, size_t size) : */ INLINE Datagram:: Datagram(vector_uchar data) : - _data(std::move(data)), -#ifdef STDFLOAT_DOUBLE - _stdfloat_double(true) -#else - _stdfloat_double(false) -#endif -{ + _data(std::move(data)) { } /** diff --git a/panda/src/express/datagram.h b/panda/src/express/datagram.h index b2a3acb363..420175c114 100644 --- a/panda/src/express/datagram.h +++ b/panda/src/express/datagram.h @@ -37,7 +37,7 @@ */ class EXPCL_PANDA_EXPRESS Datagram : public TypedObject { PUBLISHED: - INLINE Datagram(); + INLINE Datagram() = default; INLINE Datagram(const void *data, size_t size); INLINE explicit Datagram(vector_uchar data); Datagram(const Datagram ©) = default; @@ -114,7 +114,12 @@ PUBLISHED: private: PTA_uchar _data; - bool _stdfloat_double; + +#ifdef STDFLOAT_DOUBLE + bool _stdfloat_double = true; +#else + bool _stdfloat_double = false; +#endif public: From b1d21110372250b1c91a3829ae0c3f809a7d99d2 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Aug 2018 16:01:39 +0200 Subject: [PATCH 06/17] express: add Datagram add_blob and add_blob32, et al. This is for writing Python 2/3 agnostic code for writing binary data to a datagram, and reading from it using DatagramIterator. --- direct/src/distributed/PyDatagram.py | 4 +-- direct/src/distributed/PyDatagramIterator.py | 4 +-- panda/src/express/datagram.I | 34 ++++++++++++++++++++ panda/src/express/datagram.h | 5 +++ panda/src/express/datagramIterator.I | 21 ++++++++++++ panda/src/express/datagramIterator.h | 3 ++ panda/src/recorder/socketStreamRecorder.cxx | 5 +-- tests/putil/test_datagram.py | 12 +++++++ 8 files changed, 80 insertions(+), 8 deletions(-) diff --git a/direct/src/distributed/PyDatagram.py b/direct/src/distributed/PyDatagram.py index eebc06e440..f45c3c52c1 100755 --- a/direct/src/distributed/PyDatagram.py +++ b/direct/src/distributed/PyDatagram.py @@ -25,8 +25,8 @@ class PyDatagram(Datagram): STUint64: (Datagram.addUint64, int), STFloat64: (Datagram.addFloat64, None), STString: (Datagram.addString, None), - STBlob: (Datagram.addString, None), - STBlob32: (Datagram.addString32, None), + STBlob: (Datagram.addBlob, None), + STBlob32: (Datagram.addBlob32, None), } #def addChannel(self, channelId): diff --git a/direct/src/distributed/PyDatagramIterator.py b/direct/src/distributed/PyDatagramIterator.py index 60267a1ab9..6ce96e77e4 100755 --- a/direct/src/distributed/PyDatagramIterator.py +++ b/direct/src/distributed/PyDatagramIterator.py @@ -23,8 +23,8 @@ class PyDatagramIterator(DatagramIterator): STUint64: DatagramIterator.getUint64, STFloat64: DatagramIterator.getFloat64, STString: DatagramIterator.getString, - STBlob: DatagramIterator.getString, - STBlob32: DatagramIterator.getString32, + STBlob: DatagramIterator.getBlob, + STBlob32: DatagramIterator.getBlob32, } getChannel = DatagramIterator.getUint64 diff --git a/panda/src/express/datagram.I b/panda/src/express/datagram.I index 350fa3d30c..42cc6b9cf1 100644 --- a/panda/src/express/datagram.I +++ b/panda/src/express/datagram.I @@ -270,6 +270,35 @@ add_fixed_string(const std::string &str, size_t size) { } } +/** + * Adds a variable-length binary blob to the datagram. This actually adds a + * count followed by n bytes. + */ +INLINE void Datagram:: +add_blob(const vector_uchar &data) { + // The max sendable size for a blob is 2^16. + nassertv(data.size() <= (uint16_t)0xffff); + + // Blobs always are preceded by their size + add_uint16((uint16_t)data.size()); + + // Add the blob + append_data(data.data(), data.size()); +} + +/** + * Adds a variable-length binary blob to the datagram, using a 32-bit length + * field to allow very long blobs. + */ +INLINE void Datagram:: +add_blob32(const vector_uchar &data) { + // Blobs always are preceded by their size + add_uint32((uint32_t)data.size()); + + // Add the blob + append_data(data.data(), data.size()); +} + /** * Appends some more raw data to the end of the datagram. */ @@ -445,3 +474,8 @@ INLINE void generic_write_datagram(Datagram &dest, const std::wstring &value) { dest.add_wstring(value); } + +INLINE void +generic_write_datagram(Datagram &dest, const vector_uchar &value) { + dest.add_blob(value); +} diff --git a/panda/src/express/datagram.h b/panda/src/express/datagram.h index 420175c114..9611645eed 100644 --- a/panda/src/express/datagram.h +++ b/panda/src/express/datagram.h @@ -81,6 +81,9 @@ PUBLISHED: INLINE void add_fixed_string(const std::string &str, size_t size); void add_wstring(const std::wstring &str); + INLINE void add_blob(const vector_uchar &); + INLINE void add_blob32(const vector_uchar &); + void pad_bytes(size_t size); void append_data(const void *data, size_t size); INLINE void append_data(const vector_uchar &data); @@ -158,6 +161,8 @@ INLINE void generic_write_datagram(Datagram &dest, const std::string &value); INLINE void generic_write_datagram(Datagram &dest, const std::wstring &value); +INLINE void +generic_write_datagram(Datagram &dest, const vector_uchar &value); #include "datagram.I" diff --git a/panda/src/express/datagramIterator.I b/panda/src/express/datagramIterator.I index 763850b60c..140151089a 100644 --- a/panda/src/express/datagramIterator.I +++ b/panda/src/express/datagramIterator.I @@ -400,6 +400,22 @@ get_be_float64() { return tempvar; } +/** + * Extracts a variable-length binary blob. + */ +INLINE vector_uchar DatagramIterator:: +get_blob() { + return extract_bytes(get_uint16()); +} + +/** + * Extracts a variable-length binary blob with a 32-bit size field. + */ +INLINE vector_uchar DatagramIterator:: +get_blob32() { + return extract_bytes(get_uint32()); +} + /** * Skips over the indicated number of bytes in the datagram. */ @@ -485,3 +501,8 @@ INLINE void generic_read_datagram(std::wstring &result, DatagramIterator &source) { result = source.get_wstring(); } + +INLINE void +generic_read_datagram(vector_uchar &result, DatagramIterator &source) { + result = source.get_blob(); +} diff --git a/panda/src/express/datagramIterator.h b/panda/src/express/datagramIterator.h index 570e34c3c4..867c7de58c 100644 --- a/panda/src/express/datagramIterator.h +++ b/panda/src/express/datagramIterator.h @@ -61,6 +61,9 @@ PUBLISHED: std::string get_fixed_string(size_t size); std::wstring get_wstring(); + INLINE vector_uchar get_blob(); + INLINE vector_uchar get_blob32(); + INLINE void skip_bytes(size_t size); vector_uchar extract_bytes(size_t size); size_t extract_bytes(unsigned char *into, size_t size); diff --git a/panda/src/recorder/socketStreamRecorder.cxx b/panda/src/recorder/socketStreamRecorder.cxx index 5ee6168d44..8418485b20 100644 --- a/panda/src/recorder/socketStreamRecorder.cxx +++ b/panda/src/recorder/socketStreamRecorder.cxx @@ -82,10 +82,7 @@ play_frame(DatagramIterator &scan, BamReader *manager) { int num_packets = scan.get_uint16(); for (int i = 0; i < num_packets; i++) { - size_t size = scan.get_uint16(); - vector_uchar packet(size); - scan.extract_bytes(&packet[0], size); - _data.push_back(Datagram(std::move(packet))); + _data.push_back(Datagram(scan.get_blob())); } } diff --git a/tests/putil/test_datagram.py b/tests/putil/test_datagram.py index 171363109a..7919a1360f 100644 --- a/tests/putil/test_datagram.py +++ b/tests/putil/test_datagram.py @@ -28,6 +28,9 @@ def datagram_small(request): dg.add_string32('this is another string') dg.add_string('this is yet a third string') + dg.add_blob(b'blob data \x00\xf2\xa0\x00\x00') + dg.add_blob32(b'\xc9\x8f\x00 test blob32') + dg.add_stdfloat(800.2) dg.add_stdfloat(3.1415926) dg.add_stdfloat(2.7182818) @@ -49,6 +52,9 @@ def datagram_small(request): assert dgi.get_string32() == 'this is another string' assert dgi.get_string() == 'this is yet a third string' + assert dgi.get_blob() == b'blob data \x00\xf2\xa0\x00\x00' + assert dgi.get_blob32() == b'\xc9\x8f\x00 test blob32' + assert dgi.get_stdfloat() == pytest.approx(800.2) assert dgi.get_stdfloat() == pytest.approx(3.1415926) assert dgi.get_stdfloat() == pytest.approx(2.7182818) @@ -88,6 +94,12 @@ def test_datagram_bytes(): dgi.get_remaining_bytes() == b'abc\x00\xff123' +def test_datagram_get_message(): + dg = core.Datagram(b'abc\x00') + dg.append_data(b'\xff123') + assert dg.get_message() == b'abc\x00\xff123' + + def test_iterator(datagram_small): """This tests Datagram/DatagramIterator, and sort of serves as a self-check of the test fixtures too.""" From 5da8b63a668e8266ba9a81dd661bfc690e9cf65b Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Aug 2018 16:04:56 +0200 Subject: [PATCH 07/17] cppparser: fix formatting of typecast operator --- dtool/src/cppparser/cppFunctionType.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dtool/src/cppparser/cppFunctionType.cxx b/dtool/src/cppparser/cppFunctionType.cxx index 27699d711b..731b6b0cf5 100644 --- a/dtool/src/cppparser/cppFunctionType.cxx +++ b/dtool/src/cppparser/cppFunctionType.cxx @@ -292,6 +292,10 @@ output_instance(ostream &out, int indent_level, CPPScope *scope, out << str; + } else if (_flags & F_operator_typecast) { + out << "operator "; + _return_type->output_instance(out, indent_level, scope, complete, "", prename + str); + } else { if (prename.empty()) { _return_type->output_instance(out, indent_level, scope, complete, From 21f5e77467a72197d096f36759e12b0f117a5dd1 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Aug 2018 16:05:39 +0200 Subject: [PATCH 08/17] dtoolbase: prefer GCC AtomicAdjust implementation over i386 asm one --- dtool/src/dtoolbase/atomicAdjust.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/dtool/src/dtoolbase/atomicAdjust.h b/dtool/src/dtoolbase/atomicAdjust.h index 1180529ded..804224e5c3 100644 --- a/dtool/src/dtoolbase/atomicAdjust.h +++ b/dtool/src/dtoolbase/atomicAdjust.h @@ -30,6 +30,20 @@ struct AtomicAdjust { #include "atomicAdjustDummyImpl.h" typedef AtomicAdjustDummyImpl AtomicAdjust; +#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || (defined(__clang__) && (__clang_major__ >= 3)) +// GCC 4.7 and above has built-in __atomic functions for atomic operations. +// Clang 3.0 and above also supports them. + +#include "atomicAdjustGccImpl.h" +typedef AtomicAdjustGccImpl AtomicAdjust; + +#if (__GCC_ATOMIC_INT_LOCK_FREE + __GCC_ATOMIC_LONG_LOCK_FREE) > 0 +#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1 +#endif +#if __GCC_ATOMIC_POINTER_LOCK_FREE > 0 +#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1 +#endif + #elif (defined(__i386__) || defined(_M_IX86)) && !defined(__APPLE__) // For an i386 architecture, we'll always use the i386 implementation. It // should be safe for any OS, and it might be a bit faster than any OS- @@ -45,20 +59,6 @@ typedef AtomicAdjustI386Impl AtomicAdjust; #define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1 #define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1 -#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || (defined(__clang__) && (__clang_major__ >= 3)) -// GCC 4.7 and above has built-in __atomic functions for atomic operations. -// Clang 3.0 and above also supports them. - -#include "atomicAdjustGccImpl.h" -typedef AtomicAdjustGccImpl AtomicAdjust; - -#if (__GCC_ATOMIC_INT_LOCK_FREE + __GCC_ATOMIC_INT_LOCK_FREE) > 0 -#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1 -#endif -#if __GCC_ATOMIC_POINTER_LOCK_FREE > 0 -#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1 -#endif - #elif defined(THREAD_WIN32_IMPL) #include "atomicAdjustWin32Impl.h" From c4b657b5b23c72fcaeaf4d2d0205cdbcf1482c25 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Aug 2018 16:06:16 +0200 Subject: [PATCH 09/17] interrogate: support implicit typecast operators in some cases For example, this will let us pass a ConfigVariableFilename to anything that accepts a Filename, just like in C++. Does not work if the return value if the typecast operator requires management. --- .../interfaceMakerPythonNative.cxx | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 3134fcb2eb..e20aff91ef 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -1089,6 +1089,27 @@ write_class_details(ostream &out, Object *obj) { } } + // Are there any implicit cast operators that can cast this object to our + // desired pointer? + for (Function *func : obj->_methods) { + for (FunctionRemap *remap : func->_remaps) { + if (remap->_type == FunctionRemap::T_typecast_method && + is_remap_legal(remap) && + !remap->_return_type->return_value_needs_management() && + (remap->_cppfunc->_storage_class & CPPInstance::SC_explicit) == 0 && + TypeManager::is_pointer(remap->_return_type->get_new_type())) { + + CPPType *cast_type = remap->_return_type->get_orig_type(); + CPPType *obj_type = TypeManager::unwrap(TypeManager::resolve_type(remap->_return_type->get_new_type())); + string return_expr = "(" + cast_type->get_local_name(&parser) + ")*local_this"; + out << " // " << *remap->_cppfunc << "\n"; + out << " if (requested_type == Dtool_Ptr_" << make_safe_name(obj_type->get_local_name(&parser)) << ") {\n"; + out << " return (void *)(" << remap->_return_type->get_return_expr(return_expr) << ");\n"; + out << " }\n"; + } + } + } + out << " return nullptr;\n"; out << "}\n\n"; From 371c34d13bcd138a0daea42d3612e7dee1850240 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Aug 2018 16:40:35 +0200 Subject: [PATCH 10/17] linmath: allow constructing matrix from rows This also enables using mat[n] wherever an LVecBase4 is accepted, as well as Mat4(*mat). --- panda/src/linmath/lmatrix3_src.I | 42 ++++++++++++++++++++++++++ panda/src/linmath/lmatrix3_src.h | 12 +++++--- panda/src/linmath/lmatrix4_src.I | 51 ++++++++++++++++++++++++++++++++ panda/src/linmath/lmatrix4_src.h | 14 ++++++--- 4 files changed, 111 insertions(+), 8 deletions(-) diff --git a/panda/src/linmath/lmatrix3_src.I b/panda/src/linmath/lmatrix3_src.I index 8bfb3909ce..782c8599ee 100644 --- a/panda/src/linmath/lmatrix3_src.I +++ b/panda/src/linmath/lmatrix3_src.I @@ -44,6 +44,14 @@ size() { return 3; } +/** + * + */ +INLINE_LINMATH FLOATNAME(LMatrix3)::Row:: +operator const FLOATNAME(LVecBase3) &() const { + return *(const FLOATNAME(LVecBase3) *)_row; +} + /** * Defines a row-level constant accessor to the matrix. */ @@ -68,6 +76,14 @@ size() { return 3; } +/** + * + */ +INLINE_LINMATH FLOATNAME(LMatrix3)::CRow:: +operator const FLOATNAME(LVecBase3) &() const { + return *(const FLOATNAME(LVecBase3) *)_row; +} + /** * Returns an identity matrix. * @@ -132,6 +148,32 @@ FLOATNAME(LMatrix3)(FLOATTYPE e00, FLOATTYPE e01, FLOATTYPE e02, _m(2, 2) = e22; } +/** + * Constructs the matrix from three individual rows. + */ +INLINE_LINMATH FLOATNAME(LMatrix3):: +FLOATNAME(LMatrix3)(const FLOATNAME(LVecBase3) &row0, + const FLOATNAME(LVecBase3) &row1, + const FLOATNAME(LVecBase3) &row2) { + TAU_PROFILE("LMatrix3::LMatrix3(const LVecBase3 &, ...)", " ", TAU_USER); + +#ifdef HAVE_EIGEN + _m.row(0) = row0._v; + _m.row(1) = row1._v; + _m.row(2) = row2._v; +#else + _m(0, 0) = row0._v(0); + _m(0, 1) = row0._v(1); + _m(0, 2) = row0._v(2); + _m(1, 0) = row1._v(0); + _m(1, 1) = row1._v(1); + _m(1, 2) = row1._v(2); + _m(2, 0) = row2._v(0); + _m(2, 1) = row2._v(1); + _m(2, 2) = row2._v(2); +#endif // HAVE_EIGEN +} + /** * */ diff --git a/panda/src/linmath/lmatrix3_src.h b/panda/src/linmath/lmatrix3_src.h index 399508ed5f..2138f0fc39 100644 --- a/panda/src/linmath/lmatrix3_src.h +++ b/panda/src/linmath/lmatrix3_src.h @@ -38,6 +38,7 @@ PUBLISHED: INLINE_LINMATH FLOATTYPE operator [](int i) const; INLINE_LINMATH FLOATTYPE &operator [](int i); INLINE_LINMATH static int size(); + INLINE_LINMATH operator const FLOATNAME(LVecBase3) &() const; public: FLOATTYPE *_row; friend class FLOATNAME(LMatrix3); @@ -48,6 +49,7 @@ PUBLISHED: PUBLISHED: INLINE_LINMATH FLOATTYPE operator [](int i) const; INLINE_LINMATH static int size(); + INLINE_LINMATH operator const FLOATNAME(LVecBase3) &() const; public: const FLOATTYPE *_row; friend class FLOATNAME(LMatrix3); @@ -58,10 +60,12 @@ PUBLISHED: INLINE_LINMATH FLOATNAME(LMatrix3) &operator = ( const FLOATNAME(LMatrix3) &other); INLINE_LINMATH FLOATNAME(LMatrix3) &operator = (FLOATTYPE fill_value); - INLINE_LINMATH FLOATNAME(LMatrix3)( - FLOATTYPE e00, FLOATTYPE e01, FLOATTYPE e02, - FLOATTYPE e10, FLOATTYPE e11, FLOATTYPE e12, - FLOATTYPE e20, FLOATTYPE e21, FLOATTYPE e22); + INLINE_LINMATH FLOATNAME(LMatrix3)(FLOATTYPE, FLOATTYPE, FLOATTYPE, + FLOATTYPE, FLOATTYPE, FLOATTYPE, + FLOATTYPE, FLOATTYPE, FLOATTYPE); + INLINE_LINMATH FLOATNAME(LMatrix3)(const FLOATNAME(LVecBase3) &, + const FLOATNAME(LVecBase3) &, + const FLOATNAME(LVecBase3) &); ALLOC_DELETED_CHAIN(FLOATNAME(LMatrix3)); EXTENSION(INLINE_LINMATH PyObject *__reduce__(PyObject *self) const); diff --git a/panda/src/linmath/lmatrix4_src.I b/panda/src/linmath/lmatrix4_src.I index d5c16d5ce7..a887d393f1 100644 --- a/panda/src/linmath/lmatrix4_src.I +++ b/panda/src/linmath/lmatrix4_src.I @@ -44,6 +44,14 @@ size() { return 4; } +/** + * + */ +INLINE_LINMATH FLOATNAME(LMatrix4)::Row:: +operator const FLOATNAME(LVecBase4) &() const { + return *(const FLOATNAME(LVecBase4) *)_row; +} + /** * Defines a row-level constant accessor to the matrix. */ @@ -68,6 +76,14 @@ size() { return 4; } +/** + * + */ +INLINE_LINMATH FLOATNAME(LMatrix4)::CRow:: +operator const FLOATNAME(LVecBase4) &() const { + return *(const FLOATNAME(LVecBase4) *)_row; +} + /** * Returns an identity matrix. * @@ -178,6 +194,41 @@ FLOATNAME(LMatrix4)(FLOATTYPE e00, FLOATTYPE e01, FLOATTYPE e02, FLOATTYPE e03, _m(3, 3) = e33; } +/** + * Constructs the matrix from four individual rows. + */ +INLINE_LINMATH FLOATNAME(LMatrix4):: +FLOATNAME(LMatrix4)(const FLOATNAME(LVecBase4) &row0, + const FLOATNAME(LVecBase4) &row1, + const FLOATNAME(LVecBase4) &row2, + const FLOATNAME(LVecBase4) &row3) { + TAU_PROFILE("LMatrix4::LMatrix4(const LVecBase4 &, ...)", " ", TAU_USER); + +#ifdef HAVE_EIGEN + _m.row(0) = row0._v; + _m.row(1) = row1._v; + _m.row(2) = row2._v; + _m.row(3) = row3._v; +#else + _m(0, 0) = row0._v(0); + _m(0, 1) = row0._v(1); + _m(0, 2) = row0._v(2); + _m(0, 3) = row0._v(3); + _m(1, 0) = row1._v(0); + _m(1, 1) = row1._v(1); + _m(1, 2) = row1._v(2); + _m(1, 3) = row1._v(3); + _m(2, 0) = row2._v(0); + _m(2, 1) = row2._v(1); + _m(2, 2) = row2._v(2); + _m(2, 3) = row2._v(3); + _m(3, 0) = row3._v(0); + _m(3, 1) = row3._v(1); + _m(3, 2) = row3._v(2); + _m(3, 3) = row3._v(3); +#endif // HAVE_EIGEN +} + /** * */ diff --git a/panda/src/linmath/lmatrix4_src.h b/panda/src/linmath/lmatrix4_src.h index 4d749cddd5..a66a5ab45f 100644 --- a/panda/src/linmath/lmatrix4_src.h +++ b/panda/src/linmath/lmatrix4_src.h @@ -36,6 +36,7 @@ PUBLISHED: INLINE_LINMATH FLOATTYPE operator [](int i) const; INLINE_LINMATH FLOATTYPE &operator [](int i); INLINE_LINMATH static int size(); + INLINE_LINMATH operator const FLOATNAME(LVecBase4) &() const; public: FLOATTYPE *_row; friend class FLOATNAME(LMatrix4); @@ -46,6 +47,7 @@ PUBLISHED: PUBLISHED: INLINE_LINMATH FLOATTYPE operator [](int i) const; INLINE_LINMATH static int size(); + INLINE_LINMATH operator const FLOATNAME(LVecBase4) &() const; public: const FLOATTYPE *_row; friend class FLOATNAME(LMatrix4); @@ -60,10 +62,14 @@ PUBLISHED: const FLOATNAME(UnalignedLMatrix4) &other); INLINE_LINMATH FLOATNAME(LMatrix4) &operator = (FLOATTYPE fill_value); - INLINE_LINMATH FLOATNAME(LMatrix4)(FLOATTYPE e00, FLOATTYPE e01, FLOATTYPE e02, FLOATTYPE e03, - FLOATTYPE e10, FLOATTYPE e11, FLOATTYPE e12, FLOATTYPE e13, - FLOATTYPE e20, FLOATTYPE e21, FLOATTYPE e22, FLOATTYPE e23, - FLOATTYPE e30, FLOATTYPE e31, FLOATTYPE e32, FLOATTYPE e33); + INLINE_LINMATH FLOATNAME(LMatrix4)(FLOATTYPE, FLOATTYPE, FLOATTYPE, FLOATTYPE, + FLOATTYPE, FLOATTYPE, FLOATTYPE, FLOATTYPE, + FLOATTYPE, FLOATTYPE, FLOATTYPE, FLOATTYPE, + FLOATTYPE, FLOATTYPE, FLOATTYPE, FLOATTYPE); + INLINE_LINMATH FLOATNAME(LMatrix4)(const FLOATNAME(LVecBase4) &, + const FLOATNAME(LVecBase4) &, + const FLOATNAME(LVecBase4) &, + const FLOATNAME(LVecBase4) &); ALLOC_DELETED_CHAIN(FLOATNAME(LMatrix4)); EXTENSION(INLINE_LINMATH PyObject *__reduce__(PyObject *self) const); From b4abea17d59416ce77580adfcb73aeb58a1e009b Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Aug 2018 16:43:34 +0200 Subject: [PATCH 11/17] tests: add various matrix unit tests --- tests/linmath/test_lmatrix3.py | 62 ++++++++++++++++++++ tests/linmath/test_lmatrix4.py | 89 +++++++++++++++++++++++++++++ tests/linmath/test_matrix_invert.py | 20 ------- 3 files changed, 151 insertions(+), 20 deletions(-) create mode 100644 tests/linmath/test_lmatrix3.py create mode 100644 tests/linmath/test_lmatrix4.py delete mode 100644 tests/linmath/test_matrix_invert.py diff --git a/tests/linmath/test_lmatrix3.py b/tests/linmath/test_lmatrix3.py new file mode 100644 index 0000000000..b0ce53685a --- /dev/null +++ b/tests/linmath/test_lmatrix3.py @@ -0,0 +1,62 @@ +import pytest +from copy import copy +from panda3d import core + + +def test_mat3_aliases(): + assert core.LMatrix3 is core.Mat3 + assert core.LMatrix3f is core.Mat3F + assert core.LMatrix3d is core.Mat3D + + assert (core.LMatrix3f is core.Mat3) != (core.LMatrix3d is core.Mat3) + + +@pytest.mark.parametrize("type", (core.LMatrix3f, core.LMatrix3d)) +def test_mat3_constructor(type): + # Test that three ways of construction produce the same matrix. + mat1 = type((1, 2, 3), + (4, 5, 6), + (7, 8, 9)) + + mat2 = type(1, 2, 3, 4, 5, 6, 7, 8, 9) + + mat3 = type((1, 2, 3, 4, 5, 6, 7, 8, 9)) + + assert mat1 == mat2 + assert mat2 == mat3 + assert mat1 == mat3 + + +@pytest.mark.parametrize("type", (core.LMatrix3d, core.LMatrix3f)) +def test_mat3_copy_constuctor(type): + mat1 = type((1, 2, 3), + (4, 5, 6), + (7, 8, 9)) + + # Make a copy. Changing it should not change the original. + mat2 = type(mat1) + assert mat1 == mat2 + mat2[0][0] = 100 + assert mat1 != mat2 + + # Make a copy by unpacking. + mat2 = type(*mat1) + assert mat1 == mat2 + mat2[0][0] = 100 + assert mat1 != mat2 + + # Make a copy by calling copy.copy. + mat2 = copy(mat1) + assert mat1 == mat2 + mat2[0][0] = 100 + assert mat1 != mat2 + + +@pytest.mark.parametrize("type", (core.LMatrix3d, core.LMatrix3f)) +def test_mat3_invert_same_type(type): + mat = type((1, 0, 0, + 0, 1, 0, + 1, 2, 3)) + + inv = core.invert(mat) + assert mat.__class__ == inv.__class__ diff --git a/tests/linmath/test_lmatrix4.py b/tests/linmath/test_lmatrix4.py new file mode 100644 index 0000000000..23c1bcc5e9 --- /dev/null +++ b/tests/linmath/test_lmatrix4.py @@ -0,0 +1,89 @@ +import pytest +from copy import copy +from panda3d import core + + +def test_mat4_aliases(): + assert core.LMatrix4 is core.Mat4 + assert core.LMatrix4f is core.Mat4F + assert core.LMatrix4d is core.Mat4D + + assert (core.LMatrix4f is core.Mat4) != (core.LMatrix4d is core.Mat4) + + +@pytest.mark.parametrize("type", (core.LMatrix4d, core.LMatrix4f)) +def test_mat4_constructor(type): + # Test that three ways of construction produce the same matrix. + mat1 = type((1, 2, 3, 4), + (5, 6, 7, 8), + (9, 10, 11, 12), + (13, 14, 15, 16)) + + mat2 = type(1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16) + + mat3 = type((1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16)) + + assert mat1 == mat2 + assert mat2 == mat3 + assert mat1 == mat3 + + +@pytest.mark.parametrize("type", (core.LMatrix4d, core.LMatrix4f)) +def test_mat4_copy_constuctor(type): + mat1 = type((1, 2, 3, 4), + (5, 6, 7, 8), + (9, 10, 11, 12), + (13, 14, 15, 16)) + + # Make a copy. Changing it should not change the original. + mat2 = type(mat1) + assert mat1 == mat2 + mat2[0][0] = 100 + assert mat1 != mat2 + + # Make a copy by unpacking. + mat2 = type(*mat1) + assert mat1 == mat2 + mat2[0][0] = 100 + assert mat1 != mat2 + + # Make a copy by calling copy.copy. + mat2 = copy(mat1) + assert mat1 == mat2 + mat2[0][0] = 100 + assert mat1 != mat2 + + +@pytest.mark.parametrize("type", (core.LMatrix4d, core.LMatrix4f)) +def test_mat4_invert_same_type(type): + mat = type((1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 1, 2, 3, 1)) + + inv = core.invert(mat) + assert mat.__class__ == inv.__class__ + + +@pytest.mark.parametrize("type", (core.LMatrix4d, core.LMatrix4f)) +def test_mat4_invert_correct(type): + mat = type((1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 1, 2, 3, 1)) + inv = type() + assert inv.invert_from(mat) + + assert inv == type(( 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + -1, -2, -3, 1)) + + assert (mat * inv).is_identity() + assert (inv * mat).is_identity() diff --git a/tests/linmath/test_matrix_invert.py b/tests/linmath/test_matrix_invert.py deleted file mode 100644 index b2e6dd49bf..0000000000 --- a/tests/linmath/test_matrix_invert.py +++ /dev/null @@ -1,20 +0,0 @@ -import pytest -from panda3d import core - - -@pytest.mark.parametrize("type", (core.Mat4, core.Mat4D)) -def test_mat4_invert(type): - mat = type((1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 2, 3, 1)) - inv = type() - assert inv.invert_from(mat) - - assert inv == type(( 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - -1, -2, -3, 1)) - - assert (mat * inv).is_identity() - assert (inv * mat).is_identity() From 91ae68f04bef3241c2b254b5529590477602803e Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Aug 2018 16:49:54 +0200 Subject: [PATCH 12/17] tests: attempt to fix egg2pg test failure on macOS --- tests/egg2pg/test_egg_coordsys.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/egg2pg/test_egg_coordsys.py b/tests/egg2pg/test_egg_coordsys.py index b3c5583075..1c014ebf46 100644 --- a/tests/egg2pg/test_egg_coordsys.py +++ b/tests/egg2pg/test_egg_coordsys.py @@ -37,7 +37,8 @@ def test_egg2pg_transform_ident(egg_coordsys, coordsys): @pytest.mark.parametrize("coordsys", COORD_SYSTEMS) def test_egg2pg_transform_mat_unchanged(coordsys): # Ensures that the matrix remains unchanged if coordinate system is same. - mat = (5, 2, -3, 4, 5, 6, 7, 8, 9, 1, -3, 2, 5, 2, 5, 2) + matv = (5, 2, -3, 4, 5, 6, 7, 8, 9, 1, -3, 2, 5, 2, 5, 2) + mat = core.Mat4D(*matv) group = egg.EggGroup("group") group.add_matrix4(mat) assert not group.transform_is_identity() @@ -57,7 +58,7 @@ def test_egg2pg_transform_mat_unchanged(coordsys): assert root node, = root.children - assert node.transform.mat == mat + assert node.transform.mat == core.Mat4(*matv) @pytest.mark.parametrize("egg_coordsys", COORD_SYSTEMS) From 044d84c8fd42c1cec89fb4660280b0080eec01b8 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Aug 2018 16:53:03 +0200 Subject: [PATCH 13/17] mayaegg: fix various compilation warnings --- pandatool/src/mayaegg/mayaEggLoader.cxx | 18 +++++++++--------- pandatool/src/mayaegg/mayaToEggConverter.cxx | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pandatool/src/mayaegg/mayaEggLoader.cxx b/pandatool/src/mayaegg/mayaEggLoader.cxx index 4baf1dff86..68fcb8d0f7 100644 --- a/pandatool/src/mayaegg/mayaEggLoader.cxx +++ b/pandatool/src/mayaegg/mayaEggLoader.cxx @@ -837,12 +837,12 @@ int MayaEggGeom::GetVert(EggVertex *vert, EggGroup *context) void MayaEggGeom::AssignNames(void) { string name = _pool->get_name(); - int nsize = name.size(); - if ((nsize > 6) && (name.rfind(".verts")==(nsize-6))) { - name.resize(nsize-6); + size_t nsize = name.size(); + if (nsize > 6 && name.rfind(".verts") == (nsize - 6)) { + name.resize(nsize - 6); } - if ((nsize > 4) && (name.rfind(".cvs")==(nsize-4))) { - name.resize(nsize-4); + if (nsize > 4 && name.rfind(".cvs") == (nsize - 4)) { + name.resize(nsize - 4); } MFnDependencyNode dnshape(_shapeNode); @@ -913,7 +913,7 @@ void MayaEggGeom::AddEggFlag(MString fieldName) { typedef phash_map TVertTable; typedef phash_map CVertTable; -class MayaEggMesh : public MayaEggGeom +class MayaEggMesh final : public MayaEggGeom { public: MColorArray _faceColorArray; @@ -937,7 +937,7 @@ public: int GetCVert(const LColor &col); int AddFace(unsigned numVertices, MIntArray mvertIndices, MIntArray mtvertIndices, MayaEggTex *tex); - void ConnectTextures(void); + void ConnectTextures(void) override; }; int MayaEggMesh::GetTVert(const LTexCoordd &uv) @@ -2012,7 +2012,7 @@ void MayaEggLoader::PrintData(MayaEggMesh *mesh) void MayaEggLoader::ParseFrameInfo(string comment) { - int pos, ls, le; + size_t pos, ls, le; pos = comment.find("-fri"); if (pos != string::npos) { @@ -2143,7 +2143,7 @@ bool MayaEggLoader::ConvertEggFile(const char *name, bool merge, bool model, boo MObject MayaEggLoader::GetDependencyNode(string givenName) { MObject node = MObject::kNullObj; - int pos; + size_t pos; string name; pos = givenName.find(":"); diff --git a/pandatool/src/mayaegg/mayaToEggConverter.cxx b/pandatool/src/mayaegg/mayaToEggConverter.cxx index 747c8ac279..3f693dd004 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.cxx +++ b/pandatool/src/mayaegg/mayaToEggConverter.cxx @@ -2742,7 +2742,7 @@ set_shader_legacy(EggPrimitive &primitive, const MayaShader &shader, // shader on the list is the base one, which should always pick up // the alpha from the texture file. But the top textures may have // to strip the alpha - if (i!=shader._color.size()-1) { + if ((size_t)i != shader._color.size() - 1) { if (!i && is_interpolate) { // this is the grass path mode where alpha on this texture // determines whether to show layer1 or layer2. Since by now @@ -2846,7 +2846,7 @@ set_shader_legacy(EggPrimitive &primitive, const MayaShader &shader, _textures.create_unique_texture(tex, ~0); if (mesh) { - if (uvset_name.find("not found") == -1) { + if (uvset_name.find("not found") == string::npos) { primitive.add_texture(new_tex); color_def->_uvset_name.assign(uvset_name.c_str()); if (uvset_name != "map1") { From f663d215d56bb24bb316339c8bf621b674618d37 Mon Sep 17 00:00:00 2001 From: Mitchell Stokes Date: Sun, 19 Aug 2018 16:55:07 +0200 Subject: [PATCH 14/17] Remove some unused variables --- dtool/src/interrogate/interfaceMakerPythonNative.cxx | 5 +---- panda/src/egg/eggPrimitive.cxx | 2 +- panda/src/egg2pg/eggLoader.cxx | 1 - panda/src/pgraph/geomNode.cxx | 1 - panda/src/pgraph/geomTransformer.cxx | 1 - panda/src/text/dynamicTextFont.cxx | 1 - 6 files changed, 2 insertions(+), 9 deletions(-) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index e20aff91ef..5752fe126b 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -789,8 +789,6 @@ InterfaceMakerPythonNative:: */ void InterfaceMakerPythonNative:: write_prototypes(ostream &out_code, ostream *out_h) { - Functions::iterator fi; - if (out_h != nullptr) { *out_h << "#include \"py_panda.h\"\n\n"; } @@ -917,7 +915,6 @@ write_prototypes_class_external(ostream &out, Object *obj) { void InterfaceMakerPythonNative:: write_prototypes_class(ostream &out_code, ostream *out_h, Object *obj) { std::string ClassName = make_safe_name(obj->_itype.get_scoped_name()); - Functions::iterator fi; out_code << "/**\n"; out_code << " * Forward declarations for top-level class " << ClassName << "\n"; @@ -3322,7 +3319,7 @@ write_prototype_for(ostream &out, InterfaceMaker::Function *func) { */ void InterfaceMakerPythonNative:: write_prototype_for_name(ostream &out, InterfaceMaker::Function *func, const std::string &function_namename) { - Function::Remaps::const_iterator ri; +// Function::Remaps::const_iterator ri; // for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { // FunctionRemap *remap = (*ri); diff --git a/panda/src/egg/eggPrimitive.cxx b/panda/src/egg/eggPrimitive.cxx index f4985dfc90..158866855f 100644 --- a/panda/src/egg/eggPrimitive.cxx +++ b/panda/src/egg/eggPrimitive.cxx @@ -558,7 +558,7 @@ remove_doubled_verts(bool closed) { */ void EggPrimitive:: remove_nonunique_verts() { - Vertices::iterator vi, vj; + Vertices::iterator vi; Vertices new_vertices; int num_removed = 0; diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index e26a4120b9..9d885e0234 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -2661,7 +2661,6 @@ set_occluder_polygon(EggGroup *egg_group, OccluderNode *pnode) { } else { LMatrix4d mat = poly->get_vertex_to_node(); - EggPolygon::const_iterator vi; LPoint3d v0 = (*poly)[0]->get_pos3() * mat; LPoint3d v1 = (*poly)[1]->get_pos3() * mat; LPoint3d v2 = (*poly)[2]->get_pos3() * mat; diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index 328870364a..16e95442c2 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -115,7 +115,6 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, Thread *current_thread = Thread::get_current_thread(); OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { CDStageWriter cdata(_cycler, pipeline_stage, current_thread); - GeomList::iterator gi; PT(GeomList) geoms = cdata->modify_geoms(); // Iterate based on the number of geoms, not using STL iterators. This diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index cfc023b528..fe6b022d2d 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -742,7 +742,6 @@ make_compatible_state(GeomNode *node) { } GeomNode::CDWriter cdata(node->_cycler); - GeomNode::GeomList::iterator gi; PT(GeomNode::GeomList) geoms = cdata->modify_geoms(); // For each geom, calculate a canonicalized RenderState, and classify all diff --git a/panda/src/text/dynamicTextFont.cxx b/panda/src/text/dynamicTextFont.cxx index 4eb4afc96a..347841a92f 100644 --- a/panda/src/text/dynamicTextFont.cxx +++ b/panda/src/text/dynamicTextFont.cxx @@ -1072,7 +1072,6 @@ render_polygon_contours(TextGlyph *glyph, bool face, bool extrude) { // create more vertices--they don't share the same normals. for (ci = _contours.begin(); ci != _contours.end(); ++ci) { const Contour &contour = (*ci); - Points::const_iterator pi; for (size_t i = 0; i < contour._points.size(); ++i) { const ContourPoint &cp = contour._points[i]; From 35fff81b6ab9fffff61def1bae96f8142a780db1 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Aug 2018 18:52:48 +0200 Subject: [PATCH 15/17] makepanda: fix missing BUILDING_DIRECT_DCPARSER [skip ci] --- direct/src/dcparser/dcNumericRange.I | 10 +++++----- direct/src/dcparser/dcNumericRange.h | 10 +++++----- makepanda/makepanda.py | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/direct/src/dcparser/dcNumericRange.I b/direct/src/dcparser/dcNumericRange.I index bd41418205..92973d4410 100644 --- a/direct/src/dcparser/dcNumericRange.I +++ b/direct/src/dcparser/dcNumericRange.I @@ -52,7 +52,7 @@ operator = (const DCNumericRange ©) { * otherwise. */ template -bool DCNumericRange:: +INLINE bool DCNumericRange:: is_in_range(Number num) const { if (_ranges.empty()) { return true; @@ -106,7 +106,7 @@ get_one_value() const { * */ template -void DCNumericRange:: +INLINE void DCNumericRange:: generate_hash(HashGenerator &hashgen) const { if (!_ranges.empty()) { hashgen.add_int(_ranges.size()); @@ -124,7 +124,7 @@ generate_hash(HashGenerator &hashgen) const { * */ template -void DCNumericRange:: +INLINE void DCNumericRange:: output(std::ostream &out, Number divisor) const { if (!_ranges.empty()) { typename Ranges::const_iterator ri; @@ -144,7 +144,7 @@ output(std::ostream &out, Number divisor) const { * characters. */ template -void DCNumericRange:: +INLINE void DCNumericRange:: output_char(std::ostream &out, Number divisor) const { if (divisor != 1) { output(out, divisor); @@ -179,7 +179,7 @@ clear() { * minmax overlaps an existing minmax. */ template -bool DCNumericRange:: +INLINE bool DCNumericRange:: add_range(Number min, Number max) { // Check for an overlap. This is probably indicative of a typo and should // be reported. diff --git a/direct/src/dcparser/dcNumericRange.h b/direct/src/dcparser/dcNumericRange.h index f751323b01..888c54939e 100644 --- a/direct/src/dcparser/dcNumericRange.h +++ b/direct/src/dcparser/dcNumericRange.h @@ -32,20 +32,20 @@ public: INLINE DCNumericRange(const DCNumericRange ©); INLINE void operator = (const DCNumericRange ©); - bool is_in_range(Number num) const; + INLINE bool is_in_range(Number num) const; INLINE void validate(Number num, bool &range_error) const; INLINE bool has_one_value() const; INLINE Number get_one_value() const; - void generate_hash(HashGenerator &hashgen) const; + INLINE void generate_hash(HashGenerator &hashgen) const; - void output(std::ostream &out, Number divisor = 1) const; - void output_char(std::ostream &out, Number divisor = 1) const; + INLINE void output(std::ostream &out, Number divisor = 1) const; + INLINE void output_char(std::ostream &out, Number divisor = 1) const; public: INLINE void clear(); - bool add_range(Number min, Number max); + INLINE bool add_range(Number min, Number max); INLINE bool is_empty() const; INLINE int get_num_ranges() const; diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 6181ccf87e..00dd2c3cd3 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -5219,7 +5219,7 @@ if (PkgSkip("DIRECT")==0): # if (PkgSkip("DIRECT")==0): - OPTS=['DIR:direct/src/dcparser', 'WITHINPANDA', 'BISONPREFIX_dcyy', 'PYTHON'] + OPTS=['DIR:direct/src/dcparser', 'BUILDING:DIRECT_DCPARSER', 'WITHINPANDA', 'BISONPREFIX_dcyy', 'PYTHON'] CreateFile(GetOutputDir()+"/include/dcParser.h") TargetAdd('p3dcparser_dcParser.obj', opts=OPTS, input='dcParser.yxx') TargetAdd('dcParser.h', input='p3dcparser_dcParser.obj', opts=['DEPENDENCYONLY']) From 4f9a2aca85c530e9026f675fa44fa524f82a5023 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 20 Aug 2018 16:25:55 +0200 Subject: [PATCH 16/17] tests: fix issues with temp files without correct case on Windows --- tests/gobj/test_texture_pool.py | 18 ++++++++++------ tests/putil/test_datagram.py | 37 ++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/tests/gobj/test_texture_pool.py b/tests/gobj/test_texture_pool.py index b07e8a0cb9..c8ac5ae44a 100644 --- a/tests/gobj/test_texture_pool.py +++ b/tests/gobj/test_texture_pool.py @@ -22,8 +22,10 @@ def image_rgb_path(): "Generates an RGB image." file = tempfile.NamedTemporaryFile(suffix='-rgb.png') - write_image(file.name, 3) - yield file.name + path = core.Filename.from_os_specific(file.name) + path.make_true_case() + write_image(path, 3) + yield path file.close() @@ -32,8 +34,10 @@ def image_rgba_path(): "Generates an RGBA image." file = tempfile.NamedTemporaryFile(suffix='-rgba.png') - write_image(file.name, 4) - yield file.name + path = core.Filename.from_os_specific(file.name) + path.make_true_case() + write_image(path, 4) + yield path file.close() @@ -42,8 +46,10 @@ def image_gray_path(): "Generates a grayscale image." file = tempfile.NamedTemporaryFile(suffix='-gray.png') - write_image(file.name, 1) - yield file.name + path = core.Filename.from_os_specific(file.name) + path.make_true_case() + write_image(path, 1) + yield path file.close() diff --git a/tests/putil/test_datagram.py b/tests/putil/test_datagram.py index 7919a1360f..751ea0dc03 100644 --- a/tests/putil/test_datagram.py +++ b/tests/putil/test_datagram.py @@ -1,6 +1,7 @@ import pytest from panda3d import core import sys +import tempfile # Fixtures for generating interesting datagrams (and verification functions) on # the fly... @@ -147,30 +148,39 @@ def do_file_test(dg, verify, filename): dgi = core.DatagramIterator(dg2) verify(dgi) -def test_file_small(datagram_small, tmpdir): +@pytest.fixture +def tmpfile(): + file = tempfile.NamedTemporaryFile(suffix='.bin') + yield file + file.close() + +def test_file_small(datagram_small, tmpfile): """This tests DatagramOutputFile/DatagramInputFile on small datagrams.""" dg, verify = datagram_small - p = tmpdir.join('datagram.bin') - filename = core.Filename.from_os_specific(str(p)) + file = tempfile.NamedTemporaryFile(suffix='.bin') + filename = core.Filename.from_os_specific(file.name) + filename.make_true_case() do_file_test(dg, verify, filename) -def test_file_large(datagram_large, tmpdir): +def test_file_large(datagram_large, tmpfile): """This tests DatagramOutputFile/DatagramInputFile on very large datagrams.""" dg, verify = datagram_large - p = tmpdir.join('datagram.bin') - filename = core.Filename.from_os_specific(str(p)) + file = tempfile.NamedTemporaryFile(suffix='.bin') + filename = core.Filename.from_os_specific(file.name) + filename.make_true_case() do_file_test(dg, verify, filename) -def test_file_corrupt(datagram_small, tmpdir): +def test_file_corrupt(datagram_small, tmpfile): """This tests DatagramInputFile's handling of a corrupt size header.""" dg, verify = datagram_small - p = tmpdir.join('datagram.bin') - filename = core.Filename.from_os_specific(str(p)) + file = tempfile.NamedTemporaryFile(suffix='.bin') + filename = core.Filename.from_os_specific(file.name) + filename.make_true_case() dof = core.DatagramOutputFile() dof.open(filename) @@ -178,9 +188,9 @@ def test_file_corrupt(datagram_small, tmpdir): dof.close() # Corrupt the size header to 1GB - with p.open(mode='r+b') as f: - f.seek(0) - f.write(b'\xFF\xFF\xFF\x4F') + file.seek(0) + file.write(b'\xFF\xFF\xFF\x4F') + file.flush() dg2 = core.Datagram() dif = core.DatagramInputFile() @@ -190,8 +200,7 @@ def test_file_corrupt(datagram_small, tmpdir): # Truncate the file for size in [12, 8, 4, 3, 2, 1, 0]: - with p.open(mode='r+b') as f: - f.truncate(size) + file.truncate(size) dg2 = core.Datagram() dif = core.DatagramInputFile() From 5147674980d3d81314bbe3e5ddbad4c01e9ffc21 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 20 Aug 2018 16:57:34 +0200 Subject: [PATCH 17/17] Add script to run test suite on a wheel in a virtualenv [skip ci] --- makepanda/test_wheel.py | 61 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100755 makepanda/test_wheel.py diff --git a/makepanda/test_wheel.py b/makepanda/test_wheel.py new file mode 100755 index 0000000000..00555a5e60 --- /dev/null +++ b/makepanda/test_wheel.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +""" +Tests a .whl file by installing it and pytest into a virtual environment and +running the test suite. + +Requires pip to be installed, as well as 'virtualenv' on Python 2. +""" + +import os +import sys +import shutil +import subprocess +import tempfile +from optparse import OptionParser + + +def test_wheel(wheel, verbose=False): + envdir = tempfile.mkdtemp(prefix="venv-") + print("Setting up virtual environment in {0}".format(envdir)) + + if sys.version_info >= (3, 0): + subprocess.call([sys.executable, "-m", "venv", "--clear", envdir]) + else: + subprocess.call([sys.executable, "-m", "virtualenv", "--clear", envdir]) + + # Install pytest into the environment, as well as our wheel. + if sys.platform == "win32": + pip = os.path.join(envdir, "Scripts", "pip.exe") + else: + pip = os.path.join(envdir, "bin", "pip") + if subprocess.call([pip, "install", "pytest", wheel]) != 0: + shutil.rmtree(envdir) + sys.exit(1) + + # Run the test suite. + if sys.platform == "win32": + python = os.path.join(envdir, "Scripts", "python.exe") + else: + python = os.path.join(envdir, "bin", "python") + test_cmd = [python, "-m", "pytest", "tests"] + if verbose: + test_cmd.append("--verbose") + + exit_code = subprocess.call(test_cmd) + shutil.rmtree(envdir) + + if exit_code != 0: + sys.exit(exit_code) + + +if __name__ == "__main__": + parser = OptionParser(usage="%prog [options] file...") + parser.add_option('', '--verbose', dest = 'verbose', help = 'Enable verbose output', action = 'store_true', default = False) + (options, args) = parser.parse_args() + + if not args: + parser.print_usage() + sys.exit(1) + + for arg in args: + test_wheel(arg, verbose=options.verbose)