00001 // Filename: eggNurbsSurface.cxx 00002 // Created by: drose (15Feb00) 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 "eggNurbsSurface.h" 00020 00021 #include <indent.h> 00022 00023 TypeHandle EggNurbsSurface::_type_handle; 00024 00025 //////////////////////////////////////////////////////////////////// 00026 // Function: EggNurbsSurface::setup 00027 // Access: Public 00028 // Description: Prepares a new surface definition with the indicated 00029 // order and number of knots in each dimension. This 00030 // also implies a particular number of vertices in each 00031 // dimension as well (the number of knots minus the 00032 // order), but it is up to the user to add the correct 00033 // number of vertices to the surface by repeatedly 00034 // calling push_back(). 00035 //////////////////////////////////////////////////////////////////// 00036 void EggNurbsSurface:: 00037 setup(int u_order, int v_order, 00038 int num_u_knots, int num_v_knots) { 00039 _u_order = u_order; 00040 _v_order = v_order; 00041 _u_knots.clear(); 00042 _v_knots.clear(); 00043 00044 int i; 00045 _u_knots.reserve(num_u_knots); 00046 for (i = 0; i < num_u_knots; i++) { 00047 _u_knots.push_back((double)i); 00048 } 00049 _v_knots.reserve(num_v_knots); 00050 for (i = 0; i < num_v_knots; i++) { 00051 _v_knots.push_back((double)i); 00052 } 00053 } 00054 00055 //////////////////////////////////////////////////////////////////// 00056 // Function: EggNurbsSurface::set_num_u_knots 00057 // Access: Public 00058 // Description: Directly changes the number of knots in the U 00059 // direction. This will either add zero-valued knots 00060 // onto the end, or truncate knot values from the end, 00061 // depending on whether the list is being increased or 00062 // decreased. If possible, it is preferable to use the 00063 // setup() method instead of directly setting the number 00064 // of knots, as this may result in an invalid surface. 00065 //////////////////////////////////////////////////////////////////// 00066 void EggNurbsSurface:: 00067 set_num_u_knots(int num) { 00068 if ((int)_u_knots.size() >= num) { 00069 // Truncate knot values at the end. 00070 _u_knots.erase(_u_knots.begin() + num, _u_knots.end()); 00071 } else { 00072 // Append knot values to the end. 00073 _u_knots.reserve(num); 00074 for (int i = _u_knots.size(); i < num; i++) { 00075 _u_knots.push_back(0.0); 00076 } 00077 } 00078 } 00079 00080 //////////////////////////////////////////////////////////////////// 00081 // Function: EggNurbsSurface::set_num_v_knots 00082 // Access: Public 00083 // Description: Directly changes the number of knots in the V 00084 // direction. This will either add zero-valued knots 00085 // onto the end, or truncate knot values from the end, 00086 // depending on whether the list is being increased or 00087 // decreased. If possible, it is preferable to use the 00088 // setup() method instead of directly setting the number 00089 // of knots, as this may result in an invalid surface. 00090 //////////////////////////////////////////////////////////////////// 00091 void EggNurbsSurface:: 00092 set_num_v_knots(int num) { 00093 if ((int)_v_knots.size() >= num) { 00094 // Truncate knot values at the end. 00095 _v_knots.erase(_v_knots.begin() + num, _v_knots.end()); 00096 } else { 00097 // Append knot values to the end. 00098 _v_knots.reserve(num); 00099 for (int i = _v_knots.size(); i < num; i++) { 00100 _v_knots.push_back(0.0); 00101 } 00102 } 00103 } 00104 00105 //////////////////////////////////////////////////////////////////// 00106 // Function: EggNurbsSurface::is_valid 00107 // Access: Public 00108 // Description: Returns true if the NURBS parameters are all 00109 // internally consistent (e.g. it has the right number 00110 // of vertices to match its number of knots and order in 00111 // each dimension), or false otherwise. 00112 //////////////////////////////////////////////////////////////////// 00113 bool EggNurbsSurface:: 00114 is_valid() const { 00115 if (_u_order < 1 || _u_order > 4 || _v_order < 1 || _v_order > 4) { 00116 // Invalid order. 00117 return false; 00118 } 00119 00120 if (get_num_cvs() != (int)size()) { 00121 // Wrong number of CV's. 00122 return false; 00123 } 00124 00125 // Do all the knot values monotonically increase? 00126 int i; 00127 for (i = 1; i < get_num_u_knots(); i++) { 00128 if (get_u_knot(i) < get_u_knot(i - 1)) { 00129 return false; 00130 } 00131 } 00132 for (i = 1; i < get_num_v_knots(); i++) { 00133 if (get_v_knot(i) < get_v_knot(i - 1)) { 00134 return false; 00135 } 00136 } 00137 00138 // Everything's looking good! 00139 return true; 00140 } 00141 00142 //////////////////////////////////////////////////////////////////// 00143 // Function: EggNurbsSurface::is_closed_u 00144 // Access: Public 00145 // Description: Returns true if the surface appears to be closed in 00146 // the U direction. Since the Egg syntax does not 00147 // provide a means for explicit indication of closure, 00148 // this has to be guessed at by examining the surface 00149 // itself. 00150 //////////////////////////////////////////////////////////////////// 00151 bool EggNurbsSurface:: 00152 is_closed_u() const { 00153 // Technically, the surface is closed if the CV's at the end are 00154 // repeated from the beginning. We'll do a cheesy test for 00155 // expediency's sake: the surface is closed if the first n knots are 00156 // not repeated. I think this will catch all the normal surfaces 00157 // we're likely to see. 00158 00159 int i; 00160 for (i = 1; i < get_u_order(); i++) { 00161 if (get_u_knot(i) != get_u_knot(i-1)) { 00162 return true; 00163 } 00164 } 00165 return false; 00166 } 00167 00168 //////////////////////////////////////////////////////////////////// 00169 // Function: EggNurbsSurface::is_closed_v 00170 // Access: Public 00171 // Description: Returns true if the surface appears to be closed in 00172 // the V direction. Since the Egg syntax does not 00173 // provide a means for explicit indication of closure, 00174 // this has to be guessed at by examining the surface 00175 // itself. 00176 //////////////////////////////////////////////////////////////////// 00177 bool EggNurbsSurface:: 00178 is_closed_v() const { 00179 int i; 00180 for (i = 1; i < get_v_order(); i++) { 00181 if (get_v_knot(i) != get_v_knot(i-1)) { 00182 return true; 00183 } 00184 } 00185 return false; 00186 } 00187 00188 //////////////////////////////////////////////////////////////////// 00189 // Function: EggNurbsSurface::write 00190 // Access: Public, Virtual 00191 // Description: Writes the nurbsSurface to the indicated output stream in 00192 // Egg format. 00193 //////////////////////////////////////////////////////////////////// 00194 void EggNurbsSurface:: 00195 write(ostream &out, int indent_level) const { 00196 write_header(out, indent_level, "<NurbsSurface>"); 00197 00198 Trims::const_iterator ti; 00199 for (ti = _trims.begin(); ti != _trims.end(); ++ti) { 00200 indent(out, indent_level + 2) << "<Trim> {\n"; 00201 Loops::const_iterator li; 00202 for (li = (*ti).begin(); li != (*ti).end(); ++li) { 00203 indent(out, indent_level + 4) << "<Loop> {\n"; 00204 Curves::const_iterator ci; 00205 for (ci = (*li).begin(); ci != (*li).end(); ++ci) { 00206 (*ci)->write(out, indent_level + 6); 00207 } 00208 indent(out, indent_level + 4) << "}\n"; 00209 } 00210 indent(out, indent_level + 2) << "}\n"; 00211 } 00212 00213 if (get_u_subdiv() != 0) { 00214 indent(out, indent_level + 2) 00215 << "<Scalar> U-subdiv { " << get_u_subdiv() << " }\n"; 00216 } 00217 if (get_v_subdiv() != 0) { 00218 indent(out, indent_level + 2) 00219 << "<Scalar> V-subdiv { " << get_v_subdiv() << " }\n"; 00220 } 00221 indent(out, indent_level + 2) 00222 << "<Order> { " << get_u_order() << " " << get_v_order() << " }\n"; 00223 indent(out, indent_level + 2) 00224 << "<U-Knots> {\n"; 00225 write_long_list(out, indent_level+4, _u_knots.begin(), _u_knots.end(), 00226 "", "", 72); 00227 indent(out, indent_level + 2) 00228 << "}\n"; 00229 indent(out, indent_level + 2) 00230 << "<V-Knots> {\n"; 00231 write_long_list(out, indent_level+4, _v_knots.begin(), _v_knots.end(), 00232 "", "", 72); 00233 indent(out, indent_level + 2) 00234 << "}\n"; 00235 00236 write_body(out, indent_level+2); 00237 00238 Curves::const_iterator ci; 00239 for (ci = _curves_on_surface.begin(); ci != _curves_on_surface.end(); ++ci) { 00240 (*ci)->write(out, indent_level + 2); 00241 } 00242 00243 indent(out, indent_level) << "}\n"; 00244 } 00245 00246 //////////////////////////////////////////////////////////////////// 00247 // Function: EggNurbsSurface::r_apply_texmats 00248 // Access: Protected, Virtual 00249 // Description: The recursive implementation of apply_texmats(). 00250 //////////////////////////////////////////////////////////////////// 00251 void EggNurbsSurface:: 00252 r_apply_texmats(EggTextureCollection &textures) { 00253 // A NURBS cannot safely apply texture matrices, so we leave it 00254 // alone. 00255 }