Panda3D
|
00001 // Filename: mouseWatcherGroup.cxx 00002 // Created by: drose (02Jul01) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "mouseWatcherGroup.h" 00016 #include "lineSegs.h" 00017 #include "indent.h" 00018 #include "lightMutexHolder.h" 00019 00020 TypeHandle MouseWatcherGroup::_type_handle; 00021 00022 //////////////////////////////////////////////////////////////////// 00023 // Function: MouseWatcherGroup::Constructor 00024 // Access: Public 00025 // Description: 00026 //////////////////////////////////////////////////////////////////// 00027 MouseWatcherGroup:: 00028 MouseWatcherGroup() : 00029 _lock("MouseWatcherGroup") 00030 { 00031 _sorted = true; 00032 #ifndef NDEBUG 00033 _show_regions = false; 00034 _color.set(0.4, 0.6f, 1.0f, 1.0f); 00035 #endif // NDEBUG 00036 } 00037 00038 //////////////////////////////////////////////////////////////////// 00039 // Function: MouseWatcherGroup::Destructor 00040 // Access: Public, Virtual 00041 // Description: 00042 //////////////////////////////////////////////////////////////////// 00043 MouseWatcherGroup:: 00044 ~MouseWatcherGroup() { 00045 } 00046 00047 //////////////////////////////////////////////////////////////////// 00048 // Function: MouseWatcherGroup::add_region 00049 // Access: Published 00050 // Description: Adds the indicated region to the set of regions in 00051 // the group. It is an error to add the same region to 00052 // the set more than once. 00053 //////////////////////////////////////////////////////////////////// 00054 void MouseWatcherGroup:: 00055 add_region(MouseWatcherRegion *region) { 00056 PT(MouseWatcherRegion) pt = region; 00057 00058 LightMutexHolder holder(_lock); 00059 00060 // We will only bother to check for duplicates in the region list if 00061 // we are building a development Panda. The overhead for doing this 00062 // may be too high if we have many regions. 00063 #ifdef _DEBUG 00064 // See if the region is in the set/vector already 00065 Regions::const_iterator ri = 00066 find(_regions.begin(), _regions.end(), pt); 00067 nassertv(ri == _regions.end()); 00068 #endif // _DEBUG 00069 00070 #ifndef NDEBUG 00071 // Also add it to the vizzes if we have them. 00072 if (_show_regions) { 00073 nassertv(_vizzes.size() == _regions.size()); 00074 _vizzes.push_back(make_viz_region(pt)); 00075 } 00076 #endif // NDEBUG 00077 00078 _regions.push_back(pt); 00079 _sorted = false; 00080 } 00081 00082 //////////////////////////////////////////////////////////////////// 00083 // Function: MouseWatcherGroup::has_region 00084 // Access: Published 00085 // Description: Returns true if the indicated region has already been 00086 // added to the MouseWatcherGroup, false otherwise. 00087 //////////////////////////////////////////////////////////////////// 00088 bool MouseWatcherGroup:: 00089 has_region(MouseWatcherRegion *region) const { 00090 LightMutexHolder holder(_lock); 00091 00092 PT(MouseWatcherRegion) ptr = region; 00093 00094 if (_sorted) { 00095 // If the vector is already sorted, we can do this the quick way. 00096 Regions::const_iterator ri = lower_bound(_regions.begin(), _regions.end(), ptr); 00097 return (ri != _regions.end() && (*ri) == ptr); 00098 } 00099 00100 // If the vector isn't sorted, do a linear scan. 00101 Regions::const_iterator ri = find(_regions.begin(), _regions.end(), ptr); 00102 return (ri != _regions.end()); 00103 } 00104 00105 //////////////////////////////////////////////////////////////////// 00106 // Function: MouseWatcherGroup::remove_region 00107 // Access: Published 00108 // Description: Removes the indicated region from the group. 00109 // Returns true if it was successfully removed, or false 00110 // if it wasn't there in the first place. 00111 //////////////////////////////////////////////////////////////////// 00112 bool MouseWatcherGroup:: 00113 remove_region(MouseWatcherRegion *region) { 00114 LightMutexHolder holder(_lock); 00115 return do_remove_region(region); 00116 } 00117 00118 //////////////////////////////////////////////////////////////////// 00119 // Function: MouseWatcherGroup::find_region 00120 // Access: Published 00121 // Description: Returns a pointer to the first region found with the 00122 // indicated name. If multiple regions share the same 00123 // name, the one that is returned is indeterminate. 00124 //////////////////////////////////////////////////////////////////// 00125 MouseWatcherRegion *MouseWatcherGroup:: 00126 find_region(const string &name) const { 00127 LightMutexHolder holder(_lock); 00128 00129 Regions::const_iterator ri; 00130 for (ri = _regions.begin(); ri != _regions.end(); ++ri) { 00131 MouseWatcherRegion *region = (*ri); 00132 if (region->get_name() == name) { 00133 return region; 00134 } 00135 } 00136 00137 return (MouseWatcherRegion *)NULL; 00138 } 00139 00140 //////////////////////////////////////////////////////////////////// 00141 // Function: MouseWatcherGroup::clear_regions 00142 // Access: Published 00143 // Description: Removes all the regions from the group. 00144 //////////////////////////////////////////////////////////////////// 00145 void MouseWatcherGroup:: 00146 clear_regions() { 00147 LightMutexHolder holder(_lock); 00148 00149 _regions.clear(); 00150 _sorted = true; 00151 00152 #ifndef NDEBUG 00153 if (_show_regions) { 00154 _show_regions_root.node()->remove_all_children(); 00155 _vizzes.clear(); 00156 } 00157 #endif // NDEBUG 00158 } 00159 00160 //////////////////////////////////////////////////////////////////// 00161 // Function: MouseWatcherGroup::sort_regions 00162 // Access: Published 00163 // Description: Sorts all the regions in this group into pointer 00164 // order. 00165 //////////////////////////////////////////////////////////////////// 00166 void MouseWatcherGroup:: 00167 sort_regions() { 00168 LightMutexHolder holder(_lock); 00169 do_sort_regions(); 00170 } 00171 00172 //////////////////////////////////////////////////////////////////// 00173 // Function: MouseWatcherGroup::is_sorted 00174 // Access: Published 00175 // Description: Returns true if the group has already been sorted, 00176 // false otherwise. 00177 //////////////////////////////////////////////////////////////////// 00178 bool MouseWatcherGroup:: 00179 is_sorted() const { 00180 LightMutexHolder holder(_lock); 00181 00182 return _sorted; 00183 } 00184 00185 //////////////////////////////////////////////////////////////////// 00186 // Function: MouseWatcherGroup::get_num_regions 00187 // Access: Published 00188 // Description: Returns the number of regions in the group. 00189 //////////////////////////////////////////////////////////////////// 00190 int MouseWatcherGroup:: 00191 get_num_regions() const { 00192 LightMutexHolder holder(_lock); 00193 00194 return _regions.size(); 00195 } 00196 00197 //////////////////////////////////////////////////////////////////// 00198 // Function: MouseWatcherGroup::get_region 00199 // Access: Published 00200 // Description: Returns the nth region of the group; returns NULL if 00201 // there is no nth region. Note that this is not 00202 // thread-safe; another thread might have removed the 00203 // nth region before you called this method. 00204 //////////////////////////////////////////////////////////////////// 00205 MouseWatcherRegion *MouseWatcherGroup:: 00206 get_region(int n) const { 00207 LightMutexHolder holder(_lock); 00208 if (n >= 0 && n < (int)_regions.size()) { 00209 return _regions[n]; 00210 } 00211 return NULL; 00212 } 00213 00214 //////////////////////////////////////////////////////////////////// 00215 // Function: MouseWatcherGroup::output 00216 // Access: Published 00217 // Description: 00218 //////////////////////////////////////////////////////////////////// 00219 void MouseWatcherGroup:: 00220 output(ostream &out) const { 00221 out << "MouseWatcherGroup (" << _regions.size() << " regions)"; 00222 } 00223 00224 //////////////////////////////////////////////////////////////////// 00225 // Function: MouseWatcherGroup::write 00226 // Access: Published 00227 // Description: 00228 //////////////////////////////////////////////////////////////////// 00229 void MouseWatcherGroup:: 00230 write(ostream &out, int indent_level) const { 00231 LightMutexHolder holder(_lock); 00232 00233 Regions::const_iterator ri; 00234 for (ri = _regions.begin(); ri != _regions.end(); ++ri) { 00235 MouseWatcherRegion *region = (*ri); 00236 region->write(out, indent_level); 00237 } 00238 } 00239 00240 #ifndef NDEBUG 00241 //////////////////////////////////////////////////////////////////// 00242 // Function: MouseWatcherGroup::show_regions 00243 // Access: Published 00244 // Description: Enables the visualization of all of the regions 00245 // handled by this MouseWatcherGroup. The supplied 00246 // NodePath should be the root of the 2-d scene graph 00247 // for the window. 00248 //////////////////////////////////////////////////////////////////// 00249 void MouseWatcherGroup:: 00250 show_regions(const NodePath &render2d, const string &bin_name, int draw_order) { 00251 LightMutexHolder holder(_lock); 00252 do_show_regions(render2d, bin_name, draw_order); 00253 } 00254 #endif // NDEBUG 00255 00256 #ifndef NDEBUG 00257 //////////////////////////////////////////////////////////////////// 00258 // Function: MouseWatcherGroup::set_color 00259 // Access: Published 00260 // Description: Specifies the color used to draw the region 00261 // rectangles for the regions visualized by 00262 // show_regions(). 00263 //////////////////////////////////////////////////////////////////// 00264 void MouseWatcherGroup:: 00265 set_color(const LColor &color) { 00266 LightMutexHolder holder(_lock); 00267 00268 _color = color; 00269 do_update_regions(); 00270 } 00271 #endif // NDEBUG 00272 00273 #ifndef NDEBUG 00274 //////////////////////////////////////////////////////////////////// 00275 // Function: MouseWatcherGroup::hide_regions 00276 // Access: Published 00277 // Description: Stops the visualization created by a previous call to 00278 // show_regions(). 00279 //////////////////////////////////////////////////////////////////// 00280 void MouseWatcherGroup:: 00281 hide_regions() { 00282 LightMutexHolder holder(_lock); 00283 do_hide_regions(); 00284 } 00285 #endif // NDEBUG 00286 00287 #ifndef NDEBUG 00288 //////////////////////////////////////////////////////////////////// 00289 // Function: MouseWatcherGroup::update_regions 00290 // Access: Published 00291 // Description: Refreshes the visualization created by 00292 // show_regions(). 00293 //////////////////////////////////////////////////////////////////// 00294 void MouseWatcherGroup:: 00295 update_regions() { 00296 LightMutexHolder holder(_lock); 00297 do_update_regions(); 00298 } 00299 #endif // NDEBUG 00300 00301 00302 //////////////////////////////////////////////////////////////////// 00303 // Function: MouseWatcherGroup::do_sort_regions 00304 // Access: Protected 00305 // Description: Sorts all the regions in this group into pointer 00306 // order. Assumes the lock is already held. 00307 //////////////////////////////////////////////////////////////////// 00308 void MouseWatcherGroup:: 00309 do_sort_regions() { 00310 if (!_sorted) { 00311 sort(_regions.begin(), _regions.end()); 00312 _sorted = true; 00313 } 00314 } 00315 00316 //////////////////////////////////////////////////////////////////// 00317 // Function: MouseWatcherGroup::do_remove_region 00318 // Access: Protected 00319 // Description: The internal implementation of remove_region(); 00320 // assumes the lock is already held. 00321 //////////////////////////////////////////////////////////////////// 00322 bool MouseWatcherGroup:: 00323 do_remove_region(MouseWatcherRegion *region) { 00324 // See if the region is in the vector. 00325 PT(MouseWatcherRegion) ptr = region; 00326 Regions::iterator ri; 00327 00328 if (_sorted) { 00329 // Faster, binary search 00330 ri = lower_bound(_regions.begin(), _regions.end(), ptr); 00331 } else { 00332 // Unsorted, so use slower linear scan 00333 ri = find(_regions.begin(), _regions.end(), ptr); 00334 } 00335 00336 if (ri != _regions.end() && (*ri) == ptr) { 00337 // Found it, now erase it 00338 #ifndef NDEBUG 00339 // Also remove it from the vizzes. 00340 if (_show_regions) { 00341 nassertr(_vizzes.size() == _regions.size(), false); 00342 size_t index = ri - _regions.begin(); 00343 Vizzes::iterator vi = _vizzes.begin() + index; 00344 _show_regions_root.node()->remove_child(*vi); 00345 _vizzes.erase(vi); 00346 } 00347 #endif // NDEBUG 00348 00349 _regions.erase(ri); 00350 return true; 00351 } 00352 00353 // Did not find the region to erase 00354 return false; 00355 } 00356 00357 #ifndef NDEBUG 00358 //////////////////////////////////////////////////////////////////// 00359 // Function: MouseWatcherGroup::do_show_regions 00360 // Access: Protected, Virtual 00361 // Description: The protected implementation of show_regions(). This 00362 // assumes the lock is already held. 00363 //////////////////////////////////////////////////////////////////// 00364 void MouseWatcherGroup:: 00365 do_show_regions(const NodePath &render2d, const string &bin_name, 00366 int draw_order) { 00367 do_hide_regions(); 00368 _show_regions = true; 00369 _show_regions_root = render2d.attach_new_node("show_regions"); 00370 _show_regions_root.set_bin(bin_name, draw_order); 00371 do_update_regions(); 00372 } 00373 #endif // NDEBUG 00374 00375 #ifndef NDEBUG 00376 //////////////////////////////////////////////////////////////////// 00377 // Function: MouseWatcherGroup::do_hide_regions 00378 // Access: Protected, Virtual 00379 // Description: The protected implementation of hide_regions(). This 00380 // assumes the lock is already held. 00381 //////////////////////////////////////////////////////////////////// 00382 void MouseWatcherGroup:: 00383 do_hide_regions() { 00384 _show_regions_root.remove_node(); 00385 _show_regions = false; 00386 _vizzes.clear(); 00387 } 00388 #endif // NDEBUG 00389 00390 00391 #ifndef NDEBUG 00392 //////////////////////////////////////////////////////////////////// 00393 // Function: MouseWatcherGroup::do_update_regions 00394 // Access: Protected 00395 // Description: Internally regenerates the show_regions() 00396 // visualization. Assumes the lock is already held. 00397 //////////////////////////////////////////////////////////////////// 00398 void MouseWatcherGroup:: 00399 do_update_regions() { 00400 nassertv(_lock.debug_is_locked()); 00401 00402 if (_show_regions) { 00403 _show_regions_root.node()->remove_all_children(); 00404 _vizzes.clear(); 00405 _vizzes.reserve(_regions.size()); 00406 00407 Regions::const_iterator ri; 00408 for (ri = _regions.begin(); ri != _regions.end(); ++ri) { 00409 _vizzes.push_back(make_viz_region(*ri)); 00410 } 00411 } 00412 } 00413 #endif // NDEBUG 00414 00415 00416 #ifndef NDEBUG 00417 //////////////////////////////////////////////////////////////////// 00418 // Function: MouseWatcherGroup::make_viz_region 00419 // Access: Private 00420 // Description: Creates a node to represent the indicated region, and 00421 // attaches it to the _show_regions_root. Does not add 00422 // it to _vizzes. Assumes the lock is already held. 00423 //////////////////////////////////////////////////////////////////// 00424 PandaNode *MouseWatcherGroup:: 00425 make_viz_region(MouseWatcherRegion *region) { 00426 nassertr(_lock.debug_is_locked(), NULL); 00427 00428 LineSegs ls("show_regions"); 00429 ls.set_color(_color); 00430 00431 const LVecBase4 &f = region->get_frame(); 00432 00433 ls.move_to(LVector3::rfu(f[0], 0.0f, f[2])); 00434 ls.draw_to(LVector3::rfu(f[1], 0.0f, f[2])); 00435 ls.draw_to(LVector3::rfu(f[1], 0.0f, f[3])); 00436 ls.draw_to(LVector3::rfu(f[0], 0.0f, f[3])); 00437 ls.draw_to(LVector3::rfu(f[0], 0.0f, f[2])); 00438 00439 PT(PandaNode) node = ls.create(); 00440 _show_regions_root.attach_new_node(node); 00441 00442 return node; 00443 } 00444 #endif // NDEBUG