Panda3D
|
00001 // Filename: colladaInput.cxx 00002 // Created by: rdb (23May11) 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 "colladaInput.h" 00016 #include "string_utils.h" 00017 #include "geomVertexArrayFormat.h" 00018 #include "geomVertexWriter.h" 00019 00020 // Collada DOM includes. No other includes beyond this point. 00021 #include "pre_collada_include.h" 00022 #include <dom/domAccessor.h> 00023 #include <dom/domP.h> 00024 #include <dom/domSource.h> 00025 #include <dom/domVertices.h> 00026 00027 #if PANDA_COLLADA_VERSION >= 15 00028 #include <dom/domInput_local_offset.h> 00029 #include <dom/domInput_local.h> 00030 #else 00031 #include <dom/domInputLocalOffset.h> 00032 #include <dom/domInputLocal.h> 00033 #define domList_of_floats domListOfFloats 00034 #define domList_of_uints domListOfUInts 00035 #endif 00036 00037 //////////////////////////////////////////////////////////////////// 00038 // Function: ColladaInput::Constructor 00039 // Description: Pretty obvious what this does. 00040 //////////////////////////////////////////////////////////////////// 00041 ColladaInput:: 00042 ColladaInput(const string &semantic) : 00043 _column_name (NULL), 00044 _semantic (semantic), 00045 _offset (0), 00046 _have_set (false), 00047 _set (0) { 00048 00049 if (semantic == "POSITION") { 00050 _column_name = InternalName::get_vertex(); 00051 _column_contents = GeomEnums::C_point; 00052 } else if (semantic == "COLOR") { 00053 _column_name = InternalName::get_color(); 00054 _column_contents = GeomEnums::C_color; 00055 } else if (semantic == "NORMAL") { 00056 _column_name = InternalName::get_normal(); 00057 _column_contents = GeomEnums::C_vector; 00058 } else if (semantic == "TEXCOORD") { 00059 _column_name = InternalName::get_texcoord(); 00060 _column_contents = GeomEnums::C_texcoord; 00061 } else if (semantic == "TEXBINORMAL") { 00062 _column_name = InternalName::get_binormal(); 00063 _column_contents = GeomEnums::C_vector; 00064 } else if (semantic == "TEXTANGENT") { 00065 _column_name = InternalName::get_tangent(); 00066 _column_contents = GeomEnums::C_vector; 00067 } 00068 } 00069 00070 //////////////////////////////////////////////////////////////////// 00071 // Function: ColladaInput::Constructor 00072 // Description: Pretty obvious what this does. 00073 //////////////////////////////////////////////////////////////////// 00074 ColladaInput:: 00075 ColladaInput(const string &semantic, unsigned int set) : 00076 _column_name (NULL), 00077 _semantic (semantic), 00078 _offset (0), 00079 _have_set (true), 00080 _set (set) { 00081 00082 ostringstream setstr; 00083 setstr << _set; 00084 00085 if (semantic == "POSITION") { 00086 _column_name = InternalName::get_vertex(); 00087 _column_contents = GeomEnums::C_point; 00088 } else if (semantic == "COLOR") { 00089 _column_name = InternalName::get_color(); 00090 _column_contents = GeomEnums::C_color; 00091 } else if (semantic == "NORMAL") { 00092 _column_name = InternalName::get_normal(); 00093 _column_contents = GeomEnums::C_vector; 00094 } else if (semantic == "TEXCOORD") { 00095 _column_name = InternalName::get_texcoord_name(setstr.str()); 00096 _column_contents = GeomEnums::C_texcoord; 00097 } else if (semantic == "TEXBINORMAL") { 00098 _column_name = InternalName::get_binormal_name(setstr.str()); 00099 _column_contents = GeomEnums::C_vector; 00100 } else if (semantic == "TEXTANGENT") { 00101 _column_name = InternalName::get_tangent_name(setstr.str()); 00102 _column_contents = GeomEnums::C_vector; 00103 } 00104 } 00105 00106 //////////////////////////////////////////////////////////////////// 00107 // Function: ColladaInput::from_dom 00108 // Description: Returns the ColladaInput object that represents 00109 // the provided DOM input element. 00110 //////////////////////////////////////////////////////////////////// 00111 ColladaInput *ColladaInput:: 00112 from_dom(domInput_local_offset &input) { 00113 // If we already loaded it before, use that. 00114 if (input.getUserData() != NULL) { 00115 return (ColladaInput *) input.getUserData(); 00116 } 00117 00118 ColladaInput *new_input = new ColladaInput(input.getSemantic(), input.getSet()); 00119 new_input->_offset = input.getOffset(); 00120 00121 // If this has the VERTEX semantic, it points to a <vertices> element. 00122 if (new_input->is_vertex_source()) { 00123 domVertices *verts = daeSafeCast<domVertices> (input.getSource().getElement()); 00124 nassertr(verts != NULL, NULL); 00125 daeTArray<domInput_localRef> &inputs = verts->getInput_array(); 00126 00127 // Iterate over the <input> elements in <vertices>. 00128 for (size_t i = 0; i < inputs.getCount(); ++i) { 00129 PT(ColladaInput) vtx_input = ColladaInput::from_dom(*inputs[i]); 00130 new_input->_vertex_inputs.push_back(vtx_input); 00131 } 00132 } else { 00133 domSource *source = daeSafeCast<domSource> (input.getSource().getElement()); 00134 nassertr(source != NULL, NULL); 00135 new_input->read_data(*source); 00136 } 00137 00138 return new_input; 00139 } 00140 00141 //////////////////////////////////////////////////////////////////// 00142 // Function: ColladaInput::from_dom 00143 // Description: Returns the ColladaInput object that represents 00144 // the provided DOM input element. 00145 //////////////////////////////////////////////////////////////////// 00146 ColladaInput *ColladaInput:: 00147 from_dom(domInput_local &input) { 00148 // If we already loaded it before, use that. 00149 if (input.getUserData() != NULL) { 00150 return (ColladaInput *) input.getUserData(); 00151 } 00152 00153 ColladaInput *new_input = new ColladaInput(input.getSemantic()); 00154 new_input->_offset = 0; 00155 00156 nassertr (!new_input->is_vertex_source(), NULL); 00157 00158 domSource *source = daeSafeCast<domSource> (input.getSource().getElement()); 00159 nassertr(source != NULL, NULL); 00160 new_input->read_data(*source); 00161 00162 return new_input; 00163 } 00164 00165 //////////////////////////////////////////////////////////////////// 00166 // Function: ColladaInput::make_vertex_columns 00167 // Description: Takes a semantic and source URI, and adds a new 00168 // column to the format. If this is a vertex source, 00169 // adds all of the inputs from the corresponding 00170 // <vertices> element. Returns the number of 00171 // columns added to the format. 00172 //////////////////////////////////////////////////////////////////// 00173 int ColladaInput:: 00174 make_vertex_columns(GeomVertexArrayFormat *format) const { 00175 00176 if (is_vertex_source()) { 00177 int counter = 0; 00178 Inputs::const_iterator it; 00179 for (it = _vertex_inputs.begin(); it != _vertex_inputs.end(); ++it) { 00180 counter += (*it)->make_vertex_columns(format); 00181 } 00182 return counter; 00183 } 00184 00185 nassertr(_column_name != NULL, 0); 00186 00187 format->add_column(_column_name, _num_bound_params, GeomEnums::NT_stdfloat, _column_contents); 00188 return 1; 00189 } 00190 00191 //////////////////////////////////////////////////////////////////// 00192 // Function: ColladaInput::read_data 00193 // Description: Reads the data from the source and fills in _data. 00194 //////////////////////////////////////////////////////////////////// 00195 bool ColladaInput:: 00196 read_data(domSource &source) { 00197 _data.clear(); 00198 00199 // Get this, get that 00200 domFloat_array* float_array = source.getFloat_array(); 00201 if (float_array == NULL) { 00202 return false; 00203 } 00204 00205 domList_of_floats &floats = float_array->getValue(); 00206 domAccessor &accessor = *source.getTechnique_common()->getAccessor(); 00207 domParam_Array ¶ms = accessor.getParam_array(); 00208 00209 // Count the number of params that have a name attribute. 00210 _num_bound_params = 0; 00211 for (size_t p = 0; p < params.getCount(); ++p) { 00212 if (params[p]->getName()) { 00213 ++_num_bound_params; 00214 } 00215 } 00216 00217 _data.reserve(accessor.getCount()); 00218 00219 domUint pos = accessor.getOffset(); 00220 for (domUint a = 0; a < accessor.getCount(); ++a) { 00221 domUint c = 0; 00222 // Yes, the last component defaults to 1 to work around a 00223 // perspective divide that Panda3D does internally for points. 00224 LVecBase4f v (0, 0, 0, 1); 00225 for (domUint p = 0; p < params.getCount(); ++p) { 00226 if (params[c]->getName()) { 00227 v[c++] = floats[pos + p]; 00228 } 00229 } 00230 _data.push_back(v); 00231 pos += accessor.getStride(); 00232 } 00233 00234 return true; 00235 } 00236 00237 //////////////////////////////////////////////////////////////////// 00238 // Function: ColladaInput::write_data 00239 // Description: Writes data to the indicated GeomVertexData using 00240 // the given indices. 00241 //////////////////////////////////////////////////////////////////// 00242 void ColladaInput:: 00243 write_data(GeomVertexData *vdata, int start_row, domP &p, unsigned int stride) const { 00244 if (is_vertex_source()) { 00245 Inputs::const_iterator it; 00246 for (it = _vertex_inputs.begin(); it != _vertex_inputs.end(); ++it) { 00247 (*it)->write_data(vdata, start_row, p, stride, _offset); 00248 } 00249 00250 } else { 00251 write_data(vdata, start_row, p, stride, _offset); 00252 } 00253 } 00254 00255 //////////////////////////////////////////////////////////////////// 00256 // Function: ColladaInput::write_data 00257 // Description: Called internally by the other write_data. 00258 //////////////////////////////////////////////////////////////////// 00259 void ColladaInput:: 00260 write_data(GeomVertexData *vdata, int start_row, domP &p, unsigned int stride, unsigned int offset) const { 00261 nassertv(_column_name != NULL); 00262 GeomVertexWriter writer (vdata, _column_name); 00263 writer.set_row_unsafe(start_row); 00264 00265 domList_of_uints &indices = p.getValue(); 00266 00267 // Allocate space for all the rows we're going to write. 00268 int min_length = start_row + indices.getCount() / stride; 00269 if (vdata->get_num_rows() < min_length) { 00270 vdata->unclean_set_num_rows(start_row); 00271 } 00272 00273 for (size_t i = 0; i < indices.getCount(); i += stride) { 00274 size_t index = indices[i + offset]; 00275 writer.add_data4f(_data[index]); 00276 } 00277 }