- Initializes the environment so that getenv et al works properly
- No longer calls JS functions at static init time; the JS preamble will
pass the right env vars to ExecutionEnvironment
- Sets the binary name to the path of the .js file
This should be replaced with Dtool_GetPyTypeObject, hiding the implementation details a bit so that we can more easily change the underlying structure if we need later
Also adds Py_NewRef to py_compat.h, backporting from master
The main reason is that the current development version of Eigen requires C++14 to be enabled, so otherwise we can't compile with the latest Eigen.
If really needed, we can keep support for MSVC 2015 (please make your voice heard) but that would lock us out of a few features of C++14.
Will use as few digits as is necessary to ensure that round-tripping the same number with pstrtod will result in the same vector. This prevents eg. 3.3 formatting as 3.29999995 while still ensuring that two floats that are not equal (other than nan) are guaranteed to have a different string representation.
Uses a hacky pftoa function that can be abandoned as soon as we adopt C++17, which has to_chars that does what we need
Fixes#1671
After 38692dd525, GC pauses occuring before
the __init__ function of the C++ backed object is called in a inheritance chain will
cause an exception during garbage collection and cause the python runtime to exit.
This can be observed by say, forcing a GC-pause in MetaInterval.__init__ before it calls CMetaInterval::__init__.
This change enables persistent Python wrapper objects for Python subclasses of typed, reference counted C++ objects. That means that these objects will store a reference to `self` on the C++ object, and interrogate will always return that instead of making a new Python wrapper every time it is returned from C++.
Practically, this means that you could subclass eg. PandaNode, Event, Fog, what have you, and store these in the scene graph - the Python data in the subclass will be retained and Panda will return your subclass when you ask for the object back rather than creating a new wrapper object without your original data.
To do this, Interrogate generates a proxy class inheriting from the C++ type with additional room to store a `self` pointer and a TypeHandle (which is returned by an overridden `get_type()`). This TypeHandle is automatically created by registering the Python subclass with the typing system. The proxy class is only used when the constructor detects that it's constructing for a subtype, so that regular uses of the C++ type are not affected by this mechanism.
(The registration with the typing system could use some improvement. There's no regard for namespacing right now, in particular. Furthermore, we could move the registration to an `__init_subclass__()` method, with parameters to specify an existing TypeHandle or to customize the type name.)
This creates a reference cycle, which must be cleared somehow. One way this happens is by overriding `unref()` in the proxy, which checks that if the Python and C++ reference counts are both 1, this must be the circular reference, and then it breaks the cycle. Note that this will _only_ work if all other Python references have been cleared before the last C++ reference goes away. For the other case, we need to rely on Python's garbage collector, so these classes also implement tp_traverse and tp_clear.
This commit also therefore re-enables Python garbage collector support (ie. defining `__traverse__()`), which was previously disabled due to the problems caused by multiple Python wrappers referring to the same C++ object. To avoid these problems, Panda will only cooperate with Python's GC if the C++ reference count is 1, in which case we can trivially prove that the last reference must be from the Python wrapper. Note that this explains why we need persistent wrappers for traversal to work--if there are multiple Python wrappers pointing to the C++ object, and they are all participating in a reference cycle, the reference count cannot be 1, and cycle detection does not work. By default, the GC is only enabled for Python subclasses, but a class may define `__traverse__()` in order to opt-in, keeping the previous limitation in mind.
There is a second mechanism introduced by this commit: classes may define a public `__self__` member of type `PyObject *` if they want to use persistent objects even if they aren't being subclassed. This allows these classes to participate in Python's GC and avoid the situation above.
The cycle detection is implemented for PandaNode's Python tags, but this is very incomplete, since the traversal doesn't recurse into children and it won't work if there is more than one wrapper object that is part of a cycle, since PandaNode by default doesn't use persistent wrappers. This problem may need more attention later.
Fixes#1410