more threading improvements

This commit is contained in:
David Rose 2008-10-02 17:50:16 +00:00
parent eaa1318450
commit fab502970f
70 changed files with 1122 additions and 497 deletions

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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);

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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:

View File

@ -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();

View File

@ -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",

View File

@ -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();

View File

@ -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);
}

View File

@ -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 {

View File

@ -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)

View File

@ -25,7 +25,7 @@ EventQueue *EventQueue::_global_event_queue = NULL;
// Description:
////////////////////////////////////////////////////////////////////
EventQueue::
EventQueue() : _lock("EventQueue") {
EventQueue() : _lock("EventQueue::_lock") {
}
////////////////////////////////////////////////////////////////////

View File

@ -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,

View File

@ -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;
}

View File

@ -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),

View File

@ -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;

View File

@ -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.
}
////////////////////////////////////////////////////////////////////

View File

@ -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:

View File

@ -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.
}
////////////////////////////////////////////////////////////////////

View File

@ -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:

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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:

View File

@ -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");
}

View File

@ -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);

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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);

View File

@ -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),

View File

@ -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);

View File

@ -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 &copy) :
_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 &copy) {
_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

View File

@ -162,7 +162,9 @@ PandaNode(const PandaNode &copy) :
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;
}

View File

@ -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 &copy);
INLINE void copy_bounds(const BoundsData &copy);
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:

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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);

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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:

View File

@ -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;
}

View File

@ -69,6 +69,7 @@ PGButton(const PGButton &copy) :
////////////////////////////////////////////////////////////////////
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 &param) {
ReMutexHolder holder(_lock);
if (get_active()) {
set_state(_button_down ? S_depressed : S_rollover);
}
@ -94,6 +96,7 @@ enter_region(const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
void PGButton::
exit_region(const MouseWatcherParameter &param) {
ReMutexHolder holder(_lock);
if (get_active()) {
set_state(S_ready);
}
@ -109,6 +112,7 @@ exit_region(const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
void PGButton::
press(const MouseWatcherParameter &param, 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 &param, bool background) {
////////////////////////////////////////////////////////////////////
void PGButton::
release(const MouseWatcherParameter &param, 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 &param, bool background) {
////////////////////////////////////////////////////////////////////
void PGButton::
click(const MouseWatcherParameter &param) {
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 &param) {
////////////////////////////////////////////////////////////////////
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);
}

View File

@ -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;
}

View File

@ -124,6 +124,7 @@ PGEntry(const PGEntry &copy) :
////////////////////////////////////////////////////////////////////
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 &param, 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 &param, bool background) {
////////////////////////////////////////////////////////////////////
void PGEntry::
keystroke(const MouseWatcherParameter &param, 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 &param, bool background) {
////////////////////////////////////////////////////////////////////
void PGEntry::
candidate(const MouseWatcherParameter &param, 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 &param, bool background) {
////////////////////////////////////////////////////////////////////
void PGEntry::
accept(const MouseWatcherParameter &param) {
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 &param) {
////////////////////////////////////////////////////////////////////
void PGEntry::
accept_failed(const MouseWatcherParameter &param) {
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 &param) {
////////////////////////////////////////////////////////////////////
void PGEntry::
overflow(const MouseWatcherParameter &param) {
ReMutexHolder holder(_lock);
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
string event = get_overflow_event();
play_sound(event);
@ -472,6 +481,7 @@ overflow(const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
void PGEntry::
type(const MouseWatcherParameter &param) {
ReMutexHolder holder(_lock);
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
string event = get_type_event();
play_sound(event);
@ -486,6 +496,7 @@ type(const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
void PGEntry::
erase(const MouseWatcherParameter &param) {
ReMutexHolder holder(_lock);
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
string event = get_erase_event();
play_sound(event);
@ -503,6 +514,7 @@ erase(const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
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) {

View File

@ -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;
}

View File

@ -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 &copy) :
////////////////////////////////////////////////////////////////////
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 &param) {
ReMutexHolder holder(_lock);
if (pgui_cat.is_debug()) {
pgui_cat.debug()
<< *this << "::enter_region(" << param << ")\n";
@ -529,6 +541,7 @@ enter_region(const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
void PGItem::
exit_region(const MouseWatcherParameter &param) {
ReMutexHolder holder(_lock);
if (pgui_cat.is_debug()) {
pgui_cat.debug()
<< *this << "::exit_region(" << param << ")\n";
@ -558,6 +571,7 @@ exit_region(const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
void PGItem::
within_region(const MouseWatcherParameter &param) {
ReMutexHolder holder(_lock);
if (pgui_cat.is_debug()) {
pgui_cat.debug()
<< *this << "::within_region(" << param << ")\n";
@ -582,6 +596,7 @@ within_region(const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
void PGItem::
without_region(const MouseWatcherParameter &param) {
ReMutexHolder holder(_lock);
if (pgui_cat.is_debug()) {
pgui_cat.debug()
<< *this << "::without_region(" << param << ")\n";
@ -605,6 +620,7 @@ without_region(const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
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 &param, 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 &param, bool background) {
////////////////////////////////////////////////////////////////////
void PGItem::
release(const MouseWatcherParameter &param, 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 &param, bool background) {
////////////////////////////////////////////////////////////////////
void PGItem::
keystroke(const MouseWatcherParameter &param, 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 &param, bool background) {
////////////////////////////////////////////////////////////////////
void PGItem::
candidate(const MouseWatcherParameter &param, 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 &param, bool background) {
////////////////////////////////////////////////////////////////////
void PGItem::
move(const MouseWatcherParameter &param) {
ReMutexHolder holder(_lock);
if (pgui_cat.is_debug()) {
pgui_cat.debug()
<< *this << "::move(" << param << ")\n";
@ -841,6 +863,7 @@ background_candidate(const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
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;

View File

@ -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 &copy);
@ -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;

View File

@ -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();
}

View File

@ -76,6 +76,7 @@ PGScrollFrame(const PGScrollFrame &copy) :
////////////////////////////////////////////////////////////////////
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();

View File

@ -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();
}

View File

@ -98,6 +98,7 @@ PGSliderBar(const PGSliderBar &copy) :
////////////////////////////////////////////////////////////////////
PandaNode *PGSliderBar::
make_copy() const {
ReMutexHolder holder(_lock);
return new PGSliderBar(*this);
}
@ -110,6 +111,7 @@ make_copy() const {
////////////////////////////////////////////////////////////////////
void PGSliderBar::
press(const MouseWatcherParameter &param, bool background) {
ReMutexHolder holder(_lock);
if (param.has_mouse()) {
_mouse_pos = param.get_mouse();
}
@ -138,6 +140,7 @@ press(const MouseWatcherParameter &param, bool background) {
////////////////////////////////////////////////////////////////////
void PGSliderBar::
release(const MouseWatcherParameter &param, bool background) {
ReMutexHolder holder(_lock);
if (MouseButton::is_mouse_button(param.get_button())) {
_mouse_button_page = false;
}
@ -155,6 +158,7 @@ release(const MouseWatcherParameter &param, bool background) {
////////////////////////////////////////////////////////////////////
void PGSliderBar::
move(const MouseWatcherParameter &param) {
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 &param) {
////////////////////////////////////////////////////////////////////
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 &param) {
ReMutexHolder holder(_lock);
if (param.has_mouse()) {
_mouse_pos = param.get_mouse();
}
@ -648,6 +678,7 @@ item_press(PGItem *item, const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
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 &param) {
ReMutexHolder holder(_lock);
_mouse_pos = param.get_mouse();
if (item == _thumb_button) {
if (_dragging) {

View File

@ -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;
}

View File

@ -72,6 +72,7 @@ PGVirtualFrame(const PGVirtualFrame &copy) :
////////////////////////////////////////////////////////////////////
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;

View File

@ -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;
}

View File

@ -67,6 +67,7 @@ PGWaitBar(const PGWaitBar &copy) :
////////////////////////////////////////////////////////////////////
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

View File

@ -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

View File

@ -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

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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();
}

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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;

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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();

View File

@ -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 &copy) :
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 &copy) {
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

View File

@ -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

View File

@ -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 &copy);
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 {

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
////////////////////////////////////////////////////////////////////

View File

@ -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();