00001 // Filename: parametricCurveDrawer.cxx 00002 // Created by: drose (14Mar97) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 00020 #include "parametricCurveDrawer.h" 00021 #include "parametricCurve.h" 00022 #include "config_parametrics.h" 00023 00024 TypeHandle ParametricCurveDrawer::_type_handle; 00025 00026 //////////////////////////////////////////////////////////////////// 00027 // Function: ParametricCurveDrawer::Constructor 00028 // Access: Published 00029 // Description: 00030 //////////////////////////////////////////////////////////////////// 00031 ParametricCurveDrawer:: 00032 ParametricCurveDrawer() { 00033 _lines.set_color(1.0f, 1.0f, 1.0f); 00034 _ticks.set_color(1.0f, 0.0f, 0.0f); 00035 _tick_scale = 0.1; 00036 _num_segs = 100.0; 00037 _num_ticks = 0.0f; 00038 _frame_accurate = false; 00039 _geom_node = new GeomNode("pcd"); 00040 _drawn = false; 00041 } 00042 00043 //////////////////////////////////////////////////////////////////// 00044 // Function: ParametricCurveDrawer::Destructor 00045 // Access: Published, Virtual 00046 // Description: 00047 //////////////////////////////////////////////////////////////////// 00048 ParametricCurveDrawer:: 00049 ~ParametricCurveDrawer() { 00050 hide(); 00051 00052 // Unregister all the curves. 00053 clear_curves(); 00054 } 00055 00056 00057 //////////////////////////////////////////////////////////////////// 00058 // Function: ParametricCurveDrawer::set_curve 00059 // Access: Published 00060 // Description: Sets the drawer up to draw just the one curve. 00061 //////////////////////////////////////////////////////////////////// 00062 void ParametricCurveDrawer:: 00063 set_curve(ParametricCurve *curve) { 00064 PT(ParametricCurveCollection) curves = new ParametricCurveCollection(); 00065 curves->add_curve(curve); 00066 set_curves(curves); 00067 } 00068 00069 //////////////////////////////////////////////////////////////////// 00070 // Function: ParametricCurveDrawer::set_curves 00071 // Access: Published 00072 // Description: Sets the drawer up to draw the curves in the 00073 // indicated collection. The drawer will actually draw 00074 // just the first XYZ curve in the collection, but if 00075 // one or more timewarps are present, this will affect 00076 // the placement of tick marks. 00077 //////////////////////////////////////////////////////////////////// 00078 void ParametricCurveDrawer:: 00079 set_curves(ParametricCurveCollection *curves) { 00080 if (curves != _curves) { 00081 // First, unregister the old curves. 00082 if (_curves != (ParametricCurveCollection *)NULL) { 00083 _curves->unregister_drawer(this); 00084 } 00085 00086 _curves = curves; 00087 00088 // Now, register the new ones. 00089 if (_curves != (ParametricCurveCollection *)NULL) { 00090 _curves->register_drawer(this); 00091 } 00092 00093 redraw(); 00094 } 00095 } 00096 00097 //////////////////////////////////////////////////////////////////// 00098 // Function: ParametricCurveDrawer::clear_curves 00099 // Access: Published 00100 // Description: Empties the list of curves the drawer will update. 00101 // It will draw nothing. 00102 //////////////////////////////////////////////////////////////////// 00103 void ParametricCurveDrawer:: 00104 clear_curves() { 00105 set_curves((ParametricCurveCollection *)NULL); 00106 } 00107 00108 //////////////////////////////////////////////////////////////////// 00109 // Function: ParametricCurveDrawer::get_curves 00110 // Access: Published 00111 // Description: 00112 //////////////////////////////////////////////////////////////////// 00113 ParametricCurveCollection *ParametricCurveDrawer:: 00114 get_curves() { 00115 return _curves; 00116 } 00117 00118 00119 //////////////////////////////////////////////////////////////////// 00120 // Function: ParametricCurveDrawer::get_geom_node 00121 // Access: Published 00122 // Description: Returns a pointer to the drawer's GeomNode. This is 00123 // where the drawer will build the visible 00124 // representation of the curve. This GeomNode must be 00125 // inserted into the scene graph to make the curve 00126 // visible. The GeomNode remains connected to the drawer, 00127 // so that future updates to the drawer will reflect in 00128 // the GeomNode, and the GeomNode will be emptied when the 00129 // drawer destructs. Also see detach_geom_node(). 00130 //////////////////////////////////////////////////////////////////// 00131 GeomNode *ParametricCurveDrawer:: 00132 get_geom_node() { 00133 return _geom_node; 00134 } 00135 00136 00137 //////////////////////////////////////////////////////////////////// 00138 // Function: ParametricCurveDrawer::detach_geom_node 00139 // Access: Published 00140 // Description: Detaches the GeomNode from the drawer so that the 00141 // drawing will remain after the death of the drawer. 00142 // Returns the now-static GeomNode. A new, dynamic GeomNode 00143 // is created for the drawer's future use; get_geom_node() 00144 // will return this new GeomNode which will be empty until 00145 // the next call to draw(). 00146 //////////////////////////////////////////////////////////////////// 00147 PT(GeomNode) ParametricCurveDrawer:: 00148 detach_geom_node() { 00149 if (!_drawn) { 00150 draw(); 00151 } 00152 PT(GeomNode) g = _geom_node; 00153 _geom_node = new GeomNode("pcd"); 00154 _drawn = false; 00155 return g; 00156 } 00157 00158 00159 //////////////////////////////////////////////////////////////////// 00160 // Function: ParametricCurveDrawer::set_num_segs 00161 // Access: Published 00162 // Description: Specifies the number of line segments used to 00163 // approximate the curve for each parametric unit. This 00164 // just affects the visual appearance of the curve as it 00165 // is drawn. The total number of segments drawn for the 00166 // curve will be get_max_t() * get_num_segs(). 00167 //////////////////////////////////////////////////////////////////// 00168 void ParametricCurveDrawer:: 00169 set_num_segs(float num_segs) { 00170 _num_segs = num_segs; 00171 redraw(); 00172 } 00173 00174 //////////////////////////////////////////////////////////////////// 00175 // Function: ParametricCurveDrawer::get_num_segs 00176 // Access: Published 00177 // Description: Returns the number of line segments used to 00178 // approximate the curve for each parametric unit. This 00179 // just affects the visual appearance of the curve as it 00180 // is drawn. The total number of segments drawn for the 00181 // curve will be get_max_t() * get_num_segs(). 00182 //////////////////////////////////////////////////////////////////// 00183 float ParametricCurveDrawer:: 00184 get_num_segs() const { 00185 return _num_segs; 00186 } 00187 00188 00189 //////////////////////////////////////////////////////////////////// 00190 // Function: ParametricCurveDrawer::set_num_ticks 00191 // Access: Published 00192 // Description: Specifies the number of time tick marks drawn 00193 // for each unit of time. These tick marks are drawn at 00194 // equal increments in time to give a visual 00195 // approximation of speed. Specify 0 to disable drawing 00196 // of tick marks. 00197 //////////////////////////////////////////////////////////////////// 00198 void ParametricCurveDrawer:: 00199 set_num_ticks(float num_ticks) { 00200 _num_ticks = num_ticks; 00201 redraw(); 00202 } 00203 00204 //////////////////////////////////////////////////////////////////// 00205 // Function: ParametricCurveDrawer::get_num_ticks 00206 // Access: Published 00207 // Description: Returns the number of time tick marks per unit of 00208 // time drawn. 00209 //////////////////////////////////////////////////////////////////// 00210 float ParametricCurveDrawer:: 00211 get_num_ticks() const { 00212 return _num_ticks; 00213 } 00214 00215 00216 00217 //////////////////////////////////////////////////////////////////// 00218 // Function: ParametricCurveDrawer::set_color 00219 // Access: Published 00220 // Description: Specifies the color of the curve when it is drawn. 00221 // The default is white. 00222 //////////////////////////////////////////////////////////////////// 00223 void ParametricCurveDrawer:: 00224 set_color(float r, float g, float b) { 00225 _lines.set_color(r, g, b); 00226 } 00227 00228 00229 //////////////////////////////////////////////////////////////////// 00230 // Function: ParametricCurveDrawer::set_color 00231 // Access: Published 00232 // Description: Specifies the color of the time tick marks drawn on 00233 // the curve. The default is red. 00234 //////////////////////////////////////////////////////////////////// 00235 void ParametricCurveDrawer:: 00236 set_tick_color(float r, float g, float b) { 00237 _ticks.set_color(r, g, b); 00238 } 00239 00240 00241 //////////////////////////////////////////////////////////////////// 00242 // Function: ParametricCurveDrawer::set_frame_accurate 00243 // Access: Published 00244 // Description: Specifies whether the curve drawn is to be 00245 // frame-accurate. If true, then changes made to the 00246 // curve dynamically after it has been drawn will be 00247 // reflected correctly in the render window. If false, 00248 // dynamic updates may be drawn before the rest of the 00249 // scene has updated. 00250 //////////////////////////////////////////////////////////////////// 00251 void ParametricCurveDrawer:: 00252 set_frame_accurate(bool frame_accurate) { 00253 _frame_accurate = frame_accurate; 00254 redraw(); 00255 } 00256 00257 //////////////////////////////////////////////////////////////////// 00258 // Function: ParametricCurveDrawer::get_frame_accurate 00259 // Access: Published 00260 // Description: Returns whether the curve is drawn in frame-accurate 00261 // mode. 00262 //////////////////////////////////////////////////////////////////// 00263 bool ParametricCurveDrawer:: 00264 get_frame_accurate() const { 00265 return _frame_accurate; 00266 } 00267 00268 00269 00270 //////////////////////////////////////////////////////////////////// 00271 // Function: ParametricCurveDrawer::draw 00272 // Access: Published, Virtual 00273 // Description: Creates a series of line segments that approximates 00274 // the curve. These line segments may be made visible 00275 // by parenting the node returned by get_geom_node() 00276 // into the scene graph. 00277 //////////////////////////////////////////////////////////////////// 00278 bool ParametricCurveDrawer:: 00279 draw() { 00280 // First, remove the old drawing, if any. 00281 hide(); 00282 00283 _drawn = true; 00284 00285 // If there's no curve, draw nothing and return false. 00286 if (_curves == (ParametricCurveCollection *)NULL) { 00287 return false; 00288 } 00289 00290 ParametricCurve *xyz_curve = _curves->get_default_curve(); 00291 if (xyz_curve == (ParametricCurve *)NULL) { 00292 return false; 00293 } 00294 00295 // Otherwise, let's go to town! 00296 00297 // Make sure the curve(s) are fresh. 00298 _curves->recompute(); 00299 00300 int total_segs = (int)cfloor(_curves->get_max_t() * _num_segs + 0.5); 00301 00302 float max_t = xyz_curve->get_max_t(); 00303 float scale = max_t / (float)(total_segs-1); 00304 float t; 00305 LVecBase3f point; 00306 bool last_in, next_in; 00307 00308 last_in = false; 00309 int i; 00310 00311 for (i = 0; i < total_segs; i++) { 00312 t = (float)i * scale; 00313 00314 next_in = xyz_curve->get_point(t, point); 00315 00316 if (!next_in || !last_in) { 00317 _lines.move_to(point); 00318 } else { 00319 _lines.draw_to(point); 00320 } 00321 last_in = next_in; 00322 } 00323 00324 _lines.create(_geom_node, _frame_accurate); 00325 00326 max_t = get_max_t(); 00327 scale = max_t / (float)(total_segs-1); 00328 00329 // Now draw the time tick marks. 00330 if (_num_ticks > 0.0f) { 00331 int total_ticks = (int)cfloor(max_t * _num_ticks + 0.5); 00332 ParametricCurve *xyz_curve = _curves->get_default_curve(); 00333 // ParametricCurve *hpr_curve = _curves->get_hpr_curve(); 00334 00335 scale = max_t / (float)total_ticks; 00336 00337 for (i = 0; i <= total_ticks; i++) { 00338 t = (float)i * scale; 00339 float t0 = _curves->evaluate_t(t); 00340 LVecBase3f tangent; 00341 00342 if (xyz_curve->get_pt(t0, point, tangent)) { 00343 // Draw crosses. 00344 LVecBase3f t1, t2; 00345 get_tick_marks(tangent, t1, t2); 00346 00347 _ticks.move_to(point - t1 * _tick_scale); 00348 _ticks.draw_to(point + t1 * _tick_scale); 00349 _ticks.move_to(point - t2 * _tick_scale); 00350 _ticks.draw_to(point + t2 * _tick_scale); 00351 } 00352 } 00353 _ticks.create(_geom_node, _frame_accurate); 00354 } 00355 00356 return true; 00357 } 00358 00359 00360 00361 00362 //////////////////////////////////////////////////////////////////// 00363 // Function: ParametricCurveDrawer::hide 00364 // Access: Published 00365 // Description: Removes the lines that were created by a previous 00366 // call to draw(). 00367 //////////////////////////////////////////////////////////////////// 00368 void ParametricCurveDrawer:: 00369 hide() { 00370 _geom_node->remove_all_geoms(); 00371 _drawn = false; 00372 } 00373 00374 00375 //////////////////////////////////////////////////////////////////// 00376 // Function: ParametricCurveDrawer::set_tick_scale 00377 // Access: Published 00378 // Description: Sets the visible size of the time tick marks or 00379 // geometry. 00380 //////////////////////////////////////////////////////////////////// 00381 void ParametricCurveDrawer:: 00382 set_tick_scale(float scale) { 00383 _tick_scale = scale; 00384 redraw(); 00385 } 00386 00387 00388 //////////////////////////////////////////////////////////////////// 00389 // Function: ParametricCurveDrawer::get_tick_scale 00390 // Access: Published 00391 // Description: Returns the size of the time tick marks or geometry. 00392 //////////////////////////////////////////////////////////////////// 00393 float ParametricCurveDrawer:: 00394 get_tick_scale() const { 00395 return _tick_scale; 00396 } 00397 00398 //////////////////////////////////////////////////////////////////// 00399 // Function: ParametricCurveDrawer::get_tick_marks 00400 // Access: Private, Static 00401 // Description: Given a tangent vector, computes two vectors at right 00402 // angles to the tangent and to each other, suitable for 00403 // drawing as tick marks. 00404 //////////////////////////////////////////////////////////////////// 00405 void ParametricCurveDrawer:: 00406 get_tick_marks(const LVecBase3f &tangent, LVecBase3f &t1, LVecBase3f &t2) { 00407 LVector3f tn = tangent; 00408 tn.normalize(); 00409 00410 // Decide the smallest axis of tn and cross with the corresponding 00411 // unit vector. 00412 if (fabs(tn[0]) <= fabs(tn[1]) && fabs(tn[0]) <= fabs(tn[2])) { 00413 // X is smallest. 00414 t1 = tn.cross(LVector3f(1.0f, 0.0f, 0.0f)); 00415 00416 } else if (fabs(tn[1]) <= fabs(tn[2])) { 00417 // Y is smallest. 00418 t1 = tn.cross(LVector3f(0.0f, 1.0f, 0.0f)); 00419 00420 } else { 00421 // Z is smallest. 00422 t1 = tn.cross(LVector3f(0.0f, 0.0f, 1.0f)); 00423 } 00424 00425 t2 = tn.cross(t1); 00426 }