mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-28 15:53:55 -04:00
Merge branch 'release/1.10.x'
This commit is contained in:
commit
92185bcb28
@ -49,9 +49,9 @@ class MotionTrailFrame:
|
|||||||
class MotionTrail(NodePath, DirectObject):
|
class MotionTrail(NodePath, DirectObject):
|
||||||
"""Generates smooth geometry-based motion trails behind a moving object.
|
"""Generates smooth geometry-based motion trails behind a moving object.
|
||||||
|
|
||||||
To use this class, first define the shape of the cross-section of the trail
|
To use this class, first define the shape of the cross-section polygon that
|
||||||
by repeatedly calling `add_vertex()` and `set_vertex_color()`.
|
is to be extruded along the motion trail by calling `add_vertex()` and
|
||||||
When this is done, `update_vertices()` must be called.
|
`set_vertex_color()`. When this is done, call `update_vertices()`.
|
||||||
|
|
||||||
To generate the motion trail, either call `register_motion_trail()`
|
To generate the motion trail, either call `register_motion_trail()`
|
||||||
to have Panda update it automatically, or periodically call the method
|
to have Panda update it automatically, or periodically call the method
|
||||||
@ -82,6 +82,10 @@ class MotionTrail(NodePath, DirectObject):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setGlobalEnable(cls, enable):
|
def setGlobalEnable(cls, enable):
|
||||||
|
"""Set this to False to have the task stop updating all motion trails.
|
||||||
|
This does not prevent updating them manually using the
|
||||||
|
`update_motion_trail()` method.
|
||||||
|
"""
|
||||||
cls.global_enable = enable
|
cls.global_enable = enable
|
||||||
|
|
||||||
def __init__(self, name, parent_node_path):
|
def __init__(self, name, parent_node_path):
|
||||||
@ -119,14 +123,14 @@ class MotionTrail(NodePath, DirectObject):
|
|||||||
self.continuous_motion_trail = True
|
self.continuous_motion_trail = True
|
||||||
self.color_scale = 1.0
|
self.color_scale = 1.0
|
||||||
|
|
||||||
## How long the time window is for which the trail is computed. Can be
|
#: How long the time window is for which the trail is computed. Can be
|
||||||
## increased to obtain a longer trail, decreased for a shorter trail.
|
#: increased to obtain a longer trail, decreased for a shorter trail.
|
||||||
self.time_window = 1.0
|
self.time_window = 1.0
|
||||||
|
|
||||||
## How often the trail updates, in seconds. The default is 0.0, which
|
#: How often the trail updates, in seconds. The default is 0.0, which
|
||||||
## has the trail updated every frame for the smoothest result. Higher
|
#: has the trail updated every frame for the smoothest result. Higher
|
||||||
## values will generate a choppier trail. The `use_nurbs` option can
|
#: values will generate a choppier trail. The `use_nurbs` option can
|
||||||
## compensate partially for this choppiness, however.
|
#: compensate partially for this choppiness, however.
|
||||||
self.sampling_time = 0.0
|
self.sampling_time = 0.0
|
||||||
|
|
||||||
self.square_t = True
|
self.square_t = True
|
||||||
@ -137,9 +141,9 @@ class MotionTrail(NodePath, DirectObject):
|
|||||||
# node path states
|
# node path states
|
||||||
self.reparentTo(parent_node_path)
|
self.reparentTo(parent_node_path)
|
||||||
|
|
||||||
## A `.GeomNode` object containing the generated geometry. By default
|
#: A `.GeomNode` object containing the generated geometry. By default
|
||||||
## parented to the MotionTrail itself, but can be reparented elsewhere
|
#: parented to the MotionTrail itself, but can be reparented elsewhere
|
||||||
## if necessary.
|
#: if necessary.
|
||||||
self.geom_node = GeomNode("motion_trail")
|
self.geom_node = GeomNode("motion_trail")
|
||||||
self.geom_node.setBoundsType(BoundingVolume.BT_box)
|
self.geom_node.setBoundsType(BoundingVolume.BT_box)
|
||||||
self.geom_node_path = self.attachNewNode(self.geom_node)
|
self.geom_node_path = self.attachNewNode(self.geom_node)
|
||||||
@ -170,9 +174,11 @@ class MotionTrail(NodePath, DirectObject):
|
|||||||
|
|
||||||
self.relative_to_render = False
|
self.relative_to_render = False
|
||||||
|
|
||||||
## Set this to True to use a NURBS curve to generate a smooth trail,
|
#: Set this to True to use a NURBS curve to generate a smooth trail,
|
||||||
## even if the underlying animation or movement is janky.
|
#: even if the underlying animation or movement is janky.
|
||||||
self.use_nurbs = False
|
self.use_nurbs = False
|
||||||
|
|
||||||
|
#: This can be changed to fine-tune the resolution of the NURBS curve.
|
||||||
self.resolution_distance = 0.5
|
self.resolution_distance = 0.5
|
||||||
|
|
||||||
self.cmotion_trail = CMotionTrail()
|
self.cmotion_trail = CMotionTrail()
|
||||||
@ -249,7 +255,7 @@ class MotionTrail(NodePath, DirectObject):
|
|||||||
|
|
||||||
def add_vertex(self, vertex_id, vertex_function=None, context=None, *,
|
def add_vertex(self, vertex_id, vertex_function=None, context=None, *,
|
||||||
start_color=(1.0, 1.0, 1.0, 1.0), end_color=(0.0, 0.0, 0.0, 1.0)):
|
start_color=(1.0, 1.0, 1.0, 1.0), end_color=(0.0, 0.0, 0.0, 1.0)):
|
||||||
"""This must be called repeatedly to define the polygon that forms the
|
"""This must be called initially to define the polygon that forms the
|
||||||
cross-section of the generated motion trail geometry. The first
|
cross-section of the generated motion trail geometry. The first
|
||||||
argument is a user-defined vertex identifier, the second is a function
|
argument is a user-defined vertex identifier, the second is a function
|
||||||
that will be called with three parameters that should return the
|
that will be called with three parameters that should return the
|
||||||
@ -390,21 +396,21 @@ class MotionTrail(NodePath, DirectObject):
|
|||||||
|
|
||||||
def add_geometry_quad(self, v0, v1, v2, v3, c0, c1, c2, c3, t0, t1, t2, t3):
|
def add_geometry_quad(self, v0, v1, v2, v3, c0, c1, c2, c3, t0, t1, t2, t3):
|
||||||
|
|
||||||
self.vertex_writer.addData3f(v0 [0], v0 [1], v0 [2])
|
self.vertex_writer.addData3(v0[0], v0[1], v0[2])
|
||||||
self.vertex_writer.addData3f(v1 [0], v1 [1], v1 [2])
|
self.vertex_writer.addData3(v1[0], v1[1], v1[2])
|
||||||
self.vertex_writer.addData3f(v2 [0], v2 [1], v2 [2])
|
self.vertex_writer.addData3(v2[0], v2[1], v2[2])
|
||||||
self.vertex_writer.addData3f(v3 [0], v3 [1], v3 [2])
|
self.vertex_writer.addData3(v3[0], v3[1], v3[2])
|
||||||
|
|
||||||
self.color_writer.addData4f(c0)
|
self.color_writer.addData4(c0)
|
||||||
self.color_writer.addData4f(c1)
|
self.color_writer.addData4(c1)
|
||||||
self.color_writer.addData4f(c2)
|
self.color_writer.addData4(c2)
|
||||||
self.color_writer.addData4f(c3)
|
self.color_writer.addData4(c3)
|
||||||
|
|
||||||
if self.texture is not None:
|
if self.texture is not None:
|
||||||
self.texture_writer.addData2f(t0)
|
self.texture_writer.addData2(t0)
|
||||||
self.texture_writer.addData2f(t1)
|
self.texture_writer.addData2(t1)
|
||||||
self.texture_writer.addData2f(t2)
|
self.texture_writer.addData2(t2)
|
||||||
self.texture_writer.addData2f(t3)
|
self.texture_writer.addData2(t3)
|
||||||
|
|
||||||
vertex_index = self.vertex_index
|
vertex_index = self.vertex_index
|
||||||
|
|
||||||
|
@ -1151,7 +1151,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||||||
Creates the render scene graph, the primary scene graph for
|
Creates the render scene graph, the primary scene graph for
|
||||||
rendering 3-d geometry.
|
rendering 3-d geometry.
|
||||||
"""
|
"""
|
||||||
## This is the root of the 3-D scene graph.
|
#: This is the root of the 3-D scene graph.
|
||||||
self.render = NodePath('render')
|
self.render = NodePath('render')
|
||||||
self.render.setAttrib(RescaleNormalAttrib.makeDefault())
|
self.render.setAttrib(RescaleNormalAttrib.makeDefault())
|
||||||
|
|
||||||
@ -1170,7 +1170,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||||||
# for the benefit of creating DirectGui elements before ShowBase.
|
# for the benefit of creating DirectGui elements before ShowBase.
|
||||||
from . import ShowBaseGlobal
|
from . import ShowBaseGlobal
|
||||||
|
|
||||||
## This is the root of the 2-D scene graph.
|
#: This is the root of the 2-D scene graph.
|
||||||
self.render2d = ShowBaseGlobal.render2d
|
self.render2d = ShowBaseGlobal.render2d
|
||||||
|
|
||||||
# Set up some overrides to turn off certain properties which
|
# Set up some overrides to turn off certain properties which
|
||||||
@ -1191,12 +1191,12 @@ class ShowBase(DirectObject.DirectObject):
|
|||||||
self.render2d.setMaterialOff(1)
|
self.render2d.setMaterialOff(1)
|
||||||
self.render2d.setTwoSided(1)
|
self.render2d.setTwoSided(1)
|
||||||
|
|
||||||
## The normal 2-d DisplayRegion has an aspect ratio that
|
#: The normal 2-d DisplayRegion has an aspect ratio that
|
||||||
## matches the window, but its coordinate system is square.
|
#: matches the window, but its coordinate system is square.
|
||||||
## This means anything we parent to render2d gets stretched.
|
#: This means anything we parent to render2d gets stretched.
|
||||||
## For things where that makes a difference, we set up
|
#: For things where that makes a difference, we set up
|
||||||
## aspect2d, which scales things back to the right aspect
|
#: aspect2d, which scales things back to the right aspect
|
||||||
## ratio along the X axis (Z is still from -1 to 1)
|
#: ratio along the X axis (Z is still from -1 to 1)
|
||||||
self.aspect2d = ShowBaseGlobal.aspect2d
|
self.aspect2d = ShowBaseGlobal.aspect2d
|
||||||
|
|
||||||
aspectRatio = self.getAspectRatio()
|
aspectRatio = self.getAspectRatio()
|
||||||
@ -1204,13 +1204,13 @@ class ShowBase(DirectObject.DirectObject):
|
|||||||
|
|
||||||
self.a2dBackground = self.aspect2d.attachNewNode("a2dBackground")
|
self.a2dBackground = self.aspect2d.attachNewNode("a2dBackground")
|
||||||
|
|
||||||
## The Z position of the top border of the aspect2d screen.
|
#: The Z position of the top border of the aspect2d screen.
|
||||||
self.a2dTop = 1.0
|
self.a2dTop = 1.0
|
||||||
## The Z position of the bottom border of the aspect2d screen.
|
#: The Z position of the bottom border of the aspect2d screen.
|
||||||
self.a2dBottom = -1.0
|
self.a2dBottom = -1.0
|
||||||
## The X position of the left border of the aspect2d screen.
|
#: The X position of the left border of the aspect2d screen.
|
||||||
self.a2dLeft = -aspectRatio
|
self.a2dLeft = -aspectRatio
|
||||||
## The X position of the right border of the aspect2d screen.
|
#: The X position of the right border of the aspect2d screen.
|
||||||
self.a2dRight = aspectRatio
|
self.a2dRight = aspectRatio
|
||||||
|
|
||||||
self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
|
self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
|
||||||
@ -1250,9 +1250,9 @@ class ShowBase(DirectObject.DirectObject):
|
|||||||
self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
|
self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
|
||||||
self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)
|
self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)
|
||||||
|
|
||||||
## This special root, pixel2d, uses units in pixels that are relative
|
#: This special root, pixel2d, uses units in pixels that are relative
|
||||||
## to the window. The upperleft corner of the window is (0, 0),
|
#: to the window. The upperleft corner of the window is (0, 0),
|
||||||
## the lowerleft corner is (xsize, -ysize), in this coordinate system.
|
#: the lowerleft corner is (xsize, -ysize), in this coordinate system.
|
||||||
self.pixel2d = self.render2d.attachNewNode(PGTop("pixel2d"))
|
self.pixel2d = self.render2d.attachNewNode(PGTop("pixel2d"))
|
||||||
self.pixel2d.setPos(-1, 0, 1)
|
self.pixel2d.setPos(-1, 0, 1)
|
||||||
xsize, ysize = self.getSize()
|
xsize, ysize = self.getSize()
|
||||||
@ -1282,25 +1282,25 @@ class ShowBase(DirectObject.DirectObject):
|
|||||||
self.render2dp.setMaterialOff(1)
|
self.render2dp.setMaterialOff(1)
|
||||||
self.render2dp.setTwoSided(1)
|
self.render2dp.setTwoSided(1)
|
||||||
|
|
||||||
## The normal 2-d DisplayRegion has an aspect ratio that
|
#: The normal 2-d DisplayRegion has an aspect ratio that
|
||||||
## matches the window, but its coordinate system is square.
|
#: matches the window, but its coordinate system is square.
|
||||||
## This means anything we parent to render2dp gets stretched.
|
#: This means anything we parent to render2dp gets stretched.
|
||||||
## For things where that makes a difference, we set up
|
#: For things where that makes a difference, we set up
|
||||||
## aspect2dp, which scales things back to the right aspect
|
#: aspect2dp, which scales things back to the right aspect
|
||||||
## ratio along the X axis (Z is still from -1 to 1)
|
#: ratio along the X axis (Z is still from -1 to 1)
|
||||||
self.aspect2dp = self.render2dp.attachNewNode(PGTop("aspect2dp"))
|
self.aspect2dp = self.render2dp.attachNewNode(PGTop("aspect2dp"))
|
||||||
self.aspect2dp.node().setStartSort(16384)
|
self.aspect2dp.node().setStartSort(16384)
|
||||||
|
|
||||||
aspectRatio = self.getAspectRatio()
|
aspectRatio = self.getAspectRatio()
|
||||||
self.aspect2dp.setScale(1.0 / aspectRatio, 1.0, 1.0)
|
self.aspect2dp.setScale(1.0 / aspectRatio, 1.0, 1.0)
|
||||||
|
|
||||||
## The Z position of the top border of the aspect2dp screen.
|
#: The Z position of the top border of the aspect2dp screen.
|
||||||
self.a2dpTop = 1.0
|
self.a2dpTop = 1.0
|
||||||
## The Z position of the bottom border of the aspect2dp screen.
|
#: The Z position of the bottom border of the aspect2dp screen.
|
||||||
self.a2dpBottom = -1.0
|
self.a2dpBottom = -1.0
|
||||||
## The X position of the left border of the aspect2dp screen.
|
#: The X position of the left border of the aspect2dp screen.
|
||||||
self.a2dpLeft = -aspectRatio
|
self.a2dpLeft = -aspectRatio
|
||||||
## The X position of the right border of the aspect2dp screen.
|
#: The X position of the right border of the aspect2dp screen.
|
||||||
self.a2dpRight = aspectRatio
|
self.a2dpRight = aspectRatio
|
||||||
|
|
||||||
self.a2dpTopCenter = self.aspect2dp.attachNewNode("a2dpTopCenter")
|
self.a2dpTopCenter = self.aspect2dp.attachNewNode("a2dpTopCenter")
|
||||||
@ -1324,9 +1324,9 @@ class ShowBase(DirectObject.DirectObject):
|
|||||||
self.a2dpBottomLeft.setPos(self.a2dpLeft, 0, self.a2dpBottom)
|
self.a2dpBottomLeft.setPos(self.a2dpLeft, 0, self.a2dpBottom)
|
||||||
self.a2dpBottomRight.setPos(self.a2dpRight, 0, self.a2dpBottom)
|
self.a2dpBottomRight.setPos(self.a2dpRight, 0, self.a2dpBottom)
|
||||||
|
|
||||||
## This special root, pixel2d, uses units in pixels that are relative
|
#: This special root, pixel2dp, uses units in pixels that are relative
|
||||||
## to the window. The upperleft corner of the window is (0, 0),
|
#: to the window. The upperleft corner of the window is (0, 0),
|
||||||
## the lowerleft corner is (xsize, -ysize), in this coordinate system.
|
#: the lowerleft corner is (xsize, -ysize), in this coordinate system.
|
||||||
self.pixel2dp = self.render2dp.attachNewNode(PGTop("pixel2dp"))
|
self.pixel2dp = self.render2dp.attachNewNode(PGTop("pixel2dp"))
|
||||||
self.pixel2dp.node().setStartSort(16384)
|
self.pixel2dp.node().setStartSort(16384)
|
||||||
self.pixel2dp.setPos(-1, 0, 1)
|
self.pixel2dp.setPos(-1, 0, 1)
|
||||||
@ -1647,11 +1647,11 @@ class ShowBase(DirectObject.DirectObject):
|
|||||||
|
|
||||||
mw = self.buttonThrowers[0].getParent()
|
mw = self.buttonThrowers[0].getParent()
|
||||||
|
|
||||||
## A special ButtonThrower to generate keyboard events and
|
#: A special ButtonThrower to generate keyboard events and
|
||||||
## include the time from the OS. This is separate only to
|
#: include the time from the OS. This is separate only to
|
||||||
## support legacy code that did not expect a time parameter; it
|
#: support legacy code that did not expect a time parameter; it
|
||||||
## will eventually be folded into the normal ButtonThrower,
|
#: will eventually be folded into the normal ButtonThrower,
|
||||||
## above.
|
#: above.
|
||||||
self.timeButtonThrower = mw.attachNewNode(ButtonThrower('timeButtons'))
|
self.timeButtonThrower = mw.attachNewNode(ButtonThrower('timeButtons'))
|
||||||
self.timeButtonThrower.node().setPrefix('time-')
|
self.timeButtonThrower.node().setPrefix('time-')
|
||||||
self.timeButtonThrower.node().setTimeFlag(1)
|
self.timeButtonThrower.node().setTimeFlag(1)
|
||||||
|
@ -71,6 +71,8 @@ Miscellaneous
|
|||||||
* Fix texture transforms sometimes not being flattened (#1392)
|
* Fix texture transforms sometimes not being flattened (#1392)
|
||||||
* Fix support for `#pragma include <file.glsl>` in GLSL shaders
|
* Fix support for `#pragma include <file.glsl>` in GLSL shaders
|
||||||
* Fix `ShaderBuffer.prepare()` not doing anything
|
* Fix `ShaderBuffer.prepare()` not doing anything
|
||||||
|
* Implement deepcopy for PointerToArray
|
||||||
|
* Fix Texture deepcopy keeping a reference to the original RAM image
|
||||||
* Fix bf-cbc encryption no longer working when building with OpenSSL 3.0
|
* Fix bf-cbc encryption no longer working when building with OpenSSL 3.0
|
||||||
* PandaNode bounds_type property was erroneously marked read-only
|
* PandaNode bounds_type property was erroneously marked read-only
|
||||||
* Fix warnings when copying OdeTriMeshGeom objects
|
* Fix warnings when copying OdeTriMeshGeom objects
|
||||||
@ -81,8 +83,10 @@ Miscellaneous
|
|||||||
* Add various useful functions to interrogatedb module
|
* Add various useful functions to interrogatedb module
|
||||||
* Fix Python 3 issues unpacking uint types in Python 3 (#1380)
|
* Fix Python 3 issues unpacking uint types in Python 3 (#1380)
|
||||||
* Fix interrogate syntax error with C++11-style attributes in declarators
|
* Fix interrogate syntax error with C++11-style attributes in declarators
|
||||||
|
* Fix double-precision color values not being clamped by GeomVertexWriter
|
||||||
* Fix regression with BufferViewer in double-precision build (#1365)
|
* Fix regression with BufferViewer in double-precision build (#1365)
|
||||||
* Fix `PandaNode.nested_vertices` not updating properly
|
* Fix `PandaNode.nested_vertices` not updating properly
|
||||||
|
* Prevent Panda calculating bounding volume of Geom with custom bounding volume
|
||||||
* Add `do_events()` and `process_event()` snake_case aliases in eventMgr
|
* Add `do_events()` and `process_event()` snake_case aliases in eventMgr
|
||||||
* Support second arg of None in `replace_texture()` / `replace_material()`
|
* Support second arg of None in `replace_texture()` / `replace_material()`
|
||||||
* Support `os.fspath()` for ConfigVariableFilename objects (#1406)
|
* Support `os.fspath()` for ConfigVariableFilename objects (#1406)
|
||||||
|
@ -39,7 +39,8 @@
|
|||||||
// Ask all the windows whether they are OK to be closed.
|
// Ask all the windows whether they are OK to be closed.
|
||||||
bool should_close = true;
|
bool should_close = true;
|
||||||
for (NSWindow *window in [app windows]) {
|
for (NSWindow *window in [app windows]) {
|
||||||
if (![[window delegate] windowShouldClose:window]) {
|
id<NSWindowDelegate> delegate = [window delegate];
|
||||||
|
if (delegate != nil && ![delegate windowShouldClose:window]) {
|
||||||
should_close = false;
|
should_close = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,8 @@ PUBLISHED:
|
|||||||
|
|
||||||
EXTENSION(int __getbuffer__(PyObject *self, Py_buffer *view, int flags));
|
EXTENSION(int __getbuffer__(PyObject *self, Py_buffer *view, int flags));
|
||||||
EXTENSION(void __releasebuffer__(PyObject *self, Py_buffer *view) const);
|
EXTENSION(void __releasebuffer__(PyObject *self, Py_buffer *view) const);
|
||||||
|
|
||||||
|
EXTENSION(PointerToArray<Element> __deepcopy__(PyObject *memo) const);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else // CPPPARSER
|
#else // CPPPARSER
|
||||||
@ -279,6 +281,8 @@ PUBLISHED:
|
|||||||
|
|
||||||
EXTENSION(int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const);
|
EXTENSION(int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const);
|
||||||
EXTENSION(void __releasebuffer__(PyObject *self, Py_buffer *view) const);
|
EXTENSION(void __releasebuffer__(PyObject *self, Py_buffer *view) const);
|
||||||
|
|
||||||
|
EXTENSION(ConstPointerToArray<Element> __deepcopy__(PyObject *memo) const);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else // CPPPARSER
|
#else // CPPPARSER
|
||||||
|
@ -440,6 +440,20 @@ __releasebuffer__(PyObject *self, Py_buffer *view) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special Python method that is invoked by copy.deepcopy(pta). This makes
|
||||||
|
* sure that there is truly a unique copy of the array.
|
||||||
|
*/
|
||||||
|
template<class Element>
|
||||||
|
INLINE PointerToArray<Element> Extension<PointerToArray<Element> >::
|
||||||
|
__deepcopy__(PyObject *memo) const {
|
||||||
|
PointerToArray<Element> copy;
|
||||||
|
if (!this->_this->is_null()) {
|
||||||
|
copy.v() = this->_this->v();
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is used to implement the buffer protocol, in order to allow efficient
|
* This is used to implement the buffer protocol, in order to allow efficient
|
||||||
* access to the array data through a Python multiview object.
|
* access to the array data through a Python multiview object.
|
||||||
@ -610,3 +624,17 @@ __releasebuffer__(PyObject *self, Py_buffer *view) const {
|
|||||||
view->internal = nullptr;
|
view->internal = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special Python method that is invoked by copy.deepcopy(pta). This makes
|
||||||
|
* sure that there is truly a unique copy of the array.
|
||||||
|
*/
|
||||||
|
template<class Element>
|
||||||
|
INLINE ConstPointerToArray<Element> Extension<ConstPointerToArray<Element> >::
|
||||||
|
__deepcopy__(PyObject *memo) const {
|
||||||
|
PointerToArray<Element> copy;
|
||||||
|
if (!this->_this->is_null()) {
|
||||||
|
copy.v() = this->_this->v();
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
@ -44,6 +44,8 @@ public:
|
|||||||
|
|
||||||
INLINE int __getbuffer__(PyObject *self, Py_buffer *view, int flags);
|
INLINE int __getbuffer__(PyObject *self, Py_buffer *view, int flags);
|
||||||
INLINE void __releasebuffer__(PyObject *self, Py_buffer *view) const;
|
INLINE void __releasebuffer__(PyObject *self, Py_buffer *view) const;
|
||||||
|
|
||||||
|
INLINE PointerToArray<Element> __deepcopy__(PyObject *memo) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@ -81,6 +83,8 @@ public:
|
|||||||
|
|
||||||
INLINE int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
INLINE int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
||||||
INLINE void __releasebuffer__(PyObject *self, Py_buffer *view) const;
|
INLINE void __releasebuffer__(PyObject *self, Py_buffer *view) const;
|
||||||
|
|
||||||
|
INLINE ConstPointerToArray<Element> __deepcopy__(PyObject *memo) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -4472,6 +4472,20 @@ get_data4f(const unsigned char *pointer) {
|
|||||||
return _v4;
|
return _v4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const LVecBase4d &GeomVertexColumn::Packer_argb_packed::
|
||||||
|
get_data4d(const unsigned char *pointer) {
|
||||||
|
uint32_t dword = *(const uint32_t *)pointer;
|
||||||
|
_v4d.set(GeomVertexData::unpack_abcd_b(dword),
|
||||||
|
GeomVertexData::unpack_abcd_c(dword),
|
||||||
|
GeomVertexData::unpack_abcd_d(dword),
|
||||||
|
GeomVertexData::unpack_abcd_a(dword));
|
||||||
|
_v4d /= 255.0;
|
||||||
|
return _v4d;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -4486,6 +4500,20 @@ set_data4f(unsigned char *pointer, const LVecBase4f &data) {
|
|||||||
(unsigned int)(min(max(data[2], 0.0f), 1.0f) * 255.0f));
|
(unsigned int)(min(max(data[2], 0.0f), 1.0f) * 255.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void GeomVertexColumn::Packer_argb_packed::
|
||||||
|
set_data4d(unsigned char *pointer, const LVecBase4d &data) {
|
||||||
|
// when packing an argb, we want to make sure we cap the input values at 1
|
||||||
|
// since going above one will cause the value to be truncated.
|
||||||
|
*(uint32_t *)pointer = GeomVertexData::pack_abcd
|
||||||
|
((unsigned int)(min(max(data[3], 0.0), 1.0) * 255.0),
|
||||||
|
(unsigned int)(min(max(data[0], 0.0), 1.0) * 255.0),
|
||||||
|
(unsigned int)(min(max(data[1], 0.0), 1.0) * 255.0),
|
||||||
|
(unsigned int)(min(max(data[2], 0.0), 1.0) * 255.0));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -4497,6 +4525,17 @@ get_data4f(const unsigned char *pointer) {
|
|||||||
return _v4;
|
return _v4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const LVecBase4d &GeomVertexColumn::Packer_rgba_uint8_4::
|
||||||
|
get_data4d(const unsigned char *pointer) {
|
||||||
|
_v4d.set((double)pointer[0], (double)pointer[1],
|
||||||
|
(double)pointer[2], (double)pointer[3]);
|
||||||
|
_v4d /= 255.0;
|
||||||
|
return _v4d;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -4508,6 +4547,17 @@ set_data4f(unsigned char *pointer, const LVecBase4f &data) {
|
|||||||
pointer[3] = (unsigned int)(min(max(data[3], 0.0f), 1.0f) * 255.0f);
|
pointer[3] = (unsigned int)(min(max(data[3], 0.0f), 1.0f) * 255.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void GeomVertexColumn::Packer_rgba_uint8_4::
|
||||||
|
set_data4d(unsigned char *pointer, const LVecBase4d &data) {
|
||||||
|
pointer[0] = (unsigned int)(min(max(data[0], 0.0), 1.0) * 255.0);
|
||||||
|
pointer[1] = (unsigned int)(min(max(data[1], 0.0), 1.0) * 255.0);
|
||||||
|
pointer[2] = (unsigned int)(min(max(data[2], 0.0), 1.0) * 255.0);
|
||||||
|
pointer[3] = (unsigned int)(min(max(data[3], 0.0), 1.0) * 255.0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -381,7 +381,9 @@ private:
|
|||||||
class Packer_argb_packed final : public Packer_color {
|
class Packer_argb_packed final : public Packer_color {
|
||||||
public:
|
public:
|
||||||
virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
|
virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
|
||||||
|
virtual const LVecBase4d &get_data4d(const unsigned char *pointer);
|
||||||
virtual void set_data4f(unsigned char *pointer, const LVecBase4f &value);
|
virtual void set_data4f(unsigned char *pointer, const LVecBase4f &value);
|
||||||
|
virtual void set_data4d(unsigned char *pointer, const LVecBase4d &value);
|
||||||
|
|
||||||
virtual const char *get_name() const {
|
virtual const char *get_name() const {
|
||||||
return "Packer_argb_packed";
|
return "Packer_argb_packed";
|
||||||
@ -391,7 +393,9 @@ private:
|
|||||||
class Packer_rgba_uint8_4 final : public Packer_color {
|
class Packer_rgba_uint8_4 final : public Packer_color {
|
||||||
public:
|
public:
|
||||||
virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
|
virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
|
||||||
|
virtual const LVecBase4d &get_data4d(const unsigned char *pointer);
|
||||||
virtual void set_data4f(unsigned char *pointer, const LVecBase4f &value);
|
virtual void set_data4f(unsigned char *pointer, const LVecBase4f &value);
|
||||||
|
virtual void set_data4d(unsigned char *pointer, const LVecBase4d &value);
|
||||||
|
|
||||||
virtual const char *get_name() const {
|
virtual const char *get_name() const {
|
||||||
return "Packer_rgba_uint8_4";
|
return "Packer_rgba_uint8_4";
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "pnmImage.h"
|
#include "pnmImage.h"
|
||||||
#include "pfmFile.h"
|
#include "pfmFile.h"
|
||||||
#include "asyncTask.h"
|
#include "asyncTask.h"
|
||||||
|
#include "extension.h"
|
||||||
|
|
||||||
class TextureContext;
|
class TextureContext;
|
||||||
class FactoryParams;
|
class FactoryParams;
|
||||||
@ -473,6 +474,8 @@ PUBLISHED:
|
|||||||
MAKE_PROPERTY(keep_ram_image, get_keep_ram_image, set_keep_ram_image);
|
MAKE_PROPERTY(keep_ram_image, get_keep_ram_image, set_keep_ram_image);
|
||||||
MAKE_PROPERTY(cacheable, is_cacheable);
|
MAKE_PROPERTY(cacheable, is_cacheable);
|
||||||
|
|
||||||
|
EXTENSION(PT(Texture) __deepcopy__(PyObject *memo) const);
|
||||||
|
|
||||||
BLOCKING INLINE bool compress_ram_image(CompressionMode compression = CM_on,
|
BLOCKING INLINE bool compress_ram_image(CompressionMode compression = CM_on,
|
||||||
QualityLevel quality_level = QL_default,
|
QualityLevel quality_level = QL_default,
|
||||||
GraphicsStateGuardianBase *gsg = nullptr);
|
GraphicsStateGuardianBase *gsg = nullptr);
|
||||||
@ -1122,6 +1125,7 @@ private:
|
|||||||
|
|
||||||
static TypeHandle _type_handle;
|
static TypeHandle _type_handle;
|
||||||
|
|
||||||
|
friend class Extension<Texture>;
|
||||||
friend class TextureContext;
|
friend class TextureContext;
|
||||||
friend class PreparedGraphicsObjects;
|
friend class PreparedGraphicsObjects;
|
||||||
friend class TexturePool;
|
friend class TexturePool;
|
||||||
|
@ -138,4 +138,32 @@ set_ram_image_as(PyObject *image, const std::string &provided_format) {
|
|||||||
Dtool_Raise_ArgTypeError(image, 0, "Texture.set_ram_image_as", "CPTA_uchar or buffer");
|
Dtool_Raise_ArgTypeError(image, 0, "Texture.set_ram_image_as", "CPTA_uchar or buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special Python method that is invoked by copy.deepcopy(tex). This makes
|
||||||
|
* sure that the copy has a unique copy of the RAM image.
|
||||||
|
*/
|
||||||
|
PT(Texture) Extension<Texture>::
|
||||||
|
__deepcopy__(PyObject *memo) const {
|
||||||
|
PT(Texture) copy = _this->make_copy();
|
||||||
|
{
|
||||||
|
Texture::CDWriter cdata(copy->_cycler, true);
|
||||||
|
for (Texture::RamImage &image : cdata->_ram_images) {
|
||||||
|
if (image._image.get_ref_count() > 1) {
|
||||||
|
PTA_uchar new_image;
|
||||||
|
new_image.v() = image._image.v();
|
||||||
|
image._image = std::move(new_image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Texture::RamImage &image = cdata->_simple_ram_image;
|
||||||
|
if (image._image.get_ref_count() > 1) {
|
||||||
|
PTA_uchar new_image;
|
||||||
|
new_image.v() = image._image.v();
|
||||||
|
image._image = std::move(new_image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // HAVE_PYTHON
|
#endif // HAVE_PYTHON
|
||||||
|
@ -32,6 +32,8 @@ public:
|
|||||||
void set_ram_image(PyObject *image, Texture::CompressionMode compression = Texture::CM_off,
|
void set_ram_image(PyObject *image, Texture::CompressionMode compression = Texture::CM_off,
|
||||||
size_t page_size = 0);
|
size_t page_size = 0);
|
||||||
void set_ram_image_as(PyObject *image, const std::string &provided_format);
|
void set_ram_image_as(PyObject *image, const std::string &provided_format);
|
||||||
|
|
||||||
|
PT(Texture) __deepcopy__(PyObject *memo) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HAVE_PYTHON
|
#endif // HAVE_PYTHON
|
||||||
|
@ -69,3 +69,63 @@ def test_cpta_float_pickle():
|
|||||||
data_pta2 = loads(dumps(data_pta, proto))
|
data_pta2 = loads(dumps(data_pta, proto))
|
||||||
assert tuple(data_pta2) == (1.0, 2.0, 3.0)
|
assert tuple(data_pta2) == (1.0, 2.0, 3.0)
|
||||||
assert data_pta2.get_data() == data_pta.get_data()
|
assert data_pta2.get_data() == data_pta.get_data()
|
||||||
|
|
||||||
|
|
||||||
|
def test_pta_float_copy():
|
||||||
|
from panda3d.core import PTA_float
|
||||||
|
from copy import copy
|
||||||
|
|
||||||
|
null_pta = PTA_float()
|
||||||
|
assert copy(null_pta).is_null()
|
||||||
|
|
||||||
|
empty_pta = PTA_float([])
|
||||||
|
empty_pta_copy = copy(empty_pta)
|
||||||
|
assert not empty_pta_copy.is_null()
|
||||||
|
assert len(empty_pta_copy) == 0
|
||||||
|
assert empty_pta_copy.get_ref_count() == 2
|
||||||
|
|
||||||
|
data_pta = PTA_float([1.0, 2.0, 3.0])
|
||||||
|
data_pta_copy = copy(data_pta)
|
||||||
|
assert not data_pta_copy.is_null()
|
||||||
|
assert data_pta_copy.get_ref_count() == 2
|
||||||
|
assert tuple(data_pta_copy) == (1.0, 2.0, 3.0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pta_float_deepcopy():
|
||||||
|
from panda3d.core import PTA_float
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
null_pta = PTA_float()
|
||||||
|
assert deepcopy(null_pta).is_null()
|
||||||
|
|
||||||
|
empty_pta = PTA_float([])
|
||||||
|
empty_pta_copy = deepcopy(empty_pta)
|
||||||
|
assert not empty_pta_copy.is_null()
|
||||||
|
assert len(empty_pta_copy) == 0
|
||||||
|
assert empty_pta_copy.get_ref_count() == 1
|
||||||
|
|
||||||
|
data_pta = PTA_float([1.0, 2.0, 3.0])
|
||||||
|
data_pta_copy = deepcopy(data_pta)
|
||||||
|
assert not data_pta_copy.is_null()
|
||||||
|
assert data_pta_copy.get_ref_count() == 1
|
||||||
|
assert tuple(data_pta_copy) == (1.0, 2.0, 3.0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cpta_float_deepcopy():
|
||||||
|
from panda3d.core import PTA_float, CPTA_float
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
null_pta = CPTA_float(PTA_float())
|
||||||
|
assert deepcopy(null_pta).is_null()
|
||||||
|
|
||||||
|
empty_pta = CPTA_float([])
|
||||||
|
empty_pta_copy = deepcopy(empty_pta)
|
||||||
|
assert not empty_pta_copy.is_null()
|
||||||
|
assert len(empty_pta_copy) == 0
|
||||||
|
assert empty_pta_copy.get_ref_count() == 1
|
||||||
|
|
||||||
|
data_pta = CPTA_float([1.0, 2.0, 3.0])
|
||||||
|
data_pta_copy = deepcopy(data_pta)
|
||||||
|
assert not data_pta_copy.is_null()
|
||||||
|
assert data_pta_copy.get_ref_count() == 1
|
||||||
|
assert tuple(data_pta_copy) == (1.0, 2.0, 3.0)
|
||||||
|
@ -134,3 +134,26 @@ def test_texture_clear_half():
|
|||||||
assert col.y == -inf
|
assert col.y == -inf
|
||||||
assert col.z == -inf
|
assert col.z == -inf
|
||||||
assert math.isnan(col.w)
|
assert math.isnan(col.w)
|
||||||
|
|
||||||
|
|
||||||
|
def test_texture_deepcopy():
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
empty_tex = Texture("empty-texture")
|
||||||
|
empty_tex.setup_2d_texture(16, 16, Texture.T_unsigned_byte, Texture.F_rgba)
|
||||||
|
assert not empty_tex.has_ram_image()
|
||||||
|
empty_tex2 = deepcopy(empty_tex)
|
||||||
|
assert empty_tex2.name == empty_tex.name
|
||||||
|
assert not empty_tex2.has_ram_image()
|
||||||
|
|
||||||
|
tex = Texture("texture")
|
||||||
|
tex.setup_2d_texture(16, 16, Texture.T_unsigned_byte, Texture.F_rgba)
|
||||||
|
img = tex.make_ram_image()
|
||||||
|
assert tex.has_ram_image()
|
||||||
|
assert img.get_ref_count() == 2
|
||||||
|
|
||||||
|
tex2 = deepcopy(tex)
|
||||||
|
assert tex2.name == tex.name
|
||||||
|
assert tex2.has_ram_image()
|
||||||
|
img2 = tex2.get_ram_image()
|
||||||
|
assert img2.get_ref_count() == 2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user