@@ -63,8 +63,10 @@
/* Windows likes to define min() and max() macros, which will conflict with
std::min() and std::max() respectively, unless we do this: */
#ifdef WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#endif

#ifndef __has_builtin
#define __has_builtin(x) 0
@@ -32,14 +32,14 @@ AnimControl(const std::string &name, PartBundle *part,
Namable(name),
_pending_lock(name),
_pending_cvar(_pending_lock),
_bound_joints(BitArray::all_on())
_bound_joints(BitArray::all_on()),
_part(part)
{
#ifdef DO_MEMORY_USAGE
MemoryUsage::update_type(this, get_class_type());
#endif

_pending = true;
_part = part;
_anim = nullptr;
_channel_index = -1;
set_frame_rate(frame_rate);
@@ -39,6 +39,8 @@ class EXPCL_PANDA_CHAN AnimControl : public TypedReferenceCount, public AnimInte
public:
AnimControl(const std::string &name, PartBundle *part,
double frame_rate, int num_frames);
AnimControl(const AnimControl &copy) = delete;

void setup_anim(PartBundle *part, AnimBundle *anim, int channel_index,
const BitArray &bound_joints);
void set_bound_joints(const BitArray &bound_joints);
@@ -82,7 +84,7 @@ class EXPCL_PANDA_CHAN AnimControl : public TypedReferenceCount, public AnimInte
// This is a PT(PartGroup) instead of a PT(PartBundle), just because we
// can't include partBundle.h for circular reasons. But it actually keeps a
// pointer to a PartBundle.
PT(PartGroup) _part;
const PT(PartGroup) _part;
PT(AnimBundle) _anim;
int _channel_index;

@@ -558,6 +558,12 @@ control_removed(AnimControl *control) {
if (cbi != cdata->_blend.end()) {
cdata->_blend.erase(cbi);
cdata->_anim_changed = true;

// We need to make sure that any _effective_channel pointers that point
// to this control are cleared.
if (pipeline_stage == 0) {
determine_effective_channels(cdata);
}
}
}
CLOSE_ITERATE_ALL_STAGES(_cycler);
@@ -8925,6 +8925,9 @@ get_panda_wrap_mode(GLenum wm) {
case GL_REPEAT:
return SamplerState::WM_repeat;

case GL_MIRRORED_REPEAT:
return SamplerState::WM_mirror;

#ifndef OPENGLES
case GL_MIRROR_CLAMP_EXT:
case GL_MIRROR_CLAMP_TO_EDGE_EXT:
@@ -772,7 +772,9 @@ set_object(const GeomVertexData *object) {
_cdata = (GeomVertexData::CData *)_object->_cycler.read_unlocked(_current_thread);
_got_array_readers = false;

#ifdef DO_PIPELINING
_cdata->ref();
#endif // DO_PIPELINING
}

/**
@@ -54,6 +54,9 @@ apply_transform_and_state(CullTraverser *trav) {
CPT(TransformState) node_transform = _node_reader.get_transform();
node_effects->cull_callback(trav, *this, node_transform, node_state);
apply_transform(node_transform);

// The cull callback may have changed the node properties.
_node_reader.check_cached(false);
}

if (!node_state->is_empty()) {
@@ -211,7 +211,7 @@ garbage_collect() {
}

num_this_pass = std::min(num_this_pass, size);
size_t stop_at_element = (_garbage_index + num_this_pass) % size;
size_t stop_at_element = (si + num_this_pass) % size;

do {
RenderAttrib *attrib = (RenderAttrib *)_attribs->get_key(si);
@@ -229,6 +229,9 @@ garbage_collect() {
// still need to visit.
--size;
--si;
if (stop_at_element > 0) {
--stop_at_element;
}
}

si = (si + 1) % size;
@@ -950,6 +950,9 @@ garbage_collect() {
// still need to visit.
--size;
--si;
if (stop_at_element > 0) {
--stop_at_element;
}
}

si = (si + 1) % size;
@@ -1216,6 +1216,9 @@ garbage_collect() {
// still need to visit.
--size;
--si;
if (stop_at_element > 0) {
--stop_at_element;
}
}

si = (si + 1) % size;
@@ -71,7 +71,10 @@ init_libpipeline() {
}
initialized = true;

#ifdef DO_PIPELINING
CycleData::init_type();
#endif

MainThread::init_type();
ExternalThread::init_type();
GenericThread::init_type();
@@ -50,10 +50,13 @@ class EXPCL_PANDA_PIPELINE CycleData
{
public:
INLINE CycleData() = default;
INLINE CycleData(CycleData &&from) = default;
INLINE CycleData(CycleData &&from) noexcept = default;
INLINE CycleData(const CycleData &copy) = default;
virtual ~CycleData();

CycleData &operator = (CycleData &&from) noexcept = default;
CycleData &operator = (const CycleData &copy) = default;

virtual CycleData *make_copy() const=0;

virtual void write_datagram(BamWriter *, Datagram &) const;
@@ -47,6 +47,20 @@ CycleDataLockedStageReader(const CycleDataLockedStageReader<CycleDataType> &copy
_cycler->increment_read(_pointer);
}

/**
*
*/
template<class CycleDataType>
INLINE CycleDataLockedStageReader<CycleDataType>::
CycleDataLockedStageReader(CycleDataLockedStageReader<CycleDataType> &&from) noexcept :
_cycler(from._cycler),
_current_thread(from._current_thread),
_pointer(from._pointer),
_stage(from._stage)
{
from._pointer = nullptr;
}

/**
*
*/
@@ -64,20 +78,6 @@ operator = (const CycleDataLockedStageReader<CycleDataType> &copy) {
_cycler->increment_read(_pointer);
}

/**
*
*/
template<class CycleDataType>
INLINE CycleDataLockedStageReader<CycleDataType>::
CycleDataLockedStageReader(CycleDataLockedStageReader<CycleDataType> &&from) noexcept :
_cycler(from._cycler),
_current_thread(from._current_thread),
_pointer(from._pointer),
_stage(from._stage)
{
from._pointer = nullptr;
}

/**
*
*/
@@ -174,6 +174,17 @@ CycleDataLockedStageReader(const CycleDataLockedStageReader<CycleDataType> &copy
{
}

/**
*
*/
template<class CycleDataType>
INLINE CycleDataLockedStageReader<CycleDataType>::
CycleDataLockedStageReader(CycleDataLockedStageReader<CycleDataType> &&from) noexcept :
_pointer(from._cycler)
{
from._pointer = nullptr;
}

/**
*
*/
@@ -183,6 +194,18 @@ operator = (const CycleDataLockedStageReader<CycleDataType> &copy) {
_pointer = copy._pointer;
}

/**
*
*/
template<class CycleDataType>
INLINE void CycleDataLockedStageReader<CycleDataType>::
operator = (CycleDataLockedStageReader<CycleDataType> &&from) noexcept {
nassertv(_pointer == nullptr);

_pointer = from._pointer;
from._pointer = nullptr;
}

/**
*
*/
@@ -62,23 +62,6 @@ CycleDataStageWriter(const CycleDataStageWriter<CycleDataType> &copy) :
_cycler->increment_write(_pointer);
}

/**
*
*/
template<class CycleDataType>
INLINE void CycleDataStageWriter<CycleDataType>::
operator = (const CycleDataStageWriter<CycleDataType> &copy) {
nassertv(_pointer == nullptr);
nassertv(_current_thread == copy._current_thread);

_cycler = copy._cycler;
_pointer = copy._pointer;
_stage = copy._stage;

nassertv(_pointer != nullptr);
_cycler->increment_write(_pointer);
}

/**
* This flavor of the constructor elevates the pointer from the
* CycleDataLockedStageReader from a read to a write pointer (and invalidates
@@ -128,6 +111,23 @@ CycleDataStageWriter(CycleDataStageWriter<CycleDataType> &&from) noexcept :
from._pointer = nullptr;
}

/**
*
*/
template<class CycleDataType>
INLINE void CycleDataStageWriter<CycleDataType>::
operator = (const CycleDataStageWriter<CycleDataType> &copy) {
nassertv(_pointer == nullptr);
nassertv(_current_thread == copy._current_thread);

_cycler = copy._cycler;
_pointer = copy._pointer;
_stage = copy._stage;

nassertv(_pointer != nullptr);
_cycler->increment_write(_pointer);
}

/**
*
*/
@@ -227,6 +227,17 @@ CycleDataStageWriter(const CycleDataStageWriter<CycleDataType> &copy) :
{
}

/**
*
*/
template<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
CycleDataStageWriter(CycleDataStageWriter<CycleDataType> &&from) noexcept :
_pointer(from._pointer)
{
from._pointer = nullptr;
}

/**
*
*/
@@ -236,6 +247,18 @@ operator = (const CycleDataStageWriter<CycleDataType> &copy) {
_pointer = copy._pointer;
}

/**
*
*/
template<class CycleDataType>
INLINE void CycleDataStageWriter<CycleDataType>::
operator = (CycleDataStageWriter<CycleDataType> &&from) noexcept {
nassertv(_pointer == nullptr);

_pointer = from._pointer;
from._pointer = nullptr;
}

/**
* This flavor of the constructor elevates the pointer from the
* CycleDataLockedStageReader from a read to a write pointer (and invalidates
@@ -1,6 +1,5 @@
from panda3d import core
import pytest
import threading
import time
import sys

@@ -39,7 +38,11 @@ def test_future_timeout():
fut.result(0.001)


@pytest.mark.skipif(not core.Thread.is_threading_supported(),
reason="Threading support disabled")
def test_future_wait():
threading = pytest.importorskip("direct.stdpy.threading")

fut = core.AsyncFuture()

# Launch a thread to set the result value.
@@ -59,7 +62,11 @@ def thread_main():
assert fut.result() is None


@pytest.mark.skipif(not core.Thread.is_threading_supported(),
reason="Threading support disabled")
def test_future_wait_cancel():
threading = pytest.importorskip("direct.stdpy.threading")

fut = core.AsyncFuture()

# Launch a thread to cancel the future.