00001 // Filename: lineSegs.cxx 00002 // Created by: drose (16Mar02) 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 #include "lineSegs.h" 00020 00021 //////////////////////////////////////////////////////////////////// 00022 // Function: LineSegs::Constructor 00023 // Access: Public 00024 // Description: Constructs a LineSegs object, which can be used to 00025 // create any number of disconnected lines or points of 00026 // various thicknesses and colors through the visible 00027 // scene. After creating the object, call move_to() and 00028 // draw_to() repeatedly to describe the path, then call 00029 // create() to create a GeomNode which will render the 00030 // described path. 00031 //////////////////////////////////////////////////////////////////// 00032 LineSegs:: 00033 LineSegs(const string &name) : Namable(name) { 00034 _color.set(1.0f, 1.0f, 1.0f, 1.0f); 00035 _thick = 1.0f; 00036 } 00037 00038 00039 //////////////////////////////////////////////////////////////////// 00040 // Function: LineSegs::Destructor 00041 // Access: Public 00042 //////////////////////////////////////////////////////////////////// 00043 LineSegs:: 00044 ~LineSegs() { 00045 } 00046 00047 00048 //////////////////////////////////////////////////////////////////// 00049 // Function: LineSegs::reset 00050 // Access: Public 00051 // Description: Removes any lines in progress and resets to the 00052 // initial empty state. 00053 //////////////////////////////////////////////////////////////////// 00054 void LineSegs:: 00055 reset() { 00056 _list.clear(); 00057 } 00058 00059 00060 //////////////////////////////////////////////////////////////////// 00061 // Function: LineSegs::move_to 00062 // Access: Public 00063 // Description: Moves the pen to the given point without drawing a 00064 // line. When followed by draw_to(), this marks the 00065 // first point of a line segment; when followed by 00066 // move_to() or create(), this creates a single point. 00067 //////////////////////////////////////////////////////////////////// 00068 void LineSegs:: 00069 move_to(const LVecBase3f &v) { 00070 // We create a new SegmentList with the initial point in it. 00071 SegmentList segs; 00072 segs.push_back(Point(v, _color)); 00073 00074 // And add this list to the list of segments. 00075 _list.push_back(segs); 00076 } 00077 00078 //////////////////////////////////////////////////////////////////// 00079 // Function: LineSegs::draw_to 00080 // Access: Public 00081 // Description: Draws a line segment from the pen's last position 00082 // (the last call to move_to or draw_to) to the 00083 // indicated point. move_to() and draw_to() only update 00084 // tables; the actual drawing is performed when create() 00085 // is called. 00086 //////////////////////////////////////////////////////////////////// 00087 void LineSegs:: 00088 draw_to(const LVecBase3f &v) { 00089 if (_list.empty()) { 00090 // Let our first call to draw_to() be an implicit move_to(). 00091 move_to(v); 00092 00093 } else { 00094 // Get the current SegmentList, which was the last one we added to 00095 // the LineList. 00096 SegmentList &segs = _list.back(); 00097 00098 // Add the new point. 00099 segs.push_back(Point(v, _color)); 00100 } 00101 } 00102 00103 //////////////////////////////////////////////////////////////////// 00104 // Function: LineSegs::empty 00105 // Access: Public 00106 // Description: Returns true if move_to() or draw_to() have not been 00107 // called since the last reset() or create(), false 00108 // otherwise. 00109 //////////////////////////////////////////////////////////////////// 00110 bool LineSegs:: 00111 is_empty() { 00112 return _list.empty(); 00113 } 00114 00115 //////////////////////////////////////////////////////////////////// 00116 // Function: LineSegs::get_current_position 00117 // Access: Public 00118 // Description: Returns the pen's current position. The next call to 00119 // draw_to() will draw a line segment from this point. 00120 //////////////////////////////////////////////////////////////////// 00121 const Vertexf &LineSegs:: 00122 get_current_position() { 00123 if (_list.empty()) { 00124 // Our pen isn't anywhere. We'll put it somewhere. 00125 move_to(Vertexf(0.0f, 0.0f, 0.0f)); 00126 } 00127 00128 return _list.back().back()._point; 00129 } 00130 00131 //////////////////////////////////////////////////////////////////// 00132 // Function: LineSegs::create 00133 // Access: Public 00134 // Description: Appends to an existing GeomNode a new Geom that 00135 // will render the series of line segments and points 00136 // described via calls to move_to() and draw_to(). The 00137 // lines and points are created with the color and 00138 // thickness established by calls to set_color() and 00139 // set_thick(). 00140 // 00141 // If frame_accurate is true, the line segments will be 00142 // created as a frame-accurate index, so that later 00143 // calls to set_vertex or set_vertex_color will be 00144 // visually correct. 00145 //////////////////////////////////////////////////////////////////// 00146 GeomNode *LineSegs:: 00147 create(GeomNode *previous, bool) { 00148 if (!_list.empty()) { 00149 _created_verts.clear(); 00150 _created_colors.clear(); 00151 00152 // One array each for the indices into these arrays for points 00153 // and lines, and one for our line-segment lengths array. 00154 PTA_ushort point_index; 00155 PTA_ushort line_index; 00156 PTA_int lengths; 00157 00158 // Now fill up the arrays. 00159 int v = 0; 00160 LineList::const_iterator ll; 00161 SegmentList::const_iterator sl; 00162 00163 for (ll = _list.begin(); ll != _list.end(); ll++) { 00164 const SegmentList &segs = (*ll); 00165 00166 if (segs.size() < 2) { 00167 point_index.push_back(v); 00168 } else { 00169 lengths.push_back(segs.size()); 00170 } 00171 00172 for (sl = segs.begin(); sl != segs.end(); sl++) { 00173 if (segs.size() >= 2) { 00174 line_index.push_back(v); 00175 } 00176 _created_verts.push_back((*sl)._point); 00177 _created_colors.push_back((*sl)._color); 00178 v++; 00179 nassertr(v == (int)_created_verts.size(), previous); 00180 } 00181 } 00182 00183 // Now create the lines. 00184 if (line_index.size() > 0) { 00185 // Create a new Geom and add the line segments. 00186 Geom *geom; 00187 if (line_index.size() <= 2) { 00188 // Here's a special case: just one line segment. 00189 GeomLine *geom_line = new GeomLine; 00190 geom_line->set_num_prims(1); 00191 geom_line->set_width(_thick); 00192 geom = geom_line; 00193 00194 } else { 00195 // The more normal case: multiple line segments, connected 00196 // end-to-end like a series of linestrips. 00197 GeomLinestrip *geom_linestrip = new GeomLinestrip; 00198 geom_linestrip->set_num_prims(lengths.size()); 00199 geom_linestrip->set_lengths(lengths); 00200 geom_linestrip->set_width(_thick); 00201 geom = geom_linestrip; 00202 } 00203 00204 geom->set_colors(_created_colors, G_PER_VERTEX, line_index); 00205 geom->set_coords(_created_verts, line_index); 00206 00207 previous->add_geom(geom); 00208 } 00209 00210 // And now create the points. 00211 if (point_index.size() > 0) { 00212 // Create a new Geom and add the points. 00213 GeomPoint *geom = new GeomPoint; 00214 00215 geom->set_num_prims(point_index.size()); 00216 geom->set_size(_thick); 00217 geom->set_colors(_created_colors, G_PER_VERTEX, point_index); 00218 geom->set_coords(_created_verts, point_index); 00219 00220 previous->add_geom(geom); 00221 } 00222 00223 // And reset for next time. 00224 reset(); 00225 } 00226 00227 return previous; 00228 }