more threading improvements
This commit is contained in:
parent
eaa1318450
commit
fab502970f
|
|
@ -714,7 +714,8 @@
|
|||
// This gives you control over when the context switch happens, and
|
||||
// may make mutexes unnecessary, if you are somewhat careful in your
|
||||
// code design. Disabling mutexes saves a tiny bit of runtime and
|
||||
// memory overhead.
|
||||
// memory overhead. NOT RECOMMENDED! Many internal Panda functions
|
||||
// aren't quite secure enough to enable this mode for now.
|
||||
#define SIMPLE_THREADS_NO_MUTEX
|
||||
|
||||
// Whether threading is defined or not, you might want to validate the
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE BindAnimRequest::
|
||||
BindAnimRequest(const Filename &filename, const LoaderOptions &options,
|
||||
BindAnimRequest(const string &name,
|
||||
const Filename &filename, const LoaderOptions &options,
|
||||
Loader *loader,
|
||||
AnimControl *control, int hierarchy_match_flags,
|
||||
const PartSubset &subset) :
|
||||
ModelLoadRequest(filename, options, loader),
|
||||
ModelLoadRequest(name, filename, options, loader),
|
||||
_control(control),
|
||||
_hierarchy_match_flags(hierarchy_match_flags),
|
||||
_subset(subset)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ public:
|
|||
ALLOC_DELETED_CHAIN(BindAnimRequest);
|
||||
|
||||
PUBLISHED:
|
||||
INLINE BindAnimRequest(const Filename &filename,
|
||||
INLINE BindAnimRequest(const string &name,
|
||||
const Filename &filename,
|
||||
const LoaderOptions &options,
|
||||
Loader *loader,
|
||||
AnimControl *control,
|
||||
|
|
|
|||
|
|
@ -363,7 +363,8 @@ load_bind_anim(Loader *loader, const Filename &filename,
|
|||
}
|
||||
|
||||
PT(BindAnimRequest) request =
|
||||
new BindAnimRequest(filename, anim_options, loader, control,
|
||||
new BindAnimRequest(string("bind:") + filename.get_basename(),
|
||||
filename, anim_options, loader, control,
|
||||
hierarchy_match_flags, subset);
|
||||
loader->load_async(request);
|
||||
|
||||
|
|
|
|||
|
|
@ -307,7 +307,9 @@ set_from_collide_mask(CollideMask mask) {
|
|||
// thing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionNode::
|
||||
compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
pvector<CPT(BoundingVolume) > child_volumes_ref;
|
||||
pvector<const BoundingVolume *> child_volumes;
|
||||
|
|
@ -345,9 +347,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
|||
((BoundingVolume *)gbv)->around(child_begin, child_end);
|
||||
}
|
||||
|
||||
bdata->_internal_bounds = gbv;
|
||||
bdata->_internal_vertices = 0;
|
||||
bdata->_internal_bounds_stale = false;
|
||||
internal_bounds = gbv;
|
||||
internal_vertices = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -71,7 +71,9 @@ PUBLISHED:
|
|||
INLINE static CollideMask get_default_collide_mask();
|
||||
|
||||
protected:
|
||||
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
|
||||
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "collisionInvSphere.h"
|
||||
#include "collisionLine.h"
|
||||
#include "collisionLevelStateBase.h"
|
||||
#include "collisionGeom.h"
|
||||
#include "collisionNode.h"
|
||||
#include "collisionParabola.h"
|
||||
#include "collisionPlane.h"
|
||||
|
|
@ -129,6 +130,7 @@ init_libcollide() {
|
|||
CollisionInvSphere::init_type();
|
||||
CollisionLine::init_type();
|
||||
CollisionLevelStateBase::init_type();
|
||||
CollisionGeom::init_type();
|
||||
CollisionNode::init_type();
|
||||
CollisionParabola::init_type();
|
||||
CollisionPlane::init_type();
|
||||
|
|
|
|||
|
|
@ -206,13 +206,14 @@ ConfigVariableBool alpha_scale_via_texture
|
|||
"color-scale-via-lighting."));
|
||||
|
||||
ConfigVariableBool allow_incomplete_render
|
||||
("allow-incomplete-render", false,
|
||||
("allow-incomplete-render", true,
|
||||
PRC_DESC("When this is true, the frame may be rendered even if some of the "
|
||||
"geometry in the scene has been paged out. The nonresident "
|
||||
"geometry will be rendered as soon as it can be paged back in, "
|
||||
"geometry in the scene has been paged out, or if the textures are "
|
||||
"unavailable. The nonresident geometry and textures will be "
|
||||
"rendered as soon as they can be read from disk, "
|
||||
"which may be several frames in the future. When this is false, "
|
||||
"geometry is always paged in when needed, holding up the frame "
|
||||
"render if necessary."));
|
||||
"geometry is always paged in immediately when needed, holding up "
|
||||
"the frame render if necessary."));
|
||||
|
||||
ConfigVariableInt win_size
|
||||
("win-size", "640 480",
|
||||
|
|
|
|||
|
|
@ -610,191 +610,195 @@ render_frame() {
|
|||
<< "render_frame() - frame " << global_clock->get_frame_count() << "\n";
|
||||
}
|
||||
|
||||
ReMutexHolder holder(_lock, current_thread);
|
||||
{
|
||||
ReMutexHolder holder(_lock, current_thread);
|
||||
|
||||
if (!_windows_sorted) {
|
||||
do_resort_windows();
|
||||
}
|
||||
|
||||
if (sync_flip && _flip_state != FS_flip) {
|
||||
do_flip_frame(current_thread);
|
||||
}
|
||||
|
||||
// Are any of the windows ready to be deleted?
|
||||
Windows new_windows;
|
||||
new_windows.reserve(_windows.size());
|
||||
Windows::iterator wi;
|
||||
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
|
||||
GraphicsOutput *win = (*wi);
|
||||
if (win->get_delete_flag()) {
|
||||
do_remove_window(win, current_thread);
|
||||
|
||||
} else {
|
||||
new_windows.push_back(win);
|
||||
|
||||
// Let's calculate each scene's bounding volume here in App,
|
||||
// before we cycle the pipeline. The cull traversal will
|
||||
// calculate it anyway, but if we calculate it in App first
|
||||
// before it gets calculated in the Cull thread, it will be more
|
||||
// likely to stick for subsequent frames, so we won't have to
|
||||
// recompute it each frame.
|
||||
int num_drs = win->get_num_active_display_regions();
|
||||
for (int i = 0; i < num_drs; ++i) {
|
||||
DisplayRegion *dr = win->get_active_display_region(i);
|
||||
if (dr != (DisplayRegion *)NULL) {
|
||||
NodePath camera_np = dr->get_camera(current_thread);
|
||||
if (!camera_np.is_empty()) {
|
||||
Camera *camera = DCAST(Camera, camera_np.node());
|
||||
NodePath scene = camera->get_scene();
|
||||
if (scene.is_empty()) {
|
||||
scene = camera_np.get_top(current_thread);
|
||||
}
|
||||
if (!scene.is_empty()) {
|
||||
scene.get_bounds(current_thread);
|
||||
if (!_windows_sorted) {
|
||||
do_resort_windows();
|
||||
}
|
||||
|
||||
if (sync_flip && _flip_state != FS_flip) {
|
||||
do_flip_frame(current_thread);
|
||||
}
|
||||
|
||||
// Are any of the windows ready to be deleted?
|
||||
Windows new_windows;
|
||||
new_windows.reserve(_windows.size());
|
||||
Windows::iterator wi;
|
||||
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
|
||||
GraphicsOutput *win = (*wi);
|
||||
if (win->get_delete_flag()) {
|
||||
do_remove_window(win, current_thread);
|
||||
|
||||
} else {
|
||||
new_windows.push_back(win);
|
||||
|
||||
// Let's calculate each scene's bounding volume here in App,
|
||||
// before we cycle the pipeline. The cull traversal will
|
||||
// calculate it anyway, but if we calculate it in App first
|
||||
// before it gets calculated in the Cull thread, it will be more
|
||||
// likely to stick for subsequent frames, so we won't have to
|
||||
// recompute it each frame.
|
||||
int num_drs = win->get_num_active_display_regions();
|
||||
for (int i = 0; i < num_drs; ++i) {
|
||||
DisplayRegion *dr = win->get_active_display_region(i);
|
||||
if (dr != (DisplayRegion *)NULL) {
|
||||
NodePath camera_np = dr->get_camera(current_thread);
|
||||
if (!camera_np.is_empty()) {
|
||||
Camera *camera = DCAST(Camera, camera_np.node());
|
||||
NodePath scene = camera->get_scene();
|
||||
if (scene.is_empty()) {
|
||||
scene = camera_np.get_top(current_thread);
|
||||
}
|
||||
if (!scene.is_empty()) {
|
||||
scene.get_bounds(current_thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_windows.swap(new_windows);
|
||||
|
||||
// Now it's time to do any drawing from the main frame--after all of
|
||||
// the App code has executed, but before we begin the next frame.
|
||||
_app.do_frame(this, current_thread);
|
||||
|
||||
// Grab each thread's mutex again after all windows have flipped,
|
||||
// and wait for the thread to finish.
|
||||
{
|
||||
PStatTimer timer(_wait_pcollector, current_thread);
|
||||
_windows.swap(new_windows);
|
||||
|
||||
// Now it's time to do any drawing from the main frame--after all of
|
||||
// the App code has executed, but before we begin the next frame.
|
||||
_app.do_frame(this, current_thread);
|
||||
|
||||
// Grab each thread's mutex again after all windows have flipped,
|
||||
// and wait for the thread to finish.
|
||||
{
|
||||
PStatTimer timer(_wait_pcollector, current_thread);
|
||||
Threads::const_iterator ti;
|
||||
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
|
||||
RenderThread *thread = (*ti).second;
|
||||
thread->_cv_mutex.lock();
|
||||
|
||||
while (thread->_thread_state != TS_wait) {
|
||||
thread->_cv_done.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(THREADED_PIPELINE) && defined(DO_PSTATS)
|
||||
_cyclers_pcollector.set_level(_pipeline->get_num_cyclers());
|
||||
_dirty_cyclers_pcollector.set_level(_pipeline->get_num_dirty_cyclers());
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
if (PStatClient::is_connected()) {
|
||||
_pipeline->iterate_all_cycler_types(pstats_count_cycler_type, this);
|
||||
_pipeline->iterate_dirty_cycler_types(pstats_count_dirty_cycler_type, this);
|
||||
}
|
||||
#endif // DEBUG_THREADS
|
||||
|
||||
#endif // THREADED_PIPELINE && DO_PSTATS
|
||||
|
||||
GeomCacheManager::flush_level();
|
||||
CullTraverser::flush_level();
|
||||
RenderState::flush_level();
|
||||
TransformState::flush_level();
|
||||
CullableObject::flush_level();
|
||||
|
||||
// Now cycle the pipeline and officially begin the next frame.
|
||||
#ifdef THREADED_PIPELINE
|
||||
{
|
||||
PStatTimer timer(_cycle_pcollector, current_thread);
|
||||
_pipeline->cycle();
|
||||
}
|
||||
#endif // THREADED_PIPELINE
|
||||
|
||||
global_clock->tick(current_thread);
|
||||
if (global_clock->check_errors(current_thread)) {
|
||||
throw_event("clock_error");
|
||||
}
|
||||
|
||||
#ifdef DO_PSTATS
|
||||
PStatClient::main_tick();
|
||||
|
||||
// Reset our pcollectors that track data across the frame.
|
||||
CullTraverser::_nodes_pcollector.clear_level();
|
||||
CullTraverser::_geom_nodes_pcollector.clear_level();
|
||||
CullTraverser::_geoms_pcollector.clear_level();
|
||||
GeomCacheManager::_geom_cache_active_pcollector.clear_level();
|
||||
GeomCacheManager::_geom_cache_record_pcollector.clear_level();
|
||||
GeomCacheManager::_geom_cache_erase_pcollector.clear_level();
|
||||
GeomCacheManager::_geom_cache_evict_pcollector.clear_level();
|
||||
|
||||
GraphicsStateGuardian::init_frame_pstats();
|
||||
|
||||
_transform_states_pcollector.set_level(TransformState::get_num_states());
|
||||
_render_states_pcollector.set_level(RenderState::get_num_states());
|
||||
if (pstats_unused_states) {
|
||||
_transform_states_unused_pcollector.set_level(TransformState::get_num_unused_states());
|
||||
_render_states_unused_pcollector.set_level(RenderState::get_num_unused_states());
|
||||
}
|
||||
|
||||
_sw_sprites_pcollector.clear_level();
|
||||
|
||||
_cnode_volume_pcollector.clear_level();
|
||||
_gnode_volume_pcollector.clear_level();
|
||||
_geom_volume_pcollector.clear_level();
|
||||
_node_volume_pcollector.clear_level();
|
||||
_volume_pcollector.clear_level();
|
||||
_test_pcollector.clear_level();
|
||||
_volume_polygon_pcollector.clear_level();
|
||||
_test_polygon_pcollector.clear_level();
|
||||
_volume_plane_pcollector.clear_level();
|
||||
_test_plane_pcollector.clear_level();
|
||||
_volume_sphere_pcollector.clear_level();
|
||||
_test_sphere_pcollector.clear_level();
|
||||
_volume_tube_pcollector.clear_level();
|
||||
_test_tube_pcollector.clear_level();
|
||||
_volume_inv_sphere_pcollector.clear_level();
|
||||
_test_inv_sphere_pcollector.clear_level();
|
||||
_volume_geom_pcollector.clear_level();
|
||||
_test_geom_pcollector.clear_level();
|
||||
_occlusion_untested_pcollector.clear_level();
|
||||
_occlusion_passed_pcollector.clear_level();
|
||||
_occlusion_failed_pcollector.clear_level();
|
||||
_occlusion_tests_pcollector.clear_level();
|
||||
|
||||
if (PStatClient::is_connected()) {
|
||||
size_t small_buf = GeomVertexArrayData::get_small_lru()->get_total_size();
|
||||
size_t independent = GeomVertexArrayData::get_independent_lru()->get_total_size();
|
||||
size_t resident = VertexDataPage::get_global_lru(VertexDataPage::RC_resident)->get_total_size();
|
||||
size_t compressed = VertexDataPage::get_global_lru(VertexDataPage::RC_compressed)->get_total_size();
|
||||
size_t pending = VertexDataPage::get_pending_lru()->get_total_size();
|
||||
|
||||
VertexDataSaveFile *save_file = VertexDataPage::get_save_file();
|
||||
size_t total_disk = save_file->get_total_file_size();
|
||||
size_t used_disk = save_file->get_used_file_size();
|
||||
|
||||
_vertex_data_small_pcollector.set_level(small_buf);
|
||||
_vertex_data_independent_pcollector.set_level(independent);
|
||||
_vertex_data_pending_pcollector.set_level(pending);
|
||||
_vertex_data_resident_pcollector.set_level(resident);
|
||||
_vertex_data_compressed_pcollector.set_level(compressed);
|
||||
_vertex_data_unused_disk_pcollector.set_level(total_disk - used_disk);
|
||||
_vertex_data_used_disk_pcollector.set_level(used_disk);
|
||||
}
|
||||
|
||||
#endif // DO_PSTATS
|
||||
|
||||
GeomVertexArrayData::lru_epoch();
|
||||
|
||||
// Now signal all of our threads to begin their next frame.
|
||||
Threads::const_iterator ti;
|
||||
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
|
||||
RenderThread *thread = (*ti).second;
|
||||
thread->_cv_mutex.lock();
|
||||
|
||||
while (thread->_thread_state != TS_wait) {
|
||||
thread->_cv_done.wait();
|
||||
if (thread->_thread_state == TS_wait) {
|
||||
thread->_thread_state = TS_do_frame;
|
||||
thread->_cv_start.signal();
|
||||
}
|
||||
thread->_cv_mutex.release();
|
||||
}
|
||||
|
||||
// Some threads may still be drawing, so indicate that we have to
|
||||
// wait for those threads before we can flip.
|
||||
_flip_state = _auto_flip ? FS_flip : FS_draw;
|
||||
}
|
||||
|
||||
#if defined(THREADED_PIPELINE) && defined(DO_PSTATS)
|
||||
_cyclers_pcollector.set_level(_pipeline->get_num_cyclers());
|
||||
_dirty_cyclers_pcollector.set_level(_pipeline->get_num_dirty_cyclers());
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
if (PStatClient::is_connected()) {
|
||||
_pipeline->iterate_all_cycler_types(pstats_count_cycler_type, this);
|
||||
_pipeline->iterate_dirty_cycler_types(pstats_count_dirty_cycler_type, this);
|
||||
}
|
||||
#endif // DEBUG_THREADS
|
||||
|
||||
#endif // THREADED_PIPELINE && DO_PSTATS
|
||||
|
||||
GeomCacheManager::flush_level();
|
||||
CullTraverser::flush_level();
|
||||
RenderState::flush_level();
|
||||
TransformState::flush_level();
|
||||
CullableObject::flush_level();
|
||||
|
||||
// Now cycle the pipeline and officially begin the next frame.
|
||||
#ifdef THREADED_PIPELINE
|
||||
{
|
||||
PStatTimer timer(_cycle_pcollector, current_thread);
|
||||
_pipeline->cycle();
|
||||
}
|
||||
#endif // THREADED_PIPELINE
|
||||
|
||||
global_clock->tick(current_thread);
|
||||
if (global_clock->check_errors(current_thread)) {
|
||||
throw_event("clock_error");
|
||||
}
|
||||
|
||||
#ifdef DO_PSTATS
|
||||
PStatClient::main_tick();
|
||||
|
||||
// Reset our pcollectors that track data across the frame.
|
||||
CullTraverser::_nodes_pcollector.clear_level();
|
||||
CullTraverser::_geom_nodes_pcollector.clear_level();
|
||||
CullTraverser::_geoms_pcollector.clear_level();
|
||||
GeomCacheManager::_geom_cache_active_pcollector.clear_level();
|
||||
GeomCacheManager::_geom_cache_record_pcollector.clear_level();
|
||||
GeomCacheManager::_geom_cache_erase_pcollector.clear_level();
|
||||
GeomCacheManager::_geom_cache_evict_pcollector.clear_level();
|
||||
// Now the lock is released.
|
||||
|
||||
GraphicsStateGuardian::init_frame_pstats();
|
||||
|
||||
_transform_states_pcollector.set_level(TransformState::get_num_states());
|
||||
_render_states_pcollector.set_level(RenderState::get_num_states());
|
||||
if (pstats_unused_states) {
|
||||
_transform_states_unused_pcollector.set_level(TransformState::get_num_unused_states());
|
||||
_render_states_unused_pcollector.set_level(RenderState::get_num_unused_states());
|
||||
}
|
||||
|
||||
_sw_sprites_pcollector.clear_level();
|
||||
|
||||
_cnode_volume_pcollector.clear_level();
|
||||
_gnode_volume_pcollector.clear_level();
|
||||
_geom_volume_pcollector.clear_level();
|
||||
_node_volume_pcollector.clear_level();
|
||||
_volume_pcollector.clear_level();
|
||||
_test_pcollector.clear_level();
|
||||
_volume_polygon_pcollector.clear_level();
|
||||
_test_polygon_pcollector.clear_level();
|
||||
_volume_plane_pcollector.clear_level();
|
||||
_test_plane_pcollector.clear_level();
|
||||
_volume_sphere_pcollector.clear_level();
|
||||
_test_sphere_pcollector.clear_level();
|
||||
_volume_tube_pcollector.clear_level();
|
||||
_test_tube_pcollector.clear_level();
|
||||
_volume_inv_sphere_pcollector.clear_level();
|
||||
_test_inv_sphere_pcollector.clear_level();
|
||||
_volume_geom_pcollector.clear_level();
|
||||
_test_geom_pcollector.clear_level();
|
||||
_occlusion_untested_pcollector.clear_level();
|
||||
_occlusion_passed_pcollector.clear_level();
|
||||
_occlusion_failed_pcollector.clear_level();
|
||||
_occlusion_tests_pcollector.clear_level();
|
||||
|
||||
if (PStatClient::is_connected()) {
|
||||
size_t small_buf = GeomVertexArrayData::get_small_lru()->get_total_size();
|
||||
size_t independent = GeomVertexArrayData::get_independent_lru()->get_total_size();
|
||||
size_t resident = VertexDataPage::get_global_lru(VertexDataPage::RC_resident)->get_total_size();
|
||||
size_t compressed = VertexDataPage::get_global_lru(VertexDataPage::RC_compressed)->get_total_size();
|
||||
size_t pending = VertexDataPage::get_pending_lru()->get_total_size();
|
||||
|
||||
VertexDataSaveFile *save_file = VertexDataPage::get_save_file();
|
||||
size_t total_disk = save_file->get_total_file_size();
|
||||
size_t used_disk = save_file->get_used_file_size();
|
||||
|
||||
_vertex_data_small_pcollector.set_level(small_buf);
|
||||
_vertex_data_independent_pcollector.set_level(independent);
|
||||
_vertex_data_pending_pcollector.set_level(pending);
|
||||
_vertex_data_resident_pcollector.set_level(resident);
|
||||
_vertex_data_compressed_pcollector.set_level(compressed);
|
||||
_vertex_data_unused_disk_pcollector.set_level(total_disk - used_disk);
|
||||
_vertex_data_used_disk_pcollector.set_level(used_disk);
|
||||
}
|
||||
|
||||
#endif // DO_PSTATS
|
||||
|
||||
GeomVertexArrayData::lru_epoch();
|
||||
|
||||
// Now signal all of our threads to begin their next frame.
|
||||
Threads::const_iterator ti;
|
||||
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
|
||||
RenderThread *thread = (*ti).second;
|
||||
if (thread->_thread_state == TS_wait) {
|
||||
thread->_thread_state = TS_do_frame;
|
||||
thread->_cv_start.signal();
|
||||
}
|
||||
thread->_cv_mutex.release();
|
||||
}
|
||||
|
||||
// Some threads may still be drawing, so indicate that we have to
|
||||
// wait for those threads before we can flip.
|
||||
_flip_state = _auto_flip ? FS_flip : FS_draw;
|
||||
|
||||
if (yield_timeslice) {
|
||||
// Nap for a moment to yield the timeslice, to be polite to other
|
||||
// running applications.
|
||||
|
|
@ -804,7 +808,7 @@ render_frame() {
|
|||
PStatTimer timer(_yield_pcollector, current_thread);
|
||||
Thread::consider_yield();
|
||||
}
|
||||
|
||||
|
||||
// Anything that happens outside of GraphicsEngine::render_frame()
|
||||
// is deemed to be App.
|
||||
_app_pcollector.start();
|
||||
|
|
|
|||
|
|
@ -2240,7 +2240,8 @@ async_reload_texture(TextureContext *tc) {
|
|||
nassertv(_loader != (Loader *)NULL);
|
||||
|
||||
PT(AsyncTask) request =
|
||||
new TextureReloadRequest(_prepared_objects, tc->get_texture(),
|
||||
new TextureReloadRequest(string("reload:") + tc->get_texture()->get_name(),
|
||||
_prepared_objects, tc->get_texture(),
|
||||
_supports_compressed_texture);
|
||||
_loader->load_async(request);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ sync() {
|
|||
|
||||
size_t num_wrote = write_chars(pbase(), n);
|
||||
pbump(-(int)n);
|
||||
|
||||
if (num_wrote != n) {
|
||||
return EOF;
|
||||
}
|
||||
|
|
@ -213,6 +214,12 @@ underflow() {
|
|||
}
|
||||
gbump(num_bytes);
|
||||
return EOF;
|
||||
|
||||
}
|
||||
|
||||
if (downloader_cat.is_spam()) {
|
||||
downloader_cat.spam()
|
||||
<< "read " << read_count << " bytes from " << _source << "\n";
|
||||
}
|
||||
|
||||
// Slide what we did read to the top of the buffer.
|
||||
|
|
@ -241,7 +248,7 @@ write_chars(const char *start, size_t length) {
|
|||
int write_count = BIO_write(*_source, start, length);
|
||||
if (downloader_cat.is_spam()) {
|
||||
downloader_cat.spam()
|
||||
<< "wrote " << write_count << " bytes.\n";
|
||||
<< "wrote " << write_count << " bytes to " << _source << "\n";
|
||||
}
|
||||
thread_consider_yield();
|
||||
while (write_count != (int)(length - wrote_so_far)) {
|
||||
|
|
@ -272,10 +279,17 @@ write_chars(const char *start, size_t length) {
|
|||
downloader_cat.spam()
|
||||
<< "waiting to write to BIO.\n";
|
||||
}
|
||||
#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
|
||||
// In SIMPLE_THREADS mode, instead of blocking, simply yield
|
||||
// the thread.
|
||||
thread_yield();
|
||||
#else
|
||||
// In any other threading mode, we actually want to block.
|
||||
fd_set wset;
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(fd, &wset);
|
||||
select(fd + 1, NULL, &wset, NULL, NULL);
|
||||
#endif // SIMPLE_THREADS
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ TypeHandle AsyncTaskManager::_type_handle;
|
|||
AsyncTaskManager::
|
||||
AsyncTaskManager(const string &name) :
|
||||
Namable(name),
|
||||
_lock("AsyncTaskManager::_lock"),
|
||||
_num_tasks(0),
|
||||
_clock(ClockObject::get_global_clock()),
|
||||
_frame_cvar(_lock)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ EventQueue *EventQueue::_global_event_queue = NULL;
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
EventQueue::
|
||||
EventQueue() : _lock("EventQueue") {
|
||||
EventQueue() : _lock("EventQueue::_lock") {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -1421,15 +1421,18 @@ combine_primitives(GeomPrimitive *a_prim, const GeomPrimitive *b_prim,
|
|||
b_prim2 = b_prim_copy;
|
||||
}
|
||||
|
||||
PT(GeomVertexArrayDataHandle) a_handle = a_prim->modify_vertices()->modify_handle(current_thread);
|
||||
CPT(GeomVertexArrayDataHandle) b_handle = b_prim2->get_vertices()->get_handle(current_thread);
|
||||
PT(GeomVertexArrayData) a_vertices = a_prim->modify_vertices();
|
||||
CPT(GeomVertexArrayData) b_vertices = b_prim2->get_vertices();
|
||||
|
||||
if (a_prim->requires_unused_vertices()) {
|
||||
GeomVertexReader index(b_handle->get_object(), 0);
|
||||
GeomVertexReader index(b_vertices, 0);
|
||||
int b_vertex = index.get_data1i();
|
||||
a_prim->append_unused_vertices(a_handle->get_object(), b_vertex);
|
||||
a_prim->append_unused_vertices(a_vertices, b_vertex);
|
||||
}
|
||||
|
||||
PT(GeomVertexArrayDataHandle) a_handle = a_vertices->modify_handle(current_thread);
|
||||
CPT(GeomVertexArrayDataHandle) b_handle = b_vertices->get_handle(current_thread);
|
||||
|
||||
size_t orig_a_vertices = a_handle->get_num_rows();
|
||||
|
||||
a_handle->copy_subdata_from(a_handle->get_data_size_bytes(), 0,
|
||||
|
|
|
|||
|
|
@ -1385,11 +1385,11 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
|
|||
} else {
|
||||
// Indexed case.
|
||||
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
|
||||
int num_vertices = get_num_vertices();
|
||||
|
||||
if (got_mat) {
|
||||
for (int i = 0; i < num_vertices; ++i) {
|
||||
reader.set_row(index.get_data1i());
|
||||
while (!index.is_at_end()) {
|
||||
int ii = index.get_data1i();
|
||||
reader.set_row(ii);
|
||||
LPoint3f vertex = mat.xform_point(reader.get_data3f());
|
||||
|
||||
if (found_any) {
|
||||
|
|
@ -1406,7 +1406,7 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < num_vertices; ++i) {
|
||||
while (!index.is_at_end()) {
|
||||
int ii = index.get_data1i();
|
||||
reader.set_row(ii);
|
||||
const LVecBase3f &vertex = reader.get_data3f();
|
||||
|
|
@ -1523,76 +1523,79 @@ recompute_minmax(GeomPrimitive::CData *cdata) {
|
|||
cdata->_mins.clear();
|
||||
cdata->_maxs.clear();
|
||||
|
||||
} else if (get_num_vertices() == 0) {
|
||||
// Or if we don't have any vertices, the minmax is also trivial.
|
||||
cdata->_min_vertex = 0;
|
||||
cdata->_max_vertex = 0;
|
||||
cdata->_mins.clear();
|
||||
cdata->_maxs.clear();
|
||||
} else {
|
||||
int num_vertices = cdata->_vertices.get_read_pointer()->get_num_rows();
|
||||
|
||||
} else if (get_num_vertices_per_primitive() == 0) {
|
||||
// This is a complex primitive type like a triangle strip; compute
|
||||
// the minmax of each primitive (as well as the overall minmax).
|
||||
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
|
||||
|
||||
cdata->_mins = make_index_data();
|
||||
cdata->_maxs = make_index_data();
|
||||
|
||||
GeomVertexWriter mins(cdata->_mins.get_write_pointer(), 0);
|
||||
GeomVertexWriter maxs(cdata->_maxs.get_write_pointer(), 0);
|
||||
|
||||
int pi = 0;
|
||||
|
||||
unsigned int vertex = index.get_data1i();
|
||||
cdata->_min_vertex = vertex;
|
||||
cdata->_max_vertex = vertex;
|
||||
unsigned int min_prim = vertex;
|
||||
unsigned int max_prim = vertex;
|
||||
|
||||
int num_vertices = get_num_vertices();
|
||||
for (int vi = 1; vi < num_vertices; ++vi) {
|
||||
nassertv(!index.is_at_end());
|
||||
if (num_vertices == 0) {
|
||||
// Or if we don't have any vertices, the minmax is also trivial.
|
||||
cdata->_min_vertex = 0;
|
||||
cdata->_max_vertex = 0;
|
||||
cdata->_mins.clear();
|
||||
cdata->_maxs.clear();
|
||||
|
||||
} else if (get_num_vertices_per_primitive() == 0) {
|
||||
// This is a complex primitive type like a triangle strip; compute
|
||||
// the minmax of each primitive (as well as the overall minmax).
|
||||
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
|
||||
|
||||
cdata->_mins = make_index_data();
|
||||
cdata->_maxs = make_index_data();
|
||||
|
||||
GeomVertexWriter mins(cdata->_mins.get_write_pointer(), 0);
|
||||
GeomVertexWriter maxs(cdata->_maxs.get_write_pointer(), 0);
|
||||
|
||||
int pi = 0;
|
||||
|
||||
unsigned int vertex = index.get_data1i();
|
||||
cdata->_min_vertex = min(cdata->_min_vertex, vertex);
|
||||
cdata->_max_vertex = max(cdata->_max_vertex, vertex);
|
||||
cdata->_min_vertex = vertex;
|
||||
cdata->_max_vertex = vertex;
|
||||
unsigned int min_prim = vertex;
|
||||
unsigned int max_prim = vertex;
|
||||
|
||||
for (int vi = 1; vi < num_vertices; ++vi) {
|
||||
nassertv(!index.is_at_end());
|
||||
unsigned int vertex = index.get_data1i();
|
||||
cdata->_min_vertex = min(cdata->_min_vertex, vertex);
|
||||
cdata->_max_vertex = max(cdata->_max_vertex, vertex);
|
||||
|
||||
if (vi == cdata->_ends[pi]) {
|
||||
mins.add_data1i(min_prim);
|
||||
maxs.add_data1i(max_prim);
|
||||
min_prim = vertex;
|
||||
max_prim = vertex;
|
||||
++pi;
|
||||
|
||||
} else {
|
||||
min_prim = min(min_prim, vertex);
|
||||
max_prim = max(max_prim, vertex);
|
||||
nassertv(pi < cdata->_ends.size());
|
||||
if (vi == cdata->_ends[pi]) {
|
||||
mins.add_data1i(min_prim);
|
||||
maxs.add_data1i(max_prim);
|
||||
min_prim = vertex;
|
||||
max_prim = vertex;
|
||||
++pi;
|
||||
|
||||
} else {
|
||||
min_prim = min(min_prim, vertex);
|
||||
max_prim = max(max_prim, vertex);
|
||||
}
|
||||
}
|
||||
mins.add_data1i(min_prim);
|
||||
maxs.add_data1i(max_prim);
|
||||
nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size());
|
||||
|
||||
} else {
|
||||
// This is a simple primitive type like a triangle; just compute
|
||||
// the overall minmax.
|
||||
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
|
||||
|
||||
cdata->_mins.clear();
|
||||
cdata->_maxs.clear();
|
||||
|
||||
unsigned int vertex = index.get_data1i();
|
||||
cdata->_min_vertex = vertex;
|
||||
cdata->_max_vertex = vertex;
|
||||
|
||||
for (int vi = 1; vi < num_vertices; ++vi) {
|
||||
nassertv(!index.is_at_end());
|
||||
unsigned int vertex = index.get_data1i();
|
||||
cdata->_min_vertex = min(cdata->_min_vertex, vertex);
|
||||
cdata->_max_vertex = max(cdata->_max_vertex, vertex);
|
||||
}
|
||||
}
|
||||
mins.add_data1i(min_prim);
|
||||
maxs.add_data1i(max_prim);
|
||||
nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size());
|
||||
|
||||
} else {
|
||||
// This is a simple primitive type like a triangle; just compute
|
||||
// the overall minmax.
|
||||
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
|
||||
|
||||
cdata->_mins.clear();
|
||||
cdata->_maxs.clear();
|
||||
|
||||
unsigned int vertex = index.get_data1i();
|
||||
cdata->_min_vertex = vertex;
|
||||
cdata->_max_vertex = vertex;
|
||||
|
||||
int num_vertices = get_num_vertices();
|
||||
for (int vi = 1; vi < num_vertices; ++vi) {
|
||||
nassertv(!index.is_at_end());
|
||||
unsigned int vertex = index.get_data1i();
|
||||
cdata->_min_vertex = min(cdata->_min_vertex, vertex);
|
||||
cdata->_max_vertex = max(cdata->_max_vertex, vertex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cdata->_got_minmax = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,9 +20,10 @@
|
|||
// via load_async(), to begin an asynchronous load.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE TextureReloadRequest::
|
||||
TextureReloadRequest(PreparedGraphicsObjects *pgo, Texture *texture,
|
||||
TextureReloadRequest(const string &name,
|
||||
PreparedGraphicsObjects *pgo, Texture *texture,
|
||||
bool allow_compressed) :
|
||||
AsyncTask(texture->get_name()),
|
||||
AsyncTask(name),
|
||||
_pgo(pgo),
|
||||
_texture(texture),
|
||||
_allow_compressed(allow_compressed),
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ public:
|
|||
ALLOC_DELETED_CHAIN(TextureReloadRequest);
|
||||
|
||||
PUBLISHED:
|
||||
INLINE TextureReloadRequest(PreparedGraphicsObjects *pgo, Texture *texture,
|
||||
INLINE TextureReloadRequest(const string &name,
|
||||
PreparedGraphicsObjects *pgo, Texture *texture,
|
||||
bool allow_compressed);
|
||||
|
||||
INLINE PreparedGraphicsObjects *get_prepared_graphics_objects() const;
|
||||
|
|
|
|||
|
|
@ -238,15 +238,16 @@ reset_bound(const NodePath &rel_to) {
|
|||
// thing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RopeNode::
|
||||
compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
PT(BoundingVolume) bounds =
|
||||
do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage,
|
||||
current_thread);
|
||||
|
||||
bdata->_internal_bounds = bounds;
|
||||
bdata->_internal_vertices = 0; // TODO--estimate this better.
|
||||
bdata->_internal_bounds_stale = false;
|
||||
internal_bounds = bounds;
|
||||
internal_vertices = 0; // TODO--estimate this better.
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -142,7 +142,9 @@ PUBLISHED:
|
|||
void reset_bound(const NodePath &rel_to);
|
||||
|
||||
protected:
|
||||
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
|
||||
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -220,15 +220,16 @@ reset_bound(const NodePath &rel_to) {
|
|||
// thing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SheetNode::
|
||||
compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
PT(BoundingVolume) bounds =
|
||||
do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage,
|
||||
current_thread);
|
||||
|
||||
bdata->_internal_bounds = bounds;
|
||||
bdata->_internal_vertices = 0; // TODO--estimate this better.
|
||||
bdata->_internal_bounds_stale = false;
|
||||
internal_bounds = bounds;
|
||||
internal_vertices = 0; // TODO--estimate this better.
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ PUBLISHED:
|
|||
void reset_bound(const NodePath &rel_to);
|
||||
|
||||
protected:
|
||||
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
|
||||
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -366,10 +366,13 @@ safe_to_combine() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void GeomNode::
|
||||
r_prepare_scene(const RenderState *state,
|
||||
PreparedGraphicsObjects *prepared_objects) {
|
||||
int num_geoms = get_num_geoms();
|
||||
for (int i = 0; i < num_geoms; i++) {
|
||||
CPT(RenderState) geom_state = state->compose(get_geom_state(i));
|
||||
PreparedGraphicsObjects *prepared_objects,
|
||||
Thread *current_thread) {
|
||||
CDReader cdata(_cycler, current_thread);
|
||||
GeomList::const_iterator gi;
|
||||
CPT(GeomList) geoms = cdata->get_geoms();
|
||||
for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
|
||||
CPT(RenderState) geom_state = state->compose((*gi)._state);
|
||||
const RenderAttrib *attrib =
|
||||
geom_state->get_attrib(TextureAttrib::get_class_type());
|
||||
if (attrib != (const RenderAttrib *)NULL) {
|
||||
|
|
@ -382,7 +385,7 @@ r_prepare_scene(const RenderState *state,
|
|||
}
|
||||
}
|
||||
|
||||
PandaNode::r_prepare_scene(state, prepared_objects);
|
||||
PandaNode::r_prepare_scene(state, prepared_objects, current_thread);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -842,24 +845,31 @@ do_premunge(GraphicsStateGuardianBase *gsg,
|
|||
// something internally.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomNode::
|
||||
compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
int num_vertices = 0;
|
||||
|
||||
CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
|
||||
|
||||
pvector<const BoundingVolume *> child_volumes;
|
||||
pvector<CPT(BoundingVolume) > child_volumes_ref;
|
||||
bool all_box = true;
|
||||
|
||||
GeomList::const_iterator gi;
|
||||
CPT(GeomList) geoms = cdata->get_geoms();
|
||||
child_volumes.reserve(geoms->size());
|
||||
child_volumes_ref.reserve(geoms->size());
|
||||
|
||||
for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
|
||||
const GeomEntry &entry = (*gi);
|
||||
CPT(Geom) geom = entry._geom.get_read_pointer();
|
||||
const BoundingVolume *volume = geom->get_bounds();
|
||||
CPT(BoundingVolume) volume = geom->get_bounds();
|
||||
|
||||
if (!volume->is_empty()) {
|
||||
child_volumes.push_back(volume);
|
||||
child_volumes_ref.push_back(volume);
|
||||
if (!volume->is_exact_type(BoundingBox::get_class_type())) {
|
||||
all_box = false;
|
||||
}
|
||||
|
|
@ -885,9 +895,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
|||
((BoundingVolume *)gbv)->around(child_begin, child_end);
|
||||
}
|
||||
|
||||
bdata->_internal_bounds = gbv;
|
||||
bdata->_internal_vertices = num_vertices;
|
||||
bdata->_internal_bounds_stale = false;
|
||||
internal_bounds = gbv;
|
||||
internal_vertices = num_vertices;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ public:
|
|||
virtual bool safe_to_combine() const;
|
||||
|
||||
virtual void r_prepare_scene(const RenderState *state,
|
||||
PreparedGraphicsObjects *prepared_objects);
|
||||
PreparedGraphicsObjects *prepared_objects,
|
||||
Thread *current_thread);
|
||||
|
||||
PUBLISHED:
|
||||
INLINE void set_preserved(bool value);
|
||||
|
|
@ -97,7 +98,9 @@ public:
|
|||
GeomTransformer &transformer);
|
||||
|
||||
protected:
|
||||
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
|
||||
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const;
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "loaderFileTypeRegistry.h"
|
||||
#include "config_pgraph.h"
|
||||
#include "modelPool.h"
|
||||
#include "modelLoadRequest.h"
|
||||
#include "config_express.h"
|
||||
#include "config_util.h"
|
||||
#include "virtualFileSystem.h"
|
||||
|
|
@ -63,6 +64,18 @@ Loader(const string &name) :
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Loader::make_async_request
|
||||
// Access: Published
|
||||
// Description: Returns a new AsyncTask object suitable for adding to
|
||||
// load_async() to start an asynchronous model load.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(AsyncTask) Loader::
|
||||
make_async_request(const Filename &filename, const LoaderOptions &options) {
|
||||
return new ModelLoadRequest(string("model:")+filename.get_basename(),
|
||||
filename, options, this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Loader::load_bam_stream
|
||||
// Access: Published
|
||||
|
|
@ -367,6 +380,6 @@ void Loader::
|
|||
make_global_ptr() {
|
||||
nassertv(_global_ptr == (Loader *)NULL);
|
||||
|
||||
_global_ptr = new Loader("taskMgr");
|
||||
_global_ptr = new Loader("loader");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ PUBLISHED:
|
|||
BLOCKING INLINE PT(PandaNode) load_sync(const Filename &filename,
|
||||
const LoaderOptions &options = LoaderOptions()) const;
|
||||
|
||||
PT(AsyncTask) make_async_request(const Filename &filename,
|
||||
const LoaderOptions &options = LoaderOptions());
|
||||
INLINE void load_async(AsyncTask *request);
|
||||
|
||||
BLOCKING PT(PandaNode) load_bam_stream(istream &in);
|
||||
|
|
|
|||
|
|
@ -476,7 +476,9 @@ show_switches_cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|||
// something internally.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void LODNode::
|
||||
compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
// First, get ourselves a fresh, empty bounding volume.
|
||||
PT(BoundingVolume) bound = new BoundingSphere;
|
||||
|
|
@ -508,9 +510,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
|||
bound->around(child_begin, child_end);
|
||||
}
|
||||
|
||||
bdata->_internal_bounds = bound;
|
||||
bdata->_internal_vertices = 0;
|
||||
bdata->_internal_bounds_stale = false;
|
||||
internal_bounds = bound;
|
||||
internal_vertices = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -83,7 +83,9 @@ protected:
|
|||
int compute_child(CullTraverser *trav, CullTraverserData &data);
|
||||
|
||||
bool show_switches_cull_callback(CullTraverser *trav, CullTraverserData &data);
|
||||
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
|
||||
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const;
|
||||
|
||||
INLINE void consider_verify_lods(CullTraverser *trav, CullTraverserData &data);
|
||||
|
|
|
|||
|
|
@ -20,9 +20,10 @@
|
|||
// via load_async(), to begin an asynchronous load.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ModelLoadRequest::
|
||||
ModelLoadRequest(const Filename &filename, const LoaderOptions &options,
|
||||
ModelLoadRequest(const string &name,
|
||||
const Filename &filename, const LoaderOptions &options,
|
||||
Loader *loader) :
|
||||
AsyncTask(filename.get_basename()),
|
||||
AsyncTask(name),
|
||||
_filename(filename),
|
||||
_options(options),
|
||||
_loader(loader),
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ public:
|
|||
ALLOC_DELETED_CHAIN(ModelLoadRequest);
|
||||
|
||||
PUBLISHED:
|
||||
INLINE ModelLoadRequest(const Filename &filename,
|
||||
INLINE ModelLoadRequest(const string &name,
|
||||
const Filename &filename,
|
||||
const LoaderOptions &options,
|
||||
Loader *loader);
|
||||
|
||||
|
|
|
|||
|
|
@ -708,7 +708,7 @@ INLINE void PandaNode::
|
|||
mark_internal_bounds_stale(int pipeline_stage, Thread *current_thread) {
|
||||
{
|
||||
CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
|
||||
cdata->_internal_bounds_stale = true;
|
||||
++cdata->_internal_bounds_mark;
|
||||
}
|
||||
mark_bounds_stale(pipeline_stage, current_thread);
|
||||
}
|
||||
|
|
@ -942,9 +942,9 @@ get_parent() const {
|
|||
INLINE PandaNode::BoundsData::
|
||||
BoundsData() :
|
||||
_internal_bounds(NULL),
|
||||
_internal_vertices(0),
|
||||
_internal_bounds_stale(true)
|
||||
_internal_vertices(0)
|
||||
{
|
||||
++_internal_bounds_mark;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -956,10 +956,24 @@ INLINE PandaNode::BoundsData::
|
|||
BoundsData(const PandaNode::BoundsData ©) :
|
||||
_internal_bounds(copy._internal_bounds),
|
||||
_internal_vertices(copy._internal_vertices),
|
||||
_internal_bounds_stale(copy._internal_bounds_stale)
|
||||
_internal_bounds_mark(copy._internal_bounds_mark),
|
||||
_internal_bounds_computed(copy._internal_bounds_computed)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::BoundsData::copy_bounds
|
||||
// Access: Protected
|
||||
// Description: Copies just the BoundsData part of the structure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PandaNode::BoundsData::
|
||||
copy_bounds(const PandaNode::BoundsData ©) {
|
||||
_internal_bounds = copy._internal_bounds;
|
||||
_internal_vertices = copy._internal_vertices;
|
||||
_internal_bounds_mark = copy._internal_bounds_mark;
|
||||
_internal_bounds_computed = copy._internal_bounds_computed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::CData::set_fancy_bit
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -162,7 +162,9 @@ PandaNode(const PandaNode ©) :
|
|||
cdata->_into_collide_mask = copy_cdata->_into_collide_mask;
|
||||
cdata->_user_bounds = copy_cdata->_user_bounds;
|
||||
cdata->_internal_bounds = NULL;
|
||||
cdata->_internal_bounds_stale = true;
|
||||
cdata->_internal_bounds_computed = UpdateSeq::initial();
|
||||
cdata->_internal_bounds_mark = UpdateSeq::initial();
|
||||
++cdata->_internal_bounds_mark;
|
||||
cdata->_final_bounds = copy_cdata->_final_bounds;
|
||||
cdata->_fancy_bits = copy_cdata->_fancy_bits;
|
||||
|
||||
|
|
@ -1772,7 +1774,7 @@ copy_all_properties(PandaNode *other) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
replace_node(PandaNode *other) {
|
||||
nassertv(Thread::get_current_pipeline_stage() == 0);
|
||||
// nassertv(Thread::get_current_pipeline_stage() == 0);
|
||||
|
||||
if (other == this) {
|
||||
// Trivial.
|
||||
|
|
@ -2123,8 +2125,9 @@ get_off_clip_planes(Thread *current_thread) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *net_state) {
|
||||
Thread *current_thread = Thread::get_current_thread();
|
||||
PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects();
|
||||
r_prepare_scene(net_state, prepared_objects);
|
||||
r_prepare_scene(net_state, prepared_objects, current_thread);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -2421,18 +2424,42 @@ as_light() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
CPT(BoundingVolume) PandaNode::
|
||||
get_internal_bounds(int pipeline_stage, Thread *current_thread) const {
|
||||
CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
|
||||
if (cdata->_user_bounds != (BoundingVolume *)NULL) {
|
||||
return cdata->_user_bounds;
|
||||
}
|
||||
while (true) {
|
||||
UpdateSeq mark;
|
||||
{
|
||||
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
|
||||
if (cdata->_user_bounds != (BoundingVolume *)NULL) {
|
||||
return cdata->_user_bounds;
|
||||
}
|
||||
|
||||
if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) {
|
||||
return cdata->_internal_bounds;
|
||||
}
|
||||
|
||||
if (cdata->_internal_bounds_stale) {
|
||||
CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage, cdata);
|
||||
compute_internal_bounds(cdataw, pipeline_stage, current_thread);
|
||||
nassertr(!cdataw->_internal_bounds.is_null(), NULL);
|
||||
return cdataw->_internal_bounds;
|
||||
mark = cdata->_internal_bounds_mark;
|
||||
}
|
||||
|
||||
// First, call compute_internal_bounds without acquiring the lock.
|
||||
// This avoids a deadlock condition.
|
||||
CPT(BoundingVolume) internal_bounds;
|
||||
int internal_vertices;
|
||||
compute_internal_bounds(internal_bounds, internal_vertices,
|
||||
pipeline_stage, current_thread);
|
||||
nassertr(!internal_bounds.is_null(), NULL);
|
||||
|
||||
// Now, acquire the lock, and apply the above-computed bounds.
|
||||
CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage);
|
||||
if (cdataw->_internal_bounds_mark == mark) {
|
||||
cdataw->_internal_bounds_computed = mark;
|
||||
cdataw->_internal_bounds = internal_bounds;
|
||||
cdataw->_internal_vertices = internal_vertices;
|
||||
return cdataw->_internal_bounds;
|
||||
}
|
||||
|
||||
// Dang, someone in another thread incremented
|
||||
// _internal_bounds_mark while we weren't holding the lock. That
|
||||
// means we need to go back and do it again.
|
||||
}
|
||||
return cdata->_internal_bounds;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -2447,14 +2474,38 @@ get_internal_bounds(int pipeline_stage, Thread *current_thread) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
int PandaNode::
|
||||
get_internal_vertices(int pipeline_stage, Thread *current_thread) const {
|
||||
CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
|
||||
if (cdata->_internal_bounds_stale) {
|
||||
CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage, cdata);
|
||||
compute_internal_bounds(cdataw, pipeline_stage, current_thread);
|
||||
nassertr(!cdataw->_internal_bounds.is_null(), 0);
|
||||
return cdataw->_internal_vertices;
|
||||
while (true) {
|
||||
UpdateSeq mark;
|
||||
{
|
||||
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
|
||||
if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) {
|
||||
return cdata->_internal_vertices;
|
||||
}
|
||||
|
||||
mark = cdata->_internal_bounds_mark;
|
||||
}
|
||||
|
||||
// First, call compute_internal_bounds without acquiring the lock.
|
||||
// This avoids a deadlock condition.
|
||||
CPT(BoundingVolume) internal_bounds;
|
||||
int internal_vertices;
|
||||
compute_internal_bounds(internal_bounds, internal_vertices,
|
||||
pipeline_stage, current_thread);
|
||||
nassertr(!internal_bounds.is_null(), NULL);
|
||||
|
||||
// Now, acquire the lock, and apply the above-computed bounds.
|
||||
CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage);
|
||||
if (cdataw->_internal_bounds_mark == mark) {
|
||||
cdataw->_internal_bounds_computed = mark;
|
||||
cdataw->_internal_bounds = internal_bounds;
|
||||
cdataw->_internal_vertices = internal_vertices;
|
||||
return cdataw->_internal_vertices;
|
||||
}
|
||||
|
||||
// Dang, someone in another thread incremented
|
||||
// _internal_bounds_mark while we weren't holding the lock. That
|
||||
// means we need to go back and do it again.
|
||||
}
|
||||
return cdata->_internal_vertices;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -2472,7 +2523,7 @@ set_internal_bounds(const BoundingVolume *volume) {
|
|||
OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
|
||||
CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
|
||||
cdataw->_internal_bounds = volume;
|
||||
cdataw->_internal_bounds_stale = false;
|
||||
cdataw->_internal_bounds_computed = cdataw->_internal_bounds_mark;
|
||||
}
|
||||
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
|
||||
mark_bounds_stale(current_thread);
|
||||
|
|
@ -2539,11 +2590,12 @@ force_bounds_stale(int pipeline_stage, Thread *current_thread) {
|
|||
// something internally.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
bdata->_internal_bounds = new BoundingSphere;
|
||||
bdata->_internal_vertices = 0;
|
||||
bdata->_internal_bounds_stale = false;
|
||||
internal_bounds = new BoundingSphere;
|
||||
internal_vertices = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -2693,12 +2745,15 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
r_prepare_scene(const RenderState *state,
|
||||
PreparedGraphicsObjects *prepared_objects) {
|
||||
int num_children = get_num_children();
|
||||
for (int i = 0; i < num_children; i++) {
|
||||
PandaNode *child = get_child(i);
|
||||
PreparedGraphicsObjects *prepared_objects,
|
||||
Thread *current_thread) {
|
||||
Children children = get_children(current_thread);
|
||||
// We must call get_num_children() each time through the loop, in
|
||||
// case we're running SIMPLE_THREADS and we get interrupted.
|
||||
for (int i = 0; i < children.get_num_children(); i++) {
|
||||
PandaNode *child = children.get_child(i);
|
||||
CPT(RenderState) child_state = state->compose(child->get_state());
|
||||
child->r_prepare_scene(child_state, prepared_objects);
|
||||
child->r_prepare_scene(child_state, prepared_objects, current_thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3546,6 +3601,8 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) {
|
|||
// Also get the list of the node's children.
|
||||
Children children(cdata);
|
||||
|
||||
int num_vertices = cdata->_internal_vertices;
|
||||
|
||||
// Now that we've got all the data we need from the node, we can
|
||||
// release the lock.
|
||||
_cycler.release_read_stage(pipeline_stage, cdata.take_pointer());
|
||||
|
|
@ -3579,8 +3636,6 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) {
|
|||
}
|
||||
}
|
||||
|
||||
int num_vertices = cdata->_internal_vertices;
|
||||
|
||||
// Now expand those contents to include all of our children.
|
||||
|
||||
for (int i = 0; i < num_children; ++i) {
|
||||
|
|
@ -3754,6 +3809,7 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) {
|
|||
<< "} " << *this << "::update_bounds();\n";
|
||||
}
|
||||
|
||||
nassertr(cdataw->_last_update == cdataw->_next_update, cdataw)
|
||||
return cdataw;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -301,7 +301,9 @@ protected:
|
|||
void force_bounds_stale(int pipeline_stage, Thread *current_thread);
|
||||
INLINE void mark_internal_bounds_stale(int pipeline_stage, Thread *current_thread);
|
||||
|
||||
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
|
||||
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const;
|
||||
virtual void parents_changed();
|
||||
virtual void children_changed();
|
||||
|
|
@ -319,7 +321,8 @@ protected:
|
|||
|
||||
public:
|
||||
virtual void r_prepare_scene(const RenderState *state,
|
||||
PreparedGraphicsObjects *prepared_objects);
|
||||
PreparedGraphicsObjects *prepared_objects,
|
||||
Thread *current_thread);
|
||||
|
||||
protected:
|
||||
// This is a base class of CData, defined below. It contains just
|
||||
|
|
@ -329,6 +332,7 @@ protected:
|
|||
protected:
|
||||
INLINE BoundsData();
|
||||
INLINE BoundsData(const BoundsData ©);
|
||||
INLINE void copy_bounds(const BoundsData ©);
|
||||
|
||||
public:
|
||||
// This is the "internal" bounding volume, which is normally
|
||||
|
|
@ -337,7 +341,8 @@ protected:
|
|||
// overriding compute_internal_bounds().
|
||||
CPT(BoundingVolume) _internal_bounds;
|
||||
int _internal_vertices;
|
||||
bool _internal_bounds_stale;
|
||||
UpdateSeq _internal_bounds_mark; // incremented on mark_stale
|
||||
UpdateSeq _internal_bounds_computed; // set to above when computing
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -201,12 +201,13 @@ is_renderable() const {
|
|||
// something internally.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PlaneNode::
|
||||
compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
|
||||
bdata->_internal_bounds = new BoundingPlane(cdata->_plane);
|
||||
bdata->_internal_vertices = 0;
|
||||
bdata->_internal_bounds_stale = false;
|
||||
internal_bounds = new BoundingPlane(cdata->_plane);
|
||||
internal_vertices = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -72,7 +72,9 @@ public:
|
|||
INLINE static UpdateSeq get_sort_seq();
|
||||
|
||||
protected:
|
||||
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
|
||||
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const;
|
||||
PT(Geom) get_viz(CullTraverser *trav, CullTraverserData &data);
|
||||
|
||||
|
|
|
|||
|
|
@ -379,7 +379,9 @@ draw() const {
|
|||
// thing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PortalNode::
|
||||
compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
// First, get ourselves a fresh, empty bounding volume.
|
||||
PT(BoundingVolume) bound = new BoundingSphere;
|
||||
|
|
@ -394,9 +396,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
|||
// Now actually compute the bounding volume by putting it around all
|
||||
gbv->around(vertices_begin, vertices_end);
|
||||
|
||||
bdata->_internal_bounds = bound;
|
||||
bdata->_internal_vertices = 0;
|
||||
bdata->_internal_bounds_stale = false;
|
||||
internal_bounds = bound;
|
||||
internal_vertices = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -93,7 +93,9 @@ PUBLISHED:
|
|||
// void draw () const;
|
||||
|
||||
protected:
|
||||
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
|
||||
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -93,7 +93,8 @@ get_click_prefix() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGButton::
|
||||
get_click_event(const ButtonHandle &button) const {
|
||||
return "click-" + button.get_name() + "-" + get_id();
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_click_prefix() + button.get_name() + "-" + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -104,5 +105,6 @@ get_click_event(const ButtonHandle &button) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGButton::
|
||||
is_button_down() {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _button_down;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ PGButton(const PGButton ©) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PGButton::
|
||||
make_copy() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return new PGButton(*this);
|
||||
}
|
||||
|
||||
|
|
@ -80,6 +81,7 @@ make_copy() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGButton::
|
||||
enter_region(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (get_active()) {
|
||||
set_state(_button_down ? S_depressed : S_rollover);
|
||||
}
|
||||
|
|
@ -94,6 +96,7 @@ enter_region(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGButton::
|
||||
exit_region(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (get_active()) {
|
||||
set_state(S_ready);
|
||||
}
|
||||
|
|
@ -109,6 +112,7 @@ exit_region(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGButton::
|
||||
press(const MouseWatcherParameter ¶m, bool background) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (has_click_button(param.get_button())) {
|
||||
if (get_active()) {
|
||||
_button_down = true;
|
||||
|
|
@ -127,6 +131,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGButton::
|
||||
release(const MouseWatcherParameter ¶m, bool background) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (has_click_button(param.get_button())) {
|
||||
_button_down = false;
|
||||
if (get_active()) {
|
||||
|
|
@ -149,6 +154,7 @@ release(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGButton::
|
||||
click(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_click_event(param.get_button());
|
||||
play_sound(event);
|
||||
|
|
@ -170,6 +176,7 @@ click(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGButton::
|
||||
setup(const string &label, float bevel) {
|
||||
ReMutexHolder holder(_lock);
|
||||
clear_state_def(S_ready);
|
||||
clear_state_def(S_depressed);
|
||||
clear_state_def(S_rollover);
|
||||
|
|
@ -226,6 +233,7 @@ setup(const string &label, float bevel) {
|
|||
void PGButton::
|
||||
setup(const NodePath &ready, const NodePath &depressed,
|
||||
const NodePath &rollover, const NodePath &inactive) {
|
||||
ReMutexHolder holder(_lock);
|
||||
clear_state_def(S_ready);
|
||||
clear_state_def(S_depressed);
|
||||
clear_state_def(S_rollover);
|
||||
|
|
@ -246,6 +254,7 @@ setup(const NodePath &ready, const NodePath &depressed,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGButton::
|
||||
set_active(bool active) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (active != get_active()) {
|
||||
PGItem::set_active(active);
|
||||
set_state(active ? S_ready : S_inactive);
|
||||
|
|
@ -262,6 +271,7 @@ set_active(bool active) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGButton::
|
||||
add_click_button(const ButtonHandle &button) {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _click_buttons.insert(button).second;
|
||||
}
|
||||
|
||||
|
|
@ -276,6 +286,7 @@ add_click_button(const ButtonHandle &button) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGButton::
|
||||
remove_click_button(const ButtonHandle &button) {
|
||||
ReMutexHolder holder(_lock);
|
||||
return (_click_buttons.erase(button) != 0);
|
||||
}
|
||||
|
||||
|
|
@ -288,5 +299,6 @@ remove_click_button(const ButtonHandle &button) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGButton::
|
||||
has_click_button(const ButtonHandle &button) {
|
||||
ReMutexHolder holder(_lock);
|
||||
return (_click_buttons.count(button) != 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGEntry::
|
||||
set_text(const string &text) {
|
||||
ReMutexHolder holder(_lock);
|
||||
TextNode *text_node = get_text_def(S_focus);
|
||||
nassertr(text_node != (TextNode *)NULL, false);
|
||||
return set_wtext(text_node->decode_text(text));
|
||||
|
|
@ -44,6 +45,7 @@ set_text(const string &text) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGEntry::
|
||||
get_plain_text() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
TextNode *text_node = get_text_def(S_focus);
|
||||
nassertr(text_node != (TextNode *)NULL, string());
|
||||
return text_node->encode_wtext(get_plain_wtext());
|
||||
|
|
@ -59,6 +61,7 @@ get_plain_text() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGEntry::
|
||||
get_text() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
TextNode *text_node = get_text_def(S_focus);
|
||||
nassertr(text_node != (TextNode *)NULL, string());
|
||||
return text_node->encode_wtext(get_wtext());
|
||||
|
|
@ -79,6 +82,7 @@ get_text() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int PGEntry::
|
||||
get_num_characters() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _text.get_num_characters();
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +95,7 @@ get_num_characters() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE wchar_t PGEntry::
|
||||
get_character(int n) const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _text.get_character(n);
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +109,7 @@ get_character(int n) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const TextGraphic *PGEntry::
|
||||
get_graphic(int n) const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _text.get_graphic(n);
|
||||
}
|
||||
|
||||
|
|
@ -116,6 +122,7 @@ get_graphic(int n) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const TextProperties &PGEntry::
|
||||
get_properties(int n) const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _text.get_properties(n);
|
||||
}
|
||||
|
||||
|
|
@ -129,6 +136,7 @@ get_properties(int n) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
set_cursor_position(int position) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_cursor_position != position) {
|
||||
_cursor_position = position;
|
||||
_cursor_stale = true;
|
||||
|
|
@ -143,6 +151,7 @@ set_cursor_position(int position) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int PGEntry::
|
||||
get_cursor_position() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _cursor_position;
|
||||
}
|
||||
|
||||
|
|
@ -158,6 +167,7 @@ get_cursor_position() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
set_max_chars(int max_chars) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_max_chars = max_chars;
|
||||
}
|
||||
|
||||
|
|
@ -170,6 +180,7 @@ set_max_chars(int max_chars) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int PGEntry::
|
||||
get_max_chars() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _max_chars;
|
||||
}
|
||||
|
||||
|
|
@ -190,6 +201,7 @@ get_max_chars() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
set_max_width(float max_width) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_max_width = max_width;
|
||||
_text_geom_stale = true;
|
||||
}
|
||||
|
|
@ -203,6 +215,7 @@ set_max_width(float max_width) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGEntry::
|
||||
get_max_width() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _max_width;
|
||||
}
|
||||
|
||||
|
|
@ -215,6 +228,7 @@ get_max_width() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
set_num_lines(int num_lines) {
|
||||
ReMutexHolder holder(_lock);
|
||||
nassertv(num_lines >= 1);
|
||||
_num_lines = num_lines;
|
||||
_text_geom_stale = true;
|
||||
|
|
@ -228,6 +242,7 @@ set_num_lines(int num_lines) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int PGEntry::
|
||||
get_num_lines() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _num_lines;
|
||||
}
|
||||
|
||||
|
|
@ -242,6 +257,7 @@ get_num_lines() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
set_blink_rate(float blink_rate) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_blink_rate = blink_rate;
|
||||
}
|
||||
|
||||
|
|
@ -253,6 +269,7 @@ set_blink_rate(float blink_rate) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGEntry::
|
||||
get_blink_rate() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _blink_rate;
|
||||
}
|
||||
|
||||
|
|
@ -265,6 +282,7 @@ get_blink_rate() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const NodePath &PGEntry::
|
||||
get_cursor_def() {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _cursor_def;
|
||||
}
|
||||
|
||||
|
|
@ -276,6 +294,7 @@ get_cursor_def() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
clear_cursor_def() {
|
||||
ReMutexHolder holder(_lock);
|
||||
_cursor_def.remove_node();
|
||||
_cursor_def = _cursor_scale.attach_new_node("cursor");
|
||||
}
|
||||
|
|
@ -289,6 +308,7 @@ clear_cursor_def() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
set_cursor_keys_active(bool flag) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_cursor_keys_active = flag;
|
||||
}
|
||||
|
||||
|
|
@ -301,6 +321,7 @@ set_cursor_keys_active(bool flag) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGEntry::
|
||||
get_cursor_keys_active() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _cursor_keys_active;
|
||||
}
|
||||
|
||||
|
|
@ -320,6 +341,7 @@ get_cursor_keys_active() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
set_obscure_mode(bool flag) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_obscure_mode != flag) {
|
||||
_obscure_mode = flag;
|
||||
_text_geom_stale = true;
|
||||
|
|
@ -334,6 +356,7 @@ set_obscure_mode(bool flag) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGEntry::
|
||||
get_obscure_mode() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _obscure_mode;
|
||||
}
|
||||
|
||||
|
|
@ -356,6 +379,7 @@ get_obscure_mode() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
set_candidate_active(const string &candidate_active) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_candidate_active = candidate_active;
|
||||
}
|
||||
|
||||
|
|
@ -366,6 +390,7 @@ set_candidate_active(const string &candidate_active) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &PGEntry::
|
||||
get_candidate_active() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _candidate_active;
|
||||
}
|
||||
|
||||
|
|
@ -388,6 +413,7 @@ get_candidate_active() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
set_candidate_inactive(const string &candidate_inactive) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_candidate_inactive = candidate_inactive;
|
||||
}
|
||||
|
||||
|
|
@ -398,6 +424,7 @@ set_candidate_inactive(const string &candidate_inactive) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &PGEntry::
|
||||
get_candidate_inactive() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _candidate_inactive;
|
||||
}
|
||||
|
||||
|
|
@ -469,7 +496,7 @@ get_erase_prefix() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGEntry::
|
||||
get_accept_event(const ButtonHandle &button) const {
|
||||
return "accept-" + button.get_name() + "-" + get_id();
|
||||
return get_accept_prefix() + button.get_name() + "-" + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -480,7 +507,7 @@ get_accept_event(const ButtonHandle &button) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGEntry::
|
||||
get_accept_failed_event(const ButtonHandle &button) const {
|
||||
return "acceptfailed-" + button.get_name() + "-" + get_id();
|
||||
return get_accept_failed_prefix() + button.get_name() + "-" + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -493,7 +520,7 @@ get_accept_failed_event(const ButtonHandle &button) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGEntry::
|
||||
get_overflow_event() const {
|
||||
return "overflow-" + get_id();
|
||||
return get_overflow_prefix() + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -504,7 +531,7 @@ get_overflow_event() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGEntry::
|
||||
get_type_event() const {
|
||||
return "type-" + get_id();
|
||||
return get_type_prefix() + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -515,7 +542,7 @@ get_type_event() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGEntry::
|
||||
get_erase_event() const {
|
||||
return "erase-" + get_id();
|
||||
return get_erase_prefix() + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -530,6 +557,7 @@ get_erase_event() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGEntry::
|
||||
set_wtext(const wstring &wtext) {
|
||||
ReMutexHolder holder(_lock);
|
||||
bool ret = _text.set_wtext(wtext);
|
||||
if (_obscure_mode) {
|
||||
ret = _obscure_text.set_wtext(wstring(_text.get_num_characters(), '*'));
|
||||
|
|
@ -547,6 +575,7 @@ set_wtext(const wstring &wtext) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE wstring PGEntry::
|
||||
get_plain_wtext() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _text.get_plain_wtext();
|
||||
}
|
||||
|
||||
|
|
@ -558,6 +587,7 @@ get_plain_wtext() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE wstring PGEntry::
|
||||
get_wtext() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _text.get_wtext();
|
||||
}
|
||||
|
||||
|
|
@ -569,5 +599,6 @@ get_wtext() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
set_accept_enabled(bool enabled) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_accept_enabled = enabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ PGEntry(const PGEntry ©) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PGEntry::
|
||||
make_copy() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return new PGEntry(*this);
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +137,7 @@ make_copy() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
xform(const LMatrix4f &mat) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGItem::xform(mat);
|
||||
_text_render_root.set_mat(_text_render_root.get_mat() * mat);
|
||||
}
|
||||
|
|
@ -167,6 +169,7 @@ xform(const LMatrix4f &mat) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGEntry::
|
||||
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGItem::cull_callback(trav, data);
|
||||
update_text();
|
||||
update_cursor();
|
||||
|
|
@ -188,6 +191,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
press(const MouseWatcherParameter ¶m, bool background) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (get_active()) {
|
||||
if (param.has_button()) {
|
||||
// Make sure _text is initialized properly.
|
||||
|
|
@ -296,6 +300,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
keystroke(const MouseWatcherParameter ¶m, bool background) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (get_active()) {
|
||||
if (param.has_keycode()) {
|
||||
// Make sure _text is initialized properly.
|
||||
|
|
@ -402,6 +407,7 @@ keystroke(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
candidate(const MouseWatcherParameter ¶m, bool background) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (get_active()) {
|
||||
if (param.has_candidate()) {
|
||||
// Save the candidate string so it can be displayed.
|
||||
|
|
@ -426,6 +432,7 @@ candidate(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
accept(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_accept_event(param.get_button());
|
||||
play_sound(event);
|
||||
|
|
@ -441,6 +448,7 @@ accept(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
accept_failed(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_accept_failed_event(param.get_button());
|
||||
play_sound(event);
|
||||
|
|
@ -458,6 +466,7 @@ accept_failed(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
overflow(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_overflow_event();
|
||||
play_sound(event);
|
||||
|
|
@ -472,6 +481,7 @@ overflow(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
type(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_type_event();
|
||||
play_sound(event);
|
||||
|
|
@ -486,6 +496,7 @@ type(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
erase(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_erase_event();
|
||||
play_sound(event);
|
||||
|
|
@ -503,6 +514,7 @@ erase(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
setup(float width, int num_lines) {
|
||||
ReMutexHolder holder(_lock);
|
||||
setup_minimal(width, num_lines);
|
||||
|
||||
TextNode *text_node = get_text_def(S_focus);
|
||||
|
|
@ -570,6 +582,7 @@ setup(float width, int num_lines) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
setup_minimal(float width, int num_lines) {
|
||||
ReMutexHolder holder(_lock);
|
||||
set_text(string());
|
||||
_cursor_position = 0;
|
||||
set_max_chars(0);
|
||||
|
|
@ -608,6 +621,7 @@ setup_minimal(float width, int num_lines) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
set_text_def(int state, TextNode *node) {
|
||||
ReMutexHolder holder(_lock);
|
||||
nassertv(state >= 0 && state < 1000); // Sanity check.
|
||||
if (node == (TextNode *)NULL && state >= (int)_text_defs.size()) {
|
||||
// If we're setting it to NULL, we don't need to slot a new one.
|
||||
|
|
@ -627,6 +641,7 @@ set_text_def(int state, TextNode *node) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
TextNode *PGEntry::
|
||||
get_text_def(int state) const {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (state < 0 || state >= (int)_text_defs.size()) {
|
||||
// If we don't have a definition, use the global one.
|
||||
return get_text_node();
|
||||
|
|
@ -646,6 +661,7 @@ get_text_def(int state) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
set_active(bool active) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGItem::set_active(active);
|
||||
update_state();
|
||||
}
|
||||
|
|
@ -658,6 +674,7 @@ set_active(bool active) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGEntry::
|
||||
set_focus(bool focus) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGItem::set_focus(focus);
|
||||
_blink_start = ClockObject::get_global_clock()->get_frame_time();
|
||||
update_state();
|
||||
|
|
@ -673,6 +690,7 @@ set_focus(bool focus) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGEntry::
|
||||
is_wtext() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
for (int i = 0; i < _text.get_num_characters(); ++i) {
|
||||
wchar_t ch = _text.get_character(i);
|
||||
if ((ch & ~0x7f) != 0) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,17 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::set_name
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGItem::
|
||||
set_name(const string &name) {
|
||||
Namable::set_name(name);
|
||||
_lock.set_name(name);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::get_region
|
||||
// Access: Public
|
||||
|
|
@ -26,6 +37,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGMouseWatcherRegion *PGItem::
|
||||
get_region() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _region;
|
||||
}
|
||||
|
||||
|
|
@ -40,6 +52,7 @@ get_region() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGItem::
|
||||
set_notify(PGItemNotify *notify) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_notify != (PGItemNotify *)NULL) {
|
||||
_notify->remove_item(this);
|
||||
}
|
||||
|
|
@ -57,6 +70,7 @@ set_notify(PGItemNotify *notify) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGItem::
|
||||
has_notify() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return (_notify != (PGItemNotify *)NULL);
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +83,7 @@ has_notify() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGItemNotify *PGItem::
|
||||
get_notify() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _notify;
|
||||
}
|
||||
|
||||
|
|
@ -97,6 +112,7 @@ set_frame(float left, float right, float bottom, float top) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGItem::
|
||||
set_frame(const LVecBase4f &frame) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (!_has_frame || _frame != frame) {
|
||||
_has_frame = true;
|
||||
_frame = frame;
|
||||
|
|
@ -113,6 +129,7 @@ set_frame(const LVecBase4f &frame) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase4f &PGItem::
|
||||
get_frame() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
nassertr(has_frame(), _frame);
|
||||
return _frame;
|
||||
}
|
||||
|
|
@ -125,6 +142,7 @@ get_frame() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGItem::
|
||||
has_frame() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _has_frame;
|
||||
}
|
||||
|
||||
|
|
@ -137,6 +155,7 @@ has_frame() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGItem::
|
||||
clear_frame() {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_has_frame) {
|
||||
_has_frame = false;
|
||||
frame_changed();
|
||||
|
|
@ -154,6 +173,7 @@ clear_frame() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGItem::
|
||||
set_state(int state) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_state = state;
|
||||
}
|
||||
|
||||
|
|
@ -165,6 +185,7 @@ set_state(int state) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int PGItem::
|
||||
get_state() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _state;
|
||||
}
|
||||
|
||||
|
|
@ -176,6 +197,7 @@ get_state() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGItem::
|
||||
get_active() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return (_flags & F_active) != 0;
|
||||
}
|
||||
|
||||
|
|
@ -187,6 +209,7 @@ get_active() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGItem::
|
||||
get_focus() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return (_flags & F_focus) != 0;
|
||||
}
|
||||
|
||||
|
|
@ -198,6 +221,7 @@ get_focus() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGItem::
|
||||
get_background_focus() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return (_flags & F_background_focus) != 0;
|
||||
}
|
||||
|
||||
|
|
@ -210,6 +234,7 @@ get_background_focus() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGItem::
|
||||
set_suppress_flags(int suppress_flags) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_region->set_suppress_flags(suppress_flags);
|
||||
}
|
||||
|
||||
|
|
@ -222,6 +247,7 @@ set_suppress_flags(int suppress_flags) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int PGItem::
|
||||
get_suppress_flags() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _region->get_suppress_flags();
|
||||
}
|
||||
|
||||
|
|
@ -235,6 +261,7 @@ get_suppress_flags() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &PGItem::
|
||||
get_id() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _region->get_name();
|
||||
}
|
||||
|
||||
|
|
@ -253,6 +280,7 @@ get_id() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGItem::
|
||||
set_id(const string &id) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_region->set_name(id);
|
||||
}
|
||||
|
||||
|
|
@ -395,6 +423,7 @@ get_keystroke_prefix() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGItem::
|
||||
get_enter_event() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_enter_prefix() + get_id();
|
||||
}
|
||||
|
||||
|
|
@ -407,6 +436,7 @@ get_enter_event() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGItem::
|
||||
get_exit_event() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_exit_prefix() + get_id();
|
||||
}
|
||||
|
||||
|
|
@ -421,6 +451,7 @@ get_exit_event() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGItem::
|
||||
get_within_event() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_within_prefix() + get_id();
|
||||
}
|
||||
|
||||
|
|
@ -436,6 +467,7 @@ get_within_event() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGItem::
|
||||
get_without_event() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_without_prefix() + get_id();
|
||||
}
|
||||
|
||||
|
|
@ -447,6 +479,7 @@ get_without_event() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGItem::
|
||||
get_focus_in_event() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_focus_in_prefix() + get_id();
|
||||
}
|
||||
|
||||
|
|
@ -458,6 +491,7 @@ get_focus_in_event() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGItem::
|
||||
get_focus_out_event() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_focus_out_prefix() + get_id();
|
||||
}
|
||||
|
||||
|
|
@ -471,6 +505,7 @@ get_focus_out_event() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGItem::
|
||||
get_press_event(const ButtonHandle &button) const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_press_prefix() + button.get_name() + "-" + get_id();
|
||||
}
|
||||
|
||||
|
|
@ -484,6 +519,7 @@ get_press_event(const ButtonHandle &button) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGItem::
|
||||
get_repeat_event(const ButtonHandle &button) const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_repeat_prefix() + button.get_name() + "-" + get_id();
|
||||
}
|
||||
|
||||
|
|
@ -497,6 +533,7 @@ get_repeat_event(const ButtonHandle &button) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGItem::
|
||||
get_release_event(const ButtonHandle &button) const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_release_prefix() + button.get_name() + "-" + get_id();
|
||||
}
|
||||
|
||||
|
|
@ -508,6 +545,7 @@ get_release_event(const ButtonHandle &button) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGItem::
|
||||
get_keystroke_event() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_keystroke_prefix() + get_id();
|
||||
}
|
||||
|
||||
|
|
@ -543,6 +581,7 @@ get_focus_item() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE LMatrix4f PGItem::
|
||||
get_frame_inv_xform() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _frame_inv_xform;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ is_right(const LVector2f &v1, const LVector2f &v2) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
PGItem::
|
||||
PGItem(const string &name) :
|
||||
PandaNode(name)
|
||||
PandaNode(name),
|
||||
_lock(name)
|
||||
{
|
||||
set_cull_callback();
|
||||
|
||||
|
|
@ -142,6 +143,7 @@ PGItem(const PGItem ©) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PGItem::
|
||||
make_copy() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return new PGItem(*this);
|
||||
}
|
||||
|
||||
|
|
@ -154,6 +156,7 @@ make_copy() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
transform_changed() {
|
||||
ReMutexHolder holder(_lock);
|
||||
PandaNode::transform_changed();
|
||||
if (has_notify()) {
|
||||
get_notify()->item_transform_changed(this);
|
||||
|
|
@ -169,6 +172,7 @@ transform_changed() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
draw_mask_changed() {
|
||||
ReMutexHolder holder(_lock);
|
||||
PandaNode::draw_mask_changed();
|
||||
if (has_notify()) {
|
||||
get_notify()->item_draw_mask_changed(this);
|
||||
|
|
@ -202,6 +206,7 @@ draw_mask_changed() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGItem::
|
||||
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
||||
ReMutexHolder holder(_lock);
|
||||
bool this_node_hidden = data.is_this_node_hidden(trav);
|
||||
if (!this_node_hidden && has_frame() && get_active()) {
|
||||
// The item has a frame, so we want to generate a region for it
|
||||
|
|
@ -296,8 +301,11 @@ is_renderable() const {
|
|||
// thing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
ReMutexHolder holder(_lock, current_thread);
|
||||
int num_vertices = 0;
|
||||
|
||||
// First, get ourselves a fresh, empty bounding volume.
|
||||
|
|
@ -330,9 +338,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
|||
|
||||
bound->around(child_begin, child_end);
|
||||
|
||||
bdata->_internal_bounds = bound;
|
||||
bdata->_internal_vertices = num_vertices;
|
||||
bdata->_internal_bounds_stale = false;
|
||||
internal_bounds = bound;
|
||||
internal_vertices = num_vertices;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -345,18 +352,20 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
r_prepare_scene(const RenderState *state,
|
||||
PreparedGraphicsObjects *prepared_objects) {
|
||||
PreparedGraphicsObjects *prepared_objects,
|
||||
Thread *current_thread) {
|
||||
ReMutexHolder holder(_lock);
|
||||
StateDefs::iterator di;
|
||||
for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
|
||||
NodePath &root = (*di)._root;
|
||||
if (!root.is_empty()) {
|
||||
PandaNode *child = root.node();
|
||||
CPT(RenderState) child_state = state->compose(child->get_state());
|
||||
child->r_prepare_scene(child_state, prepared_objects);
|
||||
child->r_prepare_scene(child_state, prepared_objects, current_thread);
|
||||
}
|
||||
}
|
||||
|
||||
PandaNode::r_prepare_scene(state, prepared_objects);
|
||||
PandaNode::r_prepare_scene(state, prepared_objects, current_thread);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -368,6 +377,7 @@ r_prepare_scene(const RenderState *state,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
xform(const LMatrix4f &mat) {
|
||||
ReMutexHolder holder(_lock);
|
||||
// Transform the frame.
|
||||
LPoint3f ll(_frame[0], 0.0f, _frame[2]);
|
||||
LPoint3f ur(_frame[1], 0.0f, _frame[3]);
|
||||
|
|
@ -407,6 +417,7 @@ bool PGItem::
|
|||
activate_region(const LMatrix4f &transform, int sort,
|
||||
const ClipPlaneAttrib *cpa,
|
||||
const ScissorAttrib *sa) {
|
||||
ReMutexHolder holder(_lock);
|
||||
// Transform all four vertices, and get the new bounding box. This
|
||||
// way the region works (mostly) even if has been rotated.
|
||||
LPoint3f ll(_frame[0], 0.0f, _frame[2]);
|
||||
|
|
@ -503,6 +514,7 @@ activate_region(const LMatrix4f &transform, int sort,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
enter_region(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (pgui_cat.is_debug()) {
|
||||
pgui_cat.debug()
|
||||
<< *this << "::enter_region(" << param << ")\n";
|
||||
|
|
@ -529,6 +541,7 @@ enter_region(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
exit_region(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (pgui_cat.is_debug()) {
|
||||
pgui_cat.debug()
|
||||
<< *this << "::exit_region(" << param << ")\n";
|
||||
|
|
@ -558,6 +571,7 @@ exit_region(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
within_region(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (pgui_cat.is_debug()) {
|
||||
pgui_cat.debug()
|
||||
<< *this << "::within_region(" << param << ")\n";
|
||||
|
|
@ -582,6 +596,7 @@ within_region(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
without_region(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (pgui_cat.is_debug()) {
|
||||
pgui_cat.debug()
|
||||
<< *this << "::without_region(" << param << ")\n";
|
||||
|
|
@ -605,6 +620,7 @@ without_region(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
focus_in() {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (pgui_cat.is_debug()) {
|
||||
pgui_cat.debug()
|
||||
<< *this << "::focus_in()\n";
|
||||
|
|
@ -627,6 +643,7 @@ focus_in() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
focus_out() {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (pgui_cat.is_debug()) {
|
||||
pgui_cat.debug()
|
||||
<< *this << "::focus_out()\n";
|
||||
|
|
@ -650,6 +667,7 @@ focus_out() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
press(const MouseWatcherParameter ¶m, bool background) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (pgui_cat.is_debug()) {
|
||||
pgui_cat.debug()
|
||||
<< *this << "::press(" << param << ", " << background << ")\n";
|
||||
|
|
@ -681,6 +699,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
release(const MouseWatcherParameter ¶m, bool background) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (pgui_cat.is_debug()) {
|
||||
pgui_cat.debug()
|
||||
<< *this << "::release(" << param << ", " << background << ")\n";
|
||||
|
|
@ -706,6 +725,7 @@ release(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
keystroke(const MouseWatcherParameter ¶m, bool background) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (pgui_cat.is_debug()) {
|
||||
pgui_cat.debug()
|
||||
<< *this << "::keystroke(" << param << ", " << background << ")\n";
|
||||
|
|
@ -731,6 +751,7 @@ keystroke(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
candidate(const MouseWatcherParameter ¶m, bool background) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (pgui_cat.is_debug()) {
|
||||
pgui_cat.debug()
|
||||
<< *this << "::candidate(" << param << ", " << background << ")\n";
|
||||
|
|
@ -752,6 +773,7 @@ candidate(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
move(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (pgui_cat.is_debug()) {
|
||||
pgui_cat.debug()
|
||||
<< *this << "::move(" << param << ")\n";
|
||||
|
|
@ -841,6 +863,7 @@ background_candidate(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
set_active(bool active) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (active) {
|
||||
_flags |= F_active;
|
||||
} else {
|
||||
|
|
@ -867,6 +890,7 @@ set_active(bool active) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
set_focus(bool focus) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (focus) {
|
||||
if (!get_active()) {
|
||||
// Cannot set focus on an inactive item.
|
||||
|
|
@ -911,6 +935,7 @@ set_focus(bool focus) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
set_background_focus(bool focus) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (focus != get_background_focus()) {
|
||||
if (focus) {
|
||||
// Activate background focus.
|
||||
|
|
@ -940,6 +965,7 @@ set_background_focus(bool focus) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
int PGItem::
|
||||
get_num_state_defs() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _state_defs.size();
|
||||
}
|
||||
|
||||
|
|
@ -952,6 +978,7 @@ get_num_state_defs() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGItem::
|
||||
has_state_def(int state) const {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (state < 0 || state >= (int)_state_defs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -967,6 +994,7 @@ has_state_def(int state) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
clear_state_def(int state) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (state < 0 || state >= (int)_state_defs.size()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -988,6 +1016,7 @@ clear_state_def(int state) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
NodePath &PGItem::
|
||||
get_state_def(int state) {
|
||||
ReMutexHolder holder(_lock);
|
||||
nassertr(state >= 0 && state < 1000, get_state_def(0)); // Sanity check.
|
||||
slot_state_def(state);
|
||||
|
||||
|
|
@ -1012,6 +1041,7 @@ get_state_def(int state) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
NodePath PGItem::
|
||||
instance_to_state_def(int state, const NodePath &path) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (path.is_empty()) {
|
||||
// If the source is empty, quietly do nothing.
|
||||
return NodePath();
|
||||
|
|
@ -1030,6 +1060,7 @@ instance_to_state_def(int state, const NodePath &path) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
PGFrameStyle PGItem::
|
||||
get_frame_style(int state) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (state < 0 || state >= (int)_state_defs.size()) {
|
||||
return PGFrameStyle();
|
||||
}
|
||||
|
|
@ -1044,14 +1075,15 @@ get_frame_style(int state) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
set_frame_style(int state, const PGFrameStyle &style) {
|
||||
ReMutexHolder holder(_lock);
|
||||
// Get the state def node, mainly to ensure that this state is
|
||||
// slotted and listed as having been defined.
|
||||
NodePath &root = get_state_def(state);
|
||||
nassertv(!root.is_empty());
|
||||
|
||||
|
||||
_state_defs[state]._frame_style = style;
|
||||
_state_defs[state]._frame_stale = true;
|
||||
|
||||
|
||||
mark_internal_bounds_stale();
|
||||
}
|
||||
|
||||
|
|
@ -1064,6 +1096,7 @@ set_frame_style(int state, const PGFrameStyle &style) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
set_sound(const string &event, AudioSound *sound) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_sounds[event] = sound;
|
||||
}
|
||||
|
||||
|
|
@ -1075,6 +1108,7 @@ set_sound(const string &event, AudioSound *sound) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
clear_sound(const string &event) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_sounds.erase(event);
|
||||
}
|
||||
|
||||
|
|
@ -1086,6 +1120,7 @@ clear_sound(const string &event) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
AudioSound *PGItem::
|
||||
get_sound(const string &event) const {
|
||||
ReMutexHolder holder(_lock);
|
||||
Sounds::const_iterator si = _sounds.find(event);
|
||||
if (si != _sounds.end()) {
|
||||
return (*si).second;
|
||||
|
|
@ -1101,6 +1136,7 @@ get_sound(const string &event) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGItem::
|
||||
has_sound(const string &event) const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return (_sounds.count(event) != 0);
|
||||
}
|
||||
#endif // HAVE_AUDIO
|
||||
|
|
@ -1134,6 +1170,7 @@ get_text_node() {
|
|||
void PGItem::
|
||||
play_sound(const string &event) {
|
||||
#ifdef HAVE_AUDIO
|
||||
ReMutexHolder holder(_lock);
|
||||
Sounds::const_iterator si = _sounds.find(event);
|
||||
if (si != _sounds.end()) {
|
||||
AudioSound *sound = (*si).second;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
#include "textNode.h"
|
||||
#include "plane.h"
|
||||
#include "pmap.h"
|
||||
#include "reMutex.h"
|
||||
#include "reMutexHolder.h"
|
||||
|
||||
class PGTop;
|
||||
class MouseWatcherParameter;
|
||||
|
|
@ -55,6 +57,8 @@ PUBLISHED:
|
|||
PGItem(const string &name);
|
||||
virtual ~PGItem();
|
||||
|
||||
INLINE void set_name(const string &name);
|
||||
|
||||
protected:
|
||||
PGItem(const PGItem ©);
|
||||
|
||||
|
|
@ -65,11 +69,14 @@ protected:
|
|||
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
|
||||
virtual bool is_renderable() const;
|
||||
|
||||
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
|
||||
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const;
|
||||
|
||||
virtual void r_prepare_scene(const RenderState *state,
|
||||
PreparedGraphicsObjects *prepared_objects);
|
||||
PreparedGraphicsObjects *prepared_objects,
|
||||
Thread *current_thread);
|
||||
|
||||
public:
|
||||
virtual void xform(const LMatrix4f &mat);
|
||||
|
|
@ -191,6 +198,9 @@ private:
|
|||
|
||||
bool clip_frame(pvector<LPoint2f> &source_points, const Planef &plane) const;
|
||||
|
||||
protected:
|
||||
ReMutex _lock;
|
||||
|
||||
private:
|
||||
PGItemNotify *_notify;
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ set_virtual_frame(float left, float right, float bottom, float top) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
set_virtual_frame(const LVecBase4f &frame) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_has_virtual_frame = true;
|
||||
_virtual_frame = frame;
|
||||
|
||||
|
|
@ -52,6 +53,7 @@ set_virtual_frame(const LVecBase4f &frame) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase4f &PGScrollFrame::
|
||||
get_virtual_frame() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _has_virtual_frame ? _virtual_frame : get_clip_frame();
|
||||
}
|
||||
|
||||
|
|
@ -64,6 +66,7 @@ get_virtual_frame() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGScrollFrame::
|
||||
has_virtual_frame() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _has_virtual_frame;
|
||||
}
|
||||
|
||||
|
|
@ -77,6 +80,7 @@ has_virtual_frame() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
clear_virtual_frame() {
|
||||
ReMutexHolder holder(_lock);
|
||||
_has_virtual_frame = false;
|
||||
}
|
||||
|
||||
|
|
@ -92,6 +96,7 @@ clear_virtual_frame() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
set_manage_pieces(bool manage_pieces) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_manage_pieces = manage_pieces;
|
||||
_needs_remanage = true;
|
||||
_needs_recompute_clip = true;
|
||||
|
|
@ -105,6 +110,7 @@ set_manage_pieces(bool manage_pieces) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGScrollFrame::
|
||||
get_manage_pieces() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _manage_pieces;
|
||||
}
|
||||
|
||||
|
|
@ -122,6 +128,7 @@ get_manage_pieces() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
set_auto_hide(bool auto_hide) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_auto_hide = auto_hide;
|
||||
if (_auto_hide) {
|
||||
set_manage_pieces(true);
|
||||
|
|
@ -137,6 +144,7 @@ set_auto_hide(bool auto_hide) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGScrollFrame::
|
||||
get_auto_hide() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _auto_hide;
|
||||
}
|
||||
|
||||
|
|
@ -150,6 +158,7 @@ get_auto_hide() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
set_horizontal_slider(PGSliderBar *horizontal_slider) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_horizontal_slider != (PGSliderBar *)NULL) {
|
||||
_horizontal_slider->set_notify(NULL);
|
||||
}
|
||||
|
|
@ -181,6 +190,7 @@ clear_horizontal_slider() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGSliderBar *PGScrollFrame::
|
||||
get_horizontal_slider() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _horizontal_slider;
|
||||
}
|
||||
|
||||
|
|
@ -194,6 +204,7 @@ get_horizontal_slider() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
set_vertical_slider(PGSliderBar *vertical_slider) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_vertical_slider != (PGSliderBar *)NULL) {
|
||||
_vertical_slider->set_notify(NULL);
|
||||
}
|
||||
|
|
@ -225,6 +236,7 @@ clear_vertical_slider() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGSliderBar *PGScrollFrame::
|
||||
get_vertical_slider() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _vertical_slider;
|
||||
}
|
||||
|
||||
|
|
@ -236,6 +248,7 @@ get_vertical_slider() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
recompute() {
|
||||
ReMutexHolder holder(_lock);
|
||||
recompute_clip();
|
||||
recompute_canvas();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ PGScrollFrame(const PGScrollFrame ©) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PGScrollFrame::
|
||||
make_copy() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return new PGScrollFrame(*this);
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +107,7 @@ make_copy() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGScrollFrame::
|
||||
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_manage_pieces && _needs_remanage) {
|
||||
remanage();
|
||||
}
|
||||
|
|
@ -127,6 +129,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
xform(const LMatrix4f &mat) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGVirtualFrame::xform(mat);
|
||||
|
||||
_needs_remanage = true;
|
||||
|
|
@ -143,6 +146,7 @@ void PGScrollFrame::
|
|||
setup(float width, float height,
|
||||
float left, float right, float bottom, float top,
|
||||
float slider_width, float bevel) {
|
||||
ReMutexHolder holder(_lock);
|
||||
set_state(0);
|
||||
clear_state_def(0);
|
||||
|
||||
|
|
@ -196,6 +200,7 @@ setup(float width, float height,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
remanage() {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_remanage = false;
|
||||
|
||||
const LVecBase4f &frame = get_frame();
|
||||
|
|
@ -312,6 +317,7 @@ remanage() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
frame_changed() {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGVirtualFrame::frame_changed();
|
||||
_needs_remanage = true;
|
||||
_needs_recompute_clip = true;
|
||||
|
|
@ -325,6 +331,7 @@ frame_changed() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
item_transform_changed(PGItem *) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
|
|
@ -336,6 +343,7 @@ item_transform_changed(PGItem *) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
item_frame_changed(PGItem *) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
|
|
@ -347,6 +355,7 @@ item_frame_changed(PGItem *) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
item_draw_mask_changed(PGItem *) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_remanage = true;
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
|
@ -359,6 +368,7 @@ item_draw_mask_changed(PGItem *) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
slider_bar_adjust(PGSliderBar *) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_recompute_canvas = true;
|
||||
}
|
||||
|
||||
|
|
@ -370,6 +380,7 @@ slider_bar_adjust(PGSliderBar *) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
recompute_clip() {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_recompute_clip = false;
|
||||
_needs_recompute_canvas = true;
|
||||
|
||||
|
|
@ -397,6 +408,7 @@ recompute_clip() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
recompute_canvas() {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_recompute_canvas = false;
|
||||
|
||||
const LVecBase4f &clip = get_clip_frame();
|
||||
|
|
@ -423,6 +435,7 @@ float PGScrollFrame::
|
|||
interpolate_canvas(float clip_min, float clip_max,
|
||||
float canvas_min, float canvas_max,
|
||||
PGSliderBar *slider_bar) {
|
||||
ReMutexHolder holder(_lock);
|
||||
float t = 0.0f;
|
||||
if (slider_bar != (PGSliderBar *)NULL) {
|
||||
t = slider_bar->get_ratio();
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ get_notify() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_axis(const LVector3f &axis) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_axis = axis;
|
||||
_needs_remanage = true;
|
||||
_needs_recompute = true;
|
||||
|
|
@ -73,6 +74,7 @@ set_axis(const LVector3f &axis) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVector3f &PGSliderBar::
|
||||
get_axis() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _axis;
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +85,7 @@ get_axis() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_range(float min_value, float max_value) {
|
||||
ReMutexHolder holder(_lock);
|
||||
nassertv(min_value != max_value);
|
||||
_min_value = min_value;
|
||||
_max_value = max_value;
|
||||
|
|
@ -101,6 +104,7 @@ set_range(float min_value, float max_value) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_min_value() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _min_value;
|
||||
}
|
||||
|
||||
|
|
@ -112,6 +116,7 @@ get_min_value() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_max_value() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _max_value;
|
||||
}
|
||||
|
||||
|
|
@ -123,6 +128,7 @@ get_max_value() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_scroll_size(float value) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_scroll_value = value;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
|
@ -134,6 +140,7 @@ set_scroll_size(float value) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_scroll_size() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _scroll_value;
|
||||
}
|
||||
|
||||
|
|
@ -148,6 +155,7 @@ get_scroll_size() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_page_size(float value) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_page_value = value;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
|
@ -159,6 +167,7 @@ set_page_size(float value) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_page_size() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _page_value;
|
||||
}
|
||||
|
||||
|
|
@ -171,6 +180,7 @@ get_page_size() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_value(float value) {
|
||||
ReMutexHolder holder(_lock);
|
||||
set_ratio((value - _min_value) / (_max_value - _min_value));
|
||||
}
|
||||
|
||||
|
|
@ -181,6 +191,7 @@ set_value(float value) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_value() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_ratio() * (_max_value - _min_value) + _min_value;
|
||||
}
|
||||
|
||||
|
|
@ -192,6 +203,7 @@ get_value() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_ratio(float ratio) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (!is_button_down()) {
|
||||
internal_set_ratio(ratio);
|
||||
}
|
||||
|
|
@ -205,6 +217,7 @@ set_ratio(float ratio) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_ratio() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _ratio;
|
||||
}
|
||||
|
||||
|
|
@ -218,6 +231,7 @@ get_ratio() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGSliderBar::
|
||||
is_button_down() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _dragging || _mouse_button_page ||
|
||||
(_scroll_button_held != (PGItem *)NULL);
|
||||
}
|
||||
|
|
@ -232,6 +246,7 @@ is_button_down() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_resize_thumb(bool resize_thumb) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_resize_thumb = resize_thumb;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
|
@ -244,6 +259,7 @@ set_resize_thumb(bool resize_thumb) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGSliderBar::
|
||||
get_resize_thumb() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _resize_thumb;
|
||||
}
|
||||
|
||||
|
|
@ -258,6 +274,7 @@ get_resize_thumb() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_manage_pieces(bool manage_pieces) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_manage_pieces = manage_pieces;
|
||||
_needs_remanage = true;
|
||||
_needs_recompute = true;
|
||||
|
|
@ -271,6 +288,7 @@ set_manage_pieces(bool manage_pieces) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGSliderBar::
|
||||
get_manage_pieces() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _manage_pieces;
|
||||
}
|
||||
|
||||
|
|
@ -288,6 +306,7 @@ get_manage_pieces() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_thumb_button(PGButton *thumb_button) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_thumb_button != (PGButton *)NULL) {
|
||||
_thumb_button->set_notify(NULL);
|
||||
}
|
||||
|
|
@ -319,6 +338,7 @@ clear_thumb_button() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGButton *PGSliderBar::
|
||||
get_thumb_button() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _thumb_button;
|
||||
}
|
||||
|
||||
|
|
@ -336,6 +356,7 @@ get_thumb_button() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_left_button(PGButton *left_button) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_left_button != (PGButton *)NULL) {
|
||||
_left_button->set_notify(NULL);
|
||||
}
|
||||
|
|
@ -368,6 +389,7 @@ clear_left_button() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGButton *PGSliderBar::
|
||||
get_left_button() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _left_button;
|
||||
}
|
||||
|
||||
|
|
@ -385,6 +407,7 @@ get_left_button() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_right_button(PGButton *right_button) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_right_button != (PGButton *)NULL) {
|
||||
_right_button->set_notify(NULL);
|
||||
}
|
||||
|
|
@ -417,6 +440,7 @@ clear_right_button() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGButton *PGSliderBar::
|
||||
get_right_button() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _right_button;
|
||||
}
|
||||
|
||||
|
|
@ -441,6 +465,7 @@ get_adjust_prefix() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGSliderBar::
|
||||
get_adjust_event() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return get_adjust_prefix() + get_id();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ PGSliderBar(const PGSliderBar ©) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PGSliderBar::
|
||||
make_copy() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return new PGSliderBar(*this);
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +111,7 @@ make_copy() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
press(const MouseWatcherParameter ¶m, bool background) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (param.has_mouse()) {
|
||||
_mouse_pos = param.get_mouse();
|
||||
}
|
||||
|
|
@ -138,6 +140,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
release(const MouseWatcherParameter ¶m, bool background) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (MouseButton::is_mouse_button(param.get_button())) {
|
||||
_mouse_button_page = false;
|
||||
}
|
||||
|
|
@ -155,6 +158,7 @@ release(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
move(const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_mouse_pos = param.get_mouse();
|
||||
if (_dragging) {
|
||||
// We only get here if we the user originally clicked on the
|
||||
|
|
@ -193,6 +197,7 @@ move(const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGSliderBar::
|
||||
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_manage_pieces && _needs_remanage) {
|
||||
remanage();
|
||||
}
|
||||
|
|
@ -226,6 +231,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
xform(const LMatrix4f &mat) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGItem::xform(mat);
|
||||
_axis = _axis * mat;
|
||||
|
||||
|
|
@ -248,6 +254,7 @@ xform(const LMatrix4f &mat) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
adjust() {
|
||||
ReMutexHolder holder(_lock);
|
||||
string event = get_adjust_event();
|
||||
play_sound(event);
|
||||
throw_event(event);
|
||||
|
|
@ -273,6 +280,7 @@ adjust() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
setup_scroll_bar(bool vertical, float length, float width, float bevel) {
|
||||
ReMutexHolder holder(_lock);
|
||||
set_state(0);
|
||||
clear_state_def(0);
|
||||
|
||||
|
|
@ -346,6 +354,7 @@ setup_scroll_bar(bool vertical, float length, float width, float bevel) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
setup_slider(bool vertical, float length, float width, float bevel) {
|
||||
ReMutexHolder holder(_lock);
|
||||
set_state(0);
|
||||
clear_state_def(0);
|
||||
|
||||
|
|
@ -401,6 +410,7 @@ setup_slider(bool vertical, float length, float width, float bevel) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
set_active(bool active) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGItem::set_active(active);
|
||||
|
||||
// This also implicitly sets the managed pieces.
|
||||
|
|
@ -424,6 +434,7 @@ set_active(bool active) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
remanage() {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_remanage = false;
|
||||
|
||||
const LVecBase4f &frame = get_frame();
|
||||
|
|
@ -475,6 +486,7 @@ remanage() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
recompute() {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_recompute = false;
|
||||
|
||||
if (_min_value != _max_value) {
|
||||
|
|
@ -486,88 +498,101 @@ recompute() {
|
|||
_page_ratio = 0.0f;
|
||||
}
|
||||
|
||||
LVecBase4f frame = get_frame();
|
||||
reduce_region(frame, _left_button);
|
||||
reduce_region(frame, _right_button);
|
||||
|
||||
if (fabs(_axis[0]) > fabs(_axis[1] + _axis[2])) {
|
||||
// The slider is X-dominant.
|
||||
|
||||
_min_x = frame[0];
|
||||
_max_x = frame[1];
|
||||
|
||||
float trough_width = _max_x - _min_x;
|
||||
|
||||
if (_thumb_button != (PGButton *)NULL) {
|
||||
const LVecBase4f &thumb_frame = _thumb_button->get_frame();
|
||||
|
||||
if (_resize_thumb) {
|
||||
// If we're allowed to adjust the thumb's size, we don't need to
|
||||
// find out how wide it is.
|
||||
_thumb_width = trough_width * min(1.0f, _page_ratio);
|
||||
_thumb_button->set_frame(-_thumb_width / 2.0f, _thumb_width / 2.0f,
|
||||
thumb_frame[2], thumb_frame[3]);
|
||||
} else {
|
||||
// If we're not adjusting the thumb's size, we do need to know
|
||||
// its current width.
|
||||
_thumb_width = thumb_frame[1] - thumb_frame[0];
|
||||
}
|
||||
}
|
||||
|
||||
_range_x = trough_width - _thumb_width;
|
||||
|
||||
const LVecBase4f &thumb_frame = _thumb_button->get_frame();
|
||||
if (_axis[0] >= 0.0f) {
|
||||
// The slider runs forwards, left to right.
|
||||
_thumb_start = (_min_x - thumb_frame[0]) * _axis;
|
||||
} else {
|
||||
// The slider runs backwards: right to left.
|
||||
_thumb_start = (thumb_frame[1] - _max_x) * _axis;
|
||||
}
|
||||
_thumb_start += LVector3f::rfu(0.0f, 0.0f, (frame[2] + frame[3]) / 2.0f);
|
||||
if (!has_frame()) {
|
||||
_min_x = 0.0f;
|
||||
_max_x = 0.0f;
|
||||
_thumb_width = 0.0f;
|
||||
_range_x = 0.0f;
|
||||
_thumb_start.set(0.0f, 0.0f, 0.0f);
|
||||
|
||||
} else {
|
||||
// The slider is Y-dominant. We call it X in the variable names,
|
||||
// but it's really Y (or even Z).
|
||||
LVecBase4f frame = get_frame();
|
||||
reduce_region(frame, _left_button);
|
||||
reduce_region(frame, _right_button);
|
||||
|
||||
_min_x = frame[2];
|
||||
_max_x = frame[3];
|
||||
|
||||
float trough_width = _max_x - _min_x;
|
||||
|
||||
if (_thumb_button == (PGButton *)NULL) {
|
||||
_thumb_width = 0.0f;
|
||||
_range_x = 0.0f;
|
||||
_thumb_start.set(0.0f, 0.0f, 0.0f);
|
||||
|
||||
if (fabs(_axis[0]) > fabs(_axis[1] + _axis[2])) {
|
||||
// The slider is X-dominant.
|
||||
|
||||
_min_x = frame[0];
|
||||
_max_x = frame[1];
|
||||
|
||||
float trough_width = _max_x - _min_x;
|
||||
|
||||
if (_thumb_button == (PGButton *)NULL) {
|
||||
_thumb_width = 0.0f;
|
||||
_range_x = 0.0f;
|
||||
_thumb_start.set(0.0f, 0.0f, 0.0f);
|
||||
|
||||
} else {
|
||||
const LVecBase4f &thumb_frame = _thumb_button->get_frame();
|
||||
|
||||
if (_resize_thumb) {
|
||||
// If we're allowed to adjust the thumb's size, we don't need to
|
||||
// find out how wide it is.
|
||||
_thumb_width = trough_width * min(1.0f, _page_ratio);
|
||||
_thumb_button->set_frame(-_thumb_width / 2.0f, _thumb_width / 2.0f,
|
||||
thumb_frame[2], thumb_frame[3]);
|
||||
} else {
|
||||
// If we're not adjusting the thumb's size, we do need to know
|
||||
// its current width.
|
||||
_thumb_width = thumb_frame[1] - thumb_frame[0];
|
||||
}
|
||||
|
||||
_range_x = trough_width - _thumb_width;
|
||||
|
||||
if (_axis[0] >= 0.0f) {
|
||||
// The slider runs forwards, left to right.
|
||||
_thumb_start = (_min_x - thumb_frame[0]) * _axis;
|
||||
} else {
|
||||
// The slider runs backwards: right to left.
|
||||
_thumb_start = (thumb_frame[1] - _max_x) * _axis;
|
||||
}
|
||||
_thumb_start += LVector3f::rfu(0.0f, 0.0f, (frame[2] + frame[3]) / 2.0f);
|
||||
}
|
||||
|
||||
} else {
|
||||
const LVecBase4f &thumb_frame = _thumb_button->get_frame();
|
||||
|
||||
if (_resize_thumb) {
|
||||
// If we're allowed to adjust the thumb's size, we don't need to
|
||||
// find out how wide it is.
|
||||
_thumb_width = trough_width * min(1.0f, _page_ratio);
|
||||
_thumb_button->set_frame(thumb_frame[0], thumb_frame[1],
|
||||
-_thumb_width / 2.0f, _thumb_width / 2.0f);
|
||||
// The slider is Y-dominant. We call it X in the variable names,
|
||||
// but it's really Y (or even Z).
|
||||
|
||||
_min_x = frame[2];
|
||||
_max_x = frame[3];
|
||||
|
||||
float trough_width = _max_x - _min_x;
|
||||
|
||||
if (_thumb_button == (PGButton *)NULL) {
|
||||
_thumb_width = 0.0f;
|
||||
_range_x = 0.0f;
|
||||
_thumb_start.set(0.0f, 0.0f, 0.0f);
|
||||
|
||||
} else {
|
||||
// If we're not adjusting the thumb's size, we do need to know
|
||||
// its current width.
|
||||
_thumb_width = thumb_frame[3] - thumb_frame[2];
|
||||
const LVecBase4f &thumb_frame = _thumb_button->get_frame();
|
||||
|
||||
if (_resize_thumb) {
|
||||
// If we're allowed to adjust the thumb's size, we don't need to
|
||||
// find out how wide it is.
|
||||
_thumb_width = trough_width * min(1.0f, _page_ratio);
|
||||
_thumb_button->set_frame(thumb_frame[0], thumb_frame[1],
|
||||
-_thumb_width / 2.0f, _thumb_width / 2.0f);
|
||||
} else {
|
||||
// If we're not adjusting the thumb's size, we do need to know
|
||||
// its current width.
|
||||
_thumb_width = thumb_frame[3] - thumb_frame[2];
|
||||
}
|
||||
|
||||
_range_x = trough_width - _thumb_width;
|
||||
|
||||
if (_axis[1] >= 0.0f && _axis[2] >= 0.0f) {
|
||||
// The slider runs forwards, bottom to top.
|
||||
_thumb_start = (_min_x - thumb_frame[2]) * _axis;
|
||||
} else {
|
||||
// The slider runs backwards: top to bottom.
|
||||
_thumb_start = (thumb_frame[3] - _max_x) * _axis;
|
||||
}
|
||||
_thumb_start += LVector3f::rfu((frame[0] + frame[1]) / 2.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
_range_x = trough_width - _thumb_width;
|
||||
|
||||
if (_axis[1] >= 0.0f && _axis[2] >= 0.0f) {
|
||||
// The slider runs forwards, bottom to top.
|
||||
_thumb_start = (_min_x - thumb_frame[2]) * _axis;
|
||||
} else {
|
||||
// The slider runs backwards: top to bottom.
|
||||
_thumb_start = (thumb_frame[3] - _max_x) * _axis;
|
||||
}
|
||||
_thumb_start += LVector3f::rfu((frame[0] + frame[1]) / 2.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
reposition();
|
||||
}
|
||||
|
||||
|
|
@ -578,6 +603,7 @@ recompute() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
frame_changed() {
|
||||
ReMutexHolder holder(_lock);
|
||||
PGItem::frame_changed();
|
||||
_needs_remanage = true;
|
||||
_needs_recompute = true;
|
||||
|
|
@ -591,6 +617,7 @@ frame_changed() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_transform_changed(PGItem *) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
|
|
@ -602,6 +629,7 @@ item_transform_changed(PGItem *) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_frame_changed(PGItem *) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
|
|
@ -613,6 +641,7 @@ item_frame_changed(PGItem *) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_draw_mask_changed(PGItem *) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
|
|
@ -624,6 +653,7 @@ item_draw_mask_changed(PGItem *) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_press(PGItem *item, const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (param.has_mouse()) {
|
||||
_mouse_pos = param.get_mouse();
|
||||
}
|
||||
|
|
@ -648,6 +678,7 @@ item_press(PGItem *item, const MouseWatcherParameter ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_release(PGItem *item, const MouseWatcherParameter &) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (item == _scroll_button_held) {
|
||||
_scroll_button_held = NULL;
|
||||
|
||||
|
|
@ -667,6 +698,7 @@ item_release(PGItem *item, const MouseWatcherParameter &) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_move(PGItem *item, const MouseWatcherParameter ¶m) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_mouse_pos = param.get_mouse();
|
||||
if (item == _thumb_button) {
|
||||
if (_dragging) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ set_clip_frame(float left, float right, float bottom, float top) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase4f &PGVirtualFrame::
|
||||
get_clip_frame() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _has_clip_frame ? _clip_frame : get_frame();
|
||||
}
|
||||
|
||||
|
|
@ -49,6 +50,7 @@ get_clip_frame() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGVirtualFrame::
|
||||
has_clip_frame() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _has_clip_frame;
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +63,7 @@ has_clip_frame() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGVirtualFrame::
|
||||
set_canvas_transform(const TransformState *transform) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_canvas_node->set_transform(transform);
|
||||
}
|
||||
|
||||
|
|
@ -73,6 +76,7 @@ set_canvas_transform(const TransformState *transform) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const TransformState *PGVirtualFrame::
|
||||
get_canvas_transform() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _canvas_node->get_transform();
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +88,7 @@ get_canvas_transform() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *PGVirtualFrame::
|
||||
get_canvas_node() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _canvas_node;
|
||||
}
|
||||
|
||||
|
|
@ -94,5 +99,6 @@ get_canvas_node() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *PGVirtualFrame::
|
||||
get_canvas_parent() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _canvas_parent;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ PGVirtualFrame(const PGVirtualFrame ©) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PGVirtualFrame::
|
||||
make_copy() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return new PGVirtualFrame(*this);
|
||||
}
|
||||
|
||||
|
|
@ -93,6 +94,7 @@ make_copy() const {
|
|||
void PGVirtualFrame::
|
||||
r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map,
|
||||
Thread *current_thread) {
|
||||
ReMutexHolder holder(_lock);
|
||||
PandaNode::r_copy_children(from, inst_map, current_thread);
|
||||
|
||||
// Reassign the canvas_node to point to the new copy, if it's there.
|
||||
|
|
@ -129,6 +131,7 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGVirtualFrame::
|
||||
setup(float width, float height) {
|
||||
ReMutexHolder holder(_lock);
|
||||
set_state(0);
|
||||
clear_state_def(0);
|
||||
|
||||
|
|
@ -159,6 +162,7 @@ setup(float width, float height) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGVirtualFrame::
|
||||
set_clip_frame(const LVecBase4f &frame) {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (!_has_clip_frame || _clip_frame != frame) {
|
||||
_has_clip_frame = true;
|
||||
_clip_frame = frame;
|
||||
|
|
@ -182,6 +186,7 @@ set_clip_frame(const LVecBase4f &frame) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGVirtualFrame::
|
||||
clear_clip_frame() {
|
||||
ReMutexHolder holder(_lock);
|
||||
if (_has_clip_frame) {
|
||||
_has_clip_frame = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGWaitBar::
|
||||
set_range(float range) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_range = range;
|
||||
_bar_state = -1;
|
||||
}
|
||||
|
|
@ -31,6 +32,7 @@ set_range(float range) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGWaitBar::
|
||||
get_range() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _range;
|
||||
}
|
||||
|
||||
|
|
@ -42,6 +44,7 @@ get_range() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGWaitBar::
|
||||
set_value(float value) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_value = value;
|
||||
_bar_state = -1;
|
||||
}
|
||||
|
|
@ -53,6 +56,7 @@ set_value(float value) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGWaitBar::
|
||||
get_value() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _value;
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +67,7 @@ get_value() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGWaitBar::
|
||||
get_percent() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return (_value / _range) * 100.0f;
|
||||
}
|
||||
|
||||
|
|
@ -74,6 +79,7 @@ get_percent() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGWaitBar::
|
||||
set_bar_style(const PGFrameStyle &style) {
|
||||
ReMutexHolder holder(_lock);
|
||||
_bar_style = style;
|
||||
_bar_state = -1;
|
||||
}
|
||||
|
|
@ -86,5 +92,6 @@ set_bar_style(const PGFrameStyle &style) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGFrameStyle PGWaitBar::
|
||||
get_bar_style() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return _bar_style;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ PGWaitBar(const PGWaitBar ©) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PGWaitBar::
|
||||
make_copy() const {
|
||||
ReMutexHolder holder(_lock);
|
||||
return new PGWaitBar(*this);
|
||||
}
|
||||
|
||||
|
|
@ -97,6 +98,7 @@ make_copy() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGWaitBar::
|
||||
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
||||
ReMutexHolder holder(_lock);
|
||||
update();
|
||||
return PGItem::cull_callback(trav, data);
|
||||
}
|
||||
|
|
@ -109,6 +111,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGWaitBar::
|
||||
setup(float width, float height, float range) {
|
||||
ReMutexHolder holder(_lock);
|
||||
set_state(0);
|
||||
clear_state_def(0);
|
||||
|
||||
|
|
@ -136,6 +139,7 @@ setup(float width, float height, float range) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGWaitBar::
|
||||
update() {
|
||||
ReMutexHolder holder(_lock);
|
||||
int state = get_state();
|
||||
|
||||
// If the bar was last drawn in this state and is still current, we
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ wait(double timeout) {
|
|||
ts.tv_nsec += (int)((timeout - seconds) * 1000000.0);
|
||||
|
||||
int result = pthread_cond_timedwait(&_cvar, &_mutex._lock, &ts);
|
||||
nassertv(result == 0);
|
||||
nassertv(result == 0 || errno == ETIMEDOUT);
|
||||
}
|
||||
|
||||
#endif // HAVE_POSIX_THREADS
|
||||
|
|
|
|||
|
|
@ -65,7 +65,13 @@ wait(double timeout) {
|
|||
void ConditionVarSimpleImpl::
|
||||
do_signal() {
|
||||
ThreadSimpleManager *manager = ThreadSimpleManager::get_global_ptr();
|
||||
manager->unblock_one(this);
|
||||
if (manager->unblock_one(this)) {
|
||||
// There had been a thread waiting on this condition variable.
|
||||
// Switch contexts immediately, to make fairness more likely.
|
||||
ThreadSimpleImpl *thread = manager->get_current_thread();
|
||||
manager->enqueue_ready(thread);
|
||||
manager->next_context();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -76,7 +82,13 @@ do_signal() {
|
|||
void ConditionVarSimpleImpl::
|
||||
do_signal_all() {
|
||||
ThreadSimpleManager *manager = ThreadSimpleManager::get_global_ptr();
|
||||
manager->unblock_all(this);
|
||||
if (manager->unblock_all(this)) {
|
||||
// There had been a thread waiting on this condition variable.
|
||||
// Switch contexts immediately, to make fairness more likely.
|
||||
ThreadSimpleImpl *thread = manager->get_current_thread();
|
||||
manager->enqueue_ready(thread);
|
||||
manager->next_context();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // THREAD_SIMPLE_IMPL
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ MutexTrueImpl *MutexDebug::_global_lock;
|
|||
////////////////////////////////////////////////////////////////////
|
||||
MutexDebug::
|
||||
MutexDebug(const string &name, bool allow_recursion) :
|
||||
_name(name),
|
||||
Namable(name),
|
||||
_allow_recursion(allow_recursion),
|
||||
_locking_thread(NULL),
|
||||
_lock_count(0),
|
||||
|
|
@ -58,9 +58,9 @@ MutexDebug::
|
|||
void MutexDebug::
|
||||
output(ostream &out) const {
|
||||
if (_allow_recursion) {
|
||||
out << "ReMutex " << _name << " " << (void *)this;
|
||||
out << "ReMutex " << get_name() << " " << (void *)this;
|
||||
} else {
|
||||
out << "Mutex " << _name << " " << (void *)this;
|
||||
out << "Mutex " << get_name() << " " << (void *)this;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ do_lock() {
|
|||
nassertv(_lock_count > 0);
|
||||
if (!_allow_recursion) {
|
||||
ostringstream ostr;
|
||||
ostr << *_locking_thread << " attempted to double-lock non-reentrant "
|
||||
ostr << *this_thread << " attempted to double-lock non-reentrant "
|
||||
<< *this;
|
||||
nassert_raise(ostr.str());
|
||||
}
|
||||
|
|
@ -99,6 +99,26 @@ do_lock() {
|
|||
} else {
|
||||
// The mutex is locked by some other thread.
|
||||
|
||||
#ifdef PHONY_MUTEX
|
||||
// In this case, we don't really have mutexes anyway.
|
||||
MissedThreads::iterator mi = _missed_threads.insert(MissedThreads::value_type(this_thread, 0)).first;
|
||||
if ((*mi).second == 0) {
|
||||
thread_cat.info()
|
||||
<< *this_thread << " not stopped by " << *this << " (held by "
|
||||
<< *_locking_thread << ")\n";
|
||||
} else {
|
||||
if (!_allow_recursion) {
|
||||
ostringstream ostr;
|
||||
ostr << *this_thread << " attempted to double-lock non-reentrant "
|
||||
<< *this;
|
||||
nassert_raise(ostr.str());
|
||||
}
|
||||
}
|
||||
++((*mi).second);
|
||||
|
||||
#else // PHONY_MUTEX
|
||||
// This is the real case. We have mutexes, so enforce it.
|
||||
|
||||
// Check for deadlock.
|
||||
MutexDebug *next_mutex = this;
|
||||
while (next_mutex != NULL) {
|
||||
|
|
@ -133,6 +153,7 @@ do_lock() {
|
|||
<< *this_thread << " blocking on " << *this << " (held by "
|
||||
<< *_locking_thread << ")\n";
|
||||
}
|
||||
|
||||
while (_locking_thread != (Thread *)NULL) {
|
||||
_cvar_impl.wait();
|
||||
}
|
||||
|
|
@ -147,6 +168,7 @@ do_lock() {
|
|||
_locking_thread = this_thread;
|
||||
++_lock_count;
|
||||
nassertv(_lock_count == 1);
|
||||
#endif // PHONY_MUTEX
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -165,10 +187,27 @@ do_release() {
|
|||
Thread *this_thread = Thread::get_current_thread();
|
||||
|
||||
if (_locking_thread != this_thread) {
|
||||
#ifdef PHONY_MUTEX
|
||||
// No real mutexes. This just means we blew past a mutex without
|
||||
// locking it, above.
|
||||
|
||||
MissedThreads::iterator mi = _missed_threads.find(this_thread);
|
||||
nassertv(mi != _missed_threads.end());
|
||||
nassertv((*mi).second > 0);
|
||||
--((*mi).second);
|
||||
|
||||
if ((*mi).second == 0) {
|
||||
_missed_threads.erase(mi);
|
||||
}
|
||||
|
||||
#else // PHONY_MUTEX
|
||||
// In the real-mutex case, this is an error condition.
|
||||
ostringstream ostr;
|
||||
ostr << *this_thread << " attempted to release "
|
||||
<< *this << " which it does not own";
|
||||
nassert_raise(ostr.str());
|
||||
#endif // PHONY_MUTEX
|
||||
|
||||
_global_lock->release();
|
||||
return;
|
||||
}
|
||||
|
|
@ -179,7 +218,19 @@ do_release() {
|
|||
if (_lock_count == 0) {
|
||||
// That was the last lock held by this thread. Release the lock.
|
||||
_locking_thread = (Thread *)NULL;
|
||||
|
||||
#ifdef PHONY_MUTEX
|
||||
if (!_missed_threads.empty()) {
|
||||
// Promote some other thread to be the honorary lock holder.
|
||||
MissedThreads::iterator mi = _missed_threads.begin();
|
||||
_locking_thread = (*mi).first;
|
||||
_lock_count = (*mi).second;
|
||||
_missed_threads.erase(mi);
|
||||
nassertv(_lock_count > 0);
|
||||
}
|
||||
#else
|
||||
_cvar_impl.signal();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +242,20 @@ do_release() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool MutexDebug::
|
||||
do_debug_is_locked() const {
|
||||
return (_locking_thread == Thread::get_current_thread());
|
||||
Thread *this_thread = Thread::get_current_thread();
|
||||
if (_locking_thread == this_thread) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef PHONY_MUTEX
|
||||
MissedThreads::const_iterator mi = _missed_threads.find(this_thread);
|
||||
if (mi != _missed_threads.end()) {
|
||||
nassertr((*mi).second > 0, false);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -19,16 +19,25 @@
|
|||
#include "mutexTrueImpl.h"
|
||||
#include "conditionVarImpl.h"
|
||||
#include "thread.h"
|
||||
#include "namable.h"
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
|
||||
#if defined(SIMPLE_THREADS) && defined(SIMPLE_THREADS_NO_MUTEX)
|
||||
// In this mode, we don't actually lock and unlock a mutex. We just
|
||||
// wave at them as they go by. This actually involves a bit more
|
||||
// work, here in the debug mode, than a real mutex, because we have to
|
||||
// track all the threads that failed to lock the mutex.
|
||||
#define PHONY_MUTEX
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : MutexDebug
|
||||
// Description : This class implements a standard mutex the hard way,
|
||||
// by doing everything by hand. This does allow fancy
|
||||
// things like deadlock detection, however.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA_PIPELINE MutexDebug {
|
||||
class EXPCL_PANDA_PIPELINE MutexDebug : public Namable {
|
||||
protected:
|
||||
MutexDebug(const string &name, bool allow_recursion);
|
||||
virtual ~MutexDebug();
|
||||
|
|
@ -57,10 +66,13 @@ private:
|
|||
private:
|
||||
INLINE static MutexTrueImpl *get_global_lock();
|
||||
|
||||
string _name;
|
||||
bool _allow_recursion;
|
||||
Thread *_locking_thread;
|
||||
int _lock_count;
|
||||
#ifdef PHONY_MUTEX
|
||||
typedef pmap<Thread *, int> MissedThreads;
|
||||
MissedThreads _missed_threads;
|
||||
#endif
|
||||
|
||||
ConditionVarImpl _cvar_impl;
|
||||
|
||||
|
|
|
|||
|
|
@ -102,3 +102,60 @@ INLINE bool MutexDirect::
|
|||
debug_is_locked() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::debug_is_locked
|
||||
// Access: Published
|
||||
// Description: Returns true if the current thread has locked the
|
||||
// Mutex, false otherwise. This method is only intended
|
||||
// for use in debugging, hence the method name; in the
|
||||
// MutexDirect case, it always returns true, since
|
||||
// there's not a reliable way to determine this
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool MutexDirect::
|
||||
debug_is_locked() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::set_name
|
||||
// Access: Public
|
||||
// Description: The mutex name is only defined when compiling in
|
||||
// DEBUG_THREADS mode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void MutexDirect::
|
||||
set_name(const string &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::clear_name
|
||||
// Access: Public
|
||||
// Description: The mutex name is only defined when compiling in
|
||||
// DEBUG_THREADS mode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void MutexDirect::
|
||||
clear_name() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::has_name
|
||||
// Access: Public
|
||||
// Description: The mutex name is only defined when compiling in
|
||||
// DEBUG_THREADS mode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool MutexDirect::
|
||||
has_name() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::get_name
|
||||
// Access: Public
|
||||
// Description: The mutex name is only defined when compiling in
|
||||
// DEBUG_THREADS mode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string MutexDirect::
|
||||
get_name() const {
|
||||
return string();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,11 @@ PUBLISHED:
|
|||
INLINE void release() const;
|
||||
INLINE bool debug_is_locked() const;
|
||||
|
||||
INLINE void set_name(const string &name);
|
||||
INLINE void clear_name();
|
||||
INLINE bool has_name() const;
|
||||
INLINE string get_name() const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -46,7 +46,13 @@ do_lock() {
|
|||
void MutexSimpleImpl::
|
||||
do_release() {
|
||||
ThreadSimpleManager *manager = ThreadSimpleManager::get_global_ptr();
|
||||
manager->unblock_one(this);
|
||||
if (manager->unblock_one(this)) {
|
||||
// There had been a thread waiting on this mutex. Switch contexts
|
||||
// immediately, to make fairness more likely.
|
||||
ThreadSimpleImpl *thread = manager->get_current_thread();
|
||||
manager->enqueue_ready(thread);
|
||||
manager->next_context();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // THREAD_SIMPLE_IMPL
|
||||
|
|
|
|||
|
|
@ -165,6 +165,48 @@ debug_is_locked() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::set_name
|
||||
// Access: Public
|
||||
// Description: The mutex name is only defined when compiling in
|
||||
// DEBUG_THREADS mode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutexDirect::
|
||||
set_name(const string &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::clear_name
|
||||
// Access: Public
|
||||
// Description: The mutex name is only defined when compiling in
|
||||
// DEBUG_THREADS mode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutexDirect::
|
||||
clear_name() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::has_name
|
||||
// Access: Public
|
||||
// Description: The mutex name is only defined when compiling in
|
||||
// DEBUG_THREADS mode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool ReMutexDirect::
|
||||
has_name() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::get_name
|
||||
// Access: Public
|
||||
// Description: The mutex name is only defined when compiling in
|
||||
// DEBUG_THREADS mode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string ReMutexDirect::
|
||||
get_name() const {
|
||||
return string();
|
||||
}
|
||||
|
||||
#ifndef HAVE_REMUTEXIMPL
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::do_lock
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ PUBLISHED:
|
|||
|
||||
INLINE bool debug_is_locked() const;
|
||||
|
||||
INLINE void set_name(const string &name);
|
||||
INLINE void clear_name();
|
||||
INLINE bool has_name() const;
|
||||
INLINE string get_name() const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -245,11 +245,10 @@ call_python_func(PyObject *function, PyObject *args) {
|
|||
|
||||
} else {
|
||||
#ifdef SIMPLE_THREADS
|
||||
// We can't use the PyGILState interface, which assumes we are using
|
||||
// true OS-level threading (and we might be just using
|
||||
// SIMPLE_THREADS). PyGILState enforces policies like only one
|
||||
// thread state per OS-level thread, which is not true in the case
|
||||
// of SIMPLE_THREADS.
|
||||
// We can't use the PyGILState interface, which assumes we are
|
||||
// using true OS-level threading. PyGILState enforces policies
|
||||
// like only one thread state per OS-level thread, which is not
|
||||
// true in the case of SIMPLE_THREADS.
|
||||
|
||||
PyThreadState *orig_thread_state = PyThreadState_Get();
|
||||
PyInterpreterState *istate = orig_thread_state->interp;
|
||||
|
|
|
|||
|
|
@ -106,16 +106,17 @@ enqueue_block(ThreadSimpleImpl *thread, BlockerSimple *blocker) {
|
|||
// Function: ThreadSimpleManager::unblock_one
|
||||
// Access: Public
|
||||
// Description: Unblocks one thread waiting on the indicated blocker,
|
||||
// if any.
|
||||
// if any. Returns true if anything was unblocked,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ThreadSimpleManager::
|
||||
bool ThreadSimpleManager::
|
||||
unblock_one(BlockerSimple *blocker) {
|
||||
Blocked::iterator bi = _blocked.find(blocker);
|
||||
if (bi != _blocked.end()) {
|
||||
nassertv(blocker->_flags & BlockerSimple::F_has_waiters);
|
||||
nassertr(blocker->_flags & BlockerSimple::F_has_waiters, false);
|
||||
|
||||
FifoThreads &threads = (*bi).second;
|
||||
nassertv(!threads.empty());
|
||||
nassertr(!threads.empty(), false);
|
||||
ThreadSimpleImpl *thread = threads.front();
|
||||
threads.pop_front();
|
||||
_ready.push_back(thread);
|
||||
|
|
@ -123,23 +124,27 @@ unblock_one(BlockerSimple *blocker) {
|
|||
blocker->_flags &= ~BlockerSimple::F_has_waiters;
|
||||
_blocked.erase(bi);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ThreadSimpleManager::unblock_all
|
||||
// Access: Public
|
||||
// Description: Unblocks all threads waiting on the indicated
|
||||
// blocker.
|
||||
// blocker. Returns true if anything was unblocked,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ThreadSimpleManager::
|
||||
bool ThreadSimpleManager::
|
||||
unblock_all(BlockerSimple *blocker) {
|
||||
Blocked::iterator bi = _blocked.find(blocker);
|
||||
if (bi != _blocked.end()) {
|
||||
nassertv(blocker->_flags & BlockerSimple::F_has_waiters);
|
||||
nassertr(blocker->_flags & BlockerSimple::F_has_waiters, false);
|
||||
|
||||
FifoThreads &threads = (*bi).second;
|
||||
nassertv(!threads.empty());
|
||||
nassertr(!threads.empty(), false);
|
||||
while (!threads.empty()) {
|
||||
ThreadSimpleImpl *thread = threads.front();
|
||||
threads.pop_front();
|
||||
|
|
@ -147,7 +152,9 @@ unblock_all(BlockerSimple *blocker) {
|
|||
}
|
||||
blocker->_flags &= ~BlockerSimple::F_has_waiters;
|
||||
_blocked.erase(bi);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ public:
|
|||
void enqueue_ready(ThreadSimpleImpl *thread);
|
||||
void enqueue_sleep(ThreadSimpleImpl *thread, double seconds);
|
||||
void enqueue_block(ThreadSimpleImpl *thread, BlockerSimple *blocker);
|
||||
void unblock_one(BlockerSimple *blocker);
|
||||
void unblock_all(BlockerSimple *blocker);
|
||||
bool unblock_one(BlockerSimple *blocker);
|
||||
bool unblock_all(BlockerSimple *blocker);
|
||||
void enqueue_finished(ThreadSimpleImpl *thread);
|
||||
void preempt(ThreadSimpleImpl *thread);
|
||||
void next_context();
|
||||
|
|
|
|||
|
|
@ -26,17 +26,17 @@ TypeHandle CopyOnWriteObj1<Base, Param1>::_type_handle;
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CopyOnWriteObject::
|
||||
CopyOnWriteObject()
|
||||
#ifdef HAVE_THREADS
|
||||
#ifdef COW_THREADED
|
||||
: _lock_cvar(_lock_mutex)
|
||||
#endif
|
||||
{
|
||||
#ifdef DO_MEMORY_USAGE
|
||||
MemoryUsage::update_type(this, this);
|
||||
#endif
|
||||
#ifdef HAVE_THREADS
|
||||
#ifdef COW_THREADED
|
||||
_lock_status = LS_unlocked;
|
||||
_locking_thread = NULL;
|
||||
#endif // HAVE_THREADS
|
||||
#endif // COW_THREADED
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -47,17 +47,17 @@ CopyOnWriteObject()
|
|||
INLINE CopyOnWriteObject::
|
||||
CopyOnWriteObject(const CopyOnWriteObject ©) :
|
||||
CachedTypedWritableReferenceCount(copy)
|
||||
#ifdef HAVE_THREADS
|
||||
#ifdef COW_THREADED
|
||||
, _lock_cvar(_lock_mutex)
|
||||
#endif
|
||||
{
|
||||
#ifdef DO_MEMORY_USAGE
|
||||
MemoryUsage::update_type(this, this);
|
||||
#endif
|
||||
#ifdef HAVE_THREADS
|
||||
#ifdef COW_THREADED
|
||||
_lock_status = LS_unlocked;
|
||||
_locking_thread = NULL;
|
||||
#endif // HAVE_THREADS
|
||||
#endif // COW_THREADED
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -70,7 +70,7 @@ operator = (const CopyOnWriteObject ©) {
|
|||
CachedTypedWritableReferenceCount::operator = (copy);
|
||||
}
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
#ifdef COW_THREADED
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CopyOnWriteObject::cache_ref
|
||||
// Access: Published
|
||||
|
|
@ -81,7 +81,7 @@ cache_ref() const {
|
|||
MutexHolder holder(_lock_mutex);
|
||||
CachedTypedWritableReferenceCount::cache_ref();
|
||||
}
|
||||
#endif // HAVE_THREADS
|
||||
#endif // COW_THREADED
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CopyOnWriteObj::Constructor
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
TypeHandle CopyOnWriteObject::_type_handle;
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
#ifdef COW_THREADED
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CopyOnWriteObject::unref
|
||||
// Access: Public
|
||||
|
|
@ -40,4 +40,4 @@ unref() const {
|
|||
}
|
||||
return is_zero;
|
||||
}
|
||||
#endif // HAVE_THREADS
|
||||
#endif // COW_THREADED
|
||||
|
|
|
|||
|
|
@ -22,6 +22,15 @@
|
|||
#include "conditionVar.h"
|
||||
#include "mutexHolder.h"
|
||||
|
||||
// Should we implement full thread protection for CopyOnWritePointer?
|
||||
// If we can be assured that no other thread will interrupt while a
|
||||
// write pointer is held, we don't need thread protection.
|
||||
#if defined(HAVE_THREADS) && !(defined(SIMPLE_THREADS) && defined(SIMPLE_THREADS_NO_MUTEX))
|
||||
#define COW_THREADED 1
|
||||
#else
|
||||
#undef COW_THREADED
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CopyOnWriteObject
|
||||
// Description : This base class provides basic reference counting,
|
||||
|
|
@ -35,16 +44,16 @@ public:
|
|||
INLINE void operator = (const CopyOnWriteObject ©);
|
||||
|
||||
PUBLISHED:
|
||||
#ifdef HAVE_THREADS
|
||||
#ifdef COW_THREADED
|
||||
bool unref() const;
|
||||
INLINE void cache_ref() const;
|
||||
#endif // HAVE_THREADS
|
||||
#endif // COW_THREADED
|
||||
|
||||
protected:
|
||||
virtual PT(CopyOnWriteObject) make_cow_copy()=0;
|
||||
|
||||
private:
|
||||
#ifdef HAVE_THREADS
|
||||
#ifdef COW_THREADED
|
||||
enum LockStatus {
|
||||
LS_unlocked,
|
||||
LS_locked_read,
|
||||
|
|
@ -54,7 +63,7 @@ private:
|
|||
ConditionVar _lock_cvar;
|
||||
LockStatus _lock_status;
|
||||
Thread *_locking_thread;
|
||||
#endif // HAVE_THREADS
|
||||
#endif // COW_THREADED
|
||||
|
||||
public:
|
||||
virtual TypeHandle get_type() const {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ get_read_pointer() const {
|
|||
}
|
||||
|
||||
_object->_lock_status = CopyOnWriteObject::LS_locked_read;
|
||||
_object->_locking_thread = Thread::get_current_thread();
|
||||
_object->_locking_thread = current_thread;
|
||||
return _object;
|
||||
}
|
||||
#endif // COW_THREADED
|
||||
|
|
@ -129,7 +129,7 @@ get_write_pointer() {
|
|||
// have saved himself a reference.
|
||||
}
|
||||
_object->_lock_status = CopyOnWriteObject::LS_locked_write;
|
||||
_object->_locking_thread = Thread::get_current_thread();
|
||||
_object->_locking_thread = current_thread;
|
||||
|
||||
return _object;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,15 +21,6 @@
|
|||
#include "pointerTo.h"
|
||||
#include "dcast.h"
|
||||
|
||||
// Should we implement full thread protection for CopyOnWritePointer?
|
||||
// If we can be assured that no other thread will interrupt while a
|
||||
// write pointer is held, we don't need thread protection.
|
||||
#if defined(HAVE_THREADS) && !(defined(SIMPLE_THREADS) && defined(SIMPLE_THREADS_NO_MUTEX))
|
||||
#define COW_THREADED 1
|
||||
#else
|
||||
#undef COW_THREADED
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CopyOnWritePointer
|
||||
// Description : This safely stores the primary, owned pointer to a
|
||||
|
|
|
|||
|
|
@ -620,7 +620,9 @@ is_renderable() const {
|
|||
// thing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TextNode::
|
||||
compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
||||
compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const {
|
||||
// First, get ourselves a fresh, empty bounding volume.
|
||||
PT(BoundingVolume) bound = new BoundingSphere;
|
||||
|
|
@ -644,9 +646,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
|||
|
||||
gbv->around(vertices, vertices + 8);
|
||||
|
||||
bdata->_internal_bounds = bound;
|
||||
bdata->_internal_vertices = 0; // TODO: estimate this better.
|
||||
bdata->_internal_bounds_stale = false;
|
||||
internal_bounds = bound;
|
||||
internal_vertices = 0; // TODO: estimate this better.
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -659,16 +660,17 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void TextNode::
|
||||
r_prepare_scene(const RenderState *state,
|
||||
PreparedGraphicsObjects *prepared_objects) {
|
||||
PreparedGraphicsObjects *prepared_objects,
|
||||
Thread *current_thread) {
|
||||
check_rebuild();
|
||||
|
||||
PandaNode *child = _internal_geom;
|
||||
if (child != (PandaNode *)NULL) {
|
||||
CPT(RenderState) child_state = state->compose(child->get_state());
|
||||
child->r_prepare_scene(child_state, prepared_objects);
|
||||
child->r_prepare_scene(child_state, prepared_objects, current_thread);
|
||||
}
|
||||
|
||||
PandaNode::r_prepare_scene(state, prepared_objects);
|
||||
PandaNode::r_prepare_scene(state, prepared_objects, current_thread);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -239,11 +239,14 @@ public:
|
|||
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
|
||||
virtual bool is_renderable() const;
|
||||
|
||||
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
|
||||
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||||
int &internal_vertices,
|
||||
int pipeline_stage,
|
||||
Thread *current_thread) const;
|
||||
|
||||
virtual void r_prepare_scene(const RenderState *state,
|
||||
PreparedGraphicsObjects *prepared_objects);
|
||||
PreparedGraphicsObjects *prepared_objects,
|
||||
Thread *current_thread);
|
||||
|
||||
private:
|
||||
INLINE void invalidate_no_measure();
|
||||
|
|
|
|||
Loading…
Reference in New Issue