/// <summary> /// Helper function, returns the p[] value for the given index /// </summary> /// <param name="input">The "<input>" element we need the index of.</param> /// <param name="primitive">The "<primitive>" element the "<input>" is from.</param> /// <param name="index"> The index for which we need the p[] value.</param> static public int GetPValue(Document.Input input, Document.Primitive primitive, int index) { int stride = primitive.stride; int offset = input.offset; return(primitive.p[index * stride + offset]); }
/// <summary> /// Helper function. Returns all the inputs of the primitive. /// Resolve the 'VERTEX' indirection case. /// <param name="doc">The COLLADA document</param> /// <param name="primitive"> The "<primitive>" we need the inputs from.</param> /// </summary> static public List <Document.Input> getAllInputs(Document doc, Document.Primitive primitive) { List <Document.Input> inputs = new List <Document.Input>(); Document.Input vertexInput = null; // 1- get all the regular inputs foreach (Document.Input input in primitive.Inputs) { if (input.semantic == "VERTEX") { vertexInput = input; } else { inputs.Add(new Document.Input(doc, input.offset, input.semantic, input.set, ((Document.Source)input.source).id)); } } // 2- get all the indirect inputs if (vertexInput != null) { foreach (Document.Input input in ((Document.Vertices)vertexInput.source).inputs) { inputs.Add(new Document.Input(doc, vertexInput.offset, input.semantic, input.set, ((Document.Source)input.source).id)); } } return(inputs); }
/// <summary> /// Helper function, returns the element of a source for the given index /// </summary> /// <param name="doc">The COLLADA document</param> /// <param name="input">The "<input>" element we need the index of.</param> /// <param name="index"> The index for which we need the value.</param> public static float[] GetSourceElement(Document doc, Document.Input input, int index) { Document.Source src = (Document.Source)input.source; // resolve array // Note: this will work only if the array is in the current document... // TODO: create a resolver funtion rather than access to doc.dic directly... // enable loading array from binary raw file as well object array = doc.dic[src.accessor.source.Fragment]; if (array is Document.Array <float> ) { Document.Array <float> farray = (Document.Array <float>)(array); float[] returnValue = new float[src.accessor.stride]; for (int i = 0; i < returnValue.Length; i++) { returnValue[i] = farray[src.accessor[i, index]]; } return(returnValue); } else { throw new Exception("Unsupported array type"); } // Note: Rarelly int_array could be used for geometry values }
/// <summary> /// Helper function, returns the element of a source for the given index /// </summary> /// <param name="doc">The COLLADA document</param> /// <param name="input">The "<input>" element we need the index of.</param> /// <param name="index"> The index for which we need the value.</param> public static float[] GetSourceElement(Document doc, Document.Input input, int index) { Document.Source src = (Document.Source)input.source; int stride = src.accessor.stride; int offset = src.accessor.offset; // resolve array // Note: this will work only if the array is in the current document... // TODO: create a resolver funtion rather than access to doc.dic directly... // enable loading array from binary raw file as well object array = doc.dic[src.accessor.source.Fragment]; if (array is Document.Array <float> ) { Document.Array <float> farray = (Document.Array <float>)(array); if (src.accessor.ParameterCount == 1) { float[] returnValue = new float[1]; returnValue[0] = farray[src.accessor[0, index]]; return(returnValue); } else if (src.accessor.ParameterCount == 2) { float[] returnValue = new float[2]; returnValue[0] = farray[src.accessor[0, index]]; returnValue[1] = farray[offset + index * stride + src.accessor[1]]; return(returnValue); } else if (src.accessor.ParameterCount == 3) { float[] returnValue = new float[3]; returnValue[0] = farray[src.accessor[0, index]]; returnValue[1] = farray[offset + index * stride + src.accessor[1]]; returnValue[2] = farray[offset + index * stride + src.accessor[2]]; return(returnValue); } else { throw new Exception("Unsupported accessor size"); } } else { throw new Exception("Unsupported array type"); } // Note: Rarelly int_array could be used for geometry values }
public Sampler(Document doc, Document.Sampler sampler) { foreach (Document.Input input in sampler.inputs) { this.doc = doc; Document.Source source = input.source as Document.Source; switch (input.semantic) { case "INTERPOLATION": Document.Array<string> arr = source.array as Document.Array<string>; interpolations = new EInterpolation[arr.Count]; for (int i = 0; i < interpolations.Length; i++) { switch (arr.arr[i]) { case "LINEAR": interpolations[i] = EInterpolation.LINEAR; break; case "BEZIER": interpolations[i] = EInterpolation.BEZIER; break; case "STEP": interpolations[i] = EInterpolation.STEP; break; default: throw new ColladaException("unsupported interpolation type " + arr.arr[i] + " in <sampler>!"); // TODO: implement this } } break; case "INPUT": inputs = (source.array as Document.Array<float>).arr; if (inputs.Length > 0) { startTime = inputs[0]; endTime = inputs[inputs.Length - 1]; } break; case "OUTPUT": output = input; dim_output = ((Document.Source) output.source).accessor.stride; break; case "IN_TANGENT": inTangents = input; dim_tangents = ((Document.Source) inTangents.source).accessor.stride; break; case "OUT_TANGENT": outTangents = input; break; default: throw new ColladaException("unsupported semantic " + input.semantic + " in <sampler>!"); } } if (interpolations == null) { // some examples don't specify required input element with semantic INTERPOLATION // TODO: write a warning to log interpolations = new EInterpolation[inputs.Length]; for (int i = 0; i < interpolations.Length; i++) interpolations[i] = EInterpolation.LINEAR; } }
/// <summary>This method will create a single index for the primitives /// This will not work on polygons and polylist, since vcount is not taken in count there /// So you need to first run ConvexTriangulator (or equivalent) /// <para>This will make it directly usable as a index vertexArray for drawing</para> /// </summary> static public void Reindexor(Document doc) { String[] channelFlags = { "POSITION", "NORMAL", "TEXCOORD", "COLOR", "TANGENT", "BINORMAL", "UV", "TEXBINORMAL", "TEXTANGENT" }; Dictionary <string, int> channelCount = new Dictionary <string, int>(); Dictionary <string, int> maxChannelCount = new Dictionary <string, int>(); Dictionary <string, List <Document.Input> > inputs = new Dictionary <string, List <Document.Input> >();; foreach (Document.Geometry geo in doc.geometries) { // Skip geometry if there are no primitives defined if (geo.mesh.primitives.Count == 0) { continue; } foreach (string i in channelFlags) { maxChannelCount[i] = 0; } // Check if all parts have the same vertex definition bool first = true; foreach (Document.Primitive primitive in geo.mesh.primitives) { foreach (string i in channelFlags) { channelCount[i] = 0; } foreach (Document.Input input in COLLADAUtil.GetAllInputs(primitive)) { channelCount[input.semantic]++; } if (first) { foreach (string i in channelFlags) { if (maxChannelCount[i] < channelCount[i]) { maxChannelCount[i] = channelCount[i]; } } first = false; } else { foreach (string i in channelFlags) { if (maxChannelCount[i] != channelCount[i]) { throw new Exception("TODO: mesh parts have different vertex buffer definition in geometry " + geo.id); } } } } // create new float array and index List <List <int> > indexList = new List <List <int> >(); List <int> indexes; List <float> farray = new List <float>(); Dictionary <string, int> checkIndex = new Dictionary <string, int>(); int index = 0; foreach (Document.Primitive primitive in geo.mesh.primitives) { foreach (string i in channelFlags) { inputs[i] = new List <Document.Input>(); } foreach (Document.Input input in COLLADAUtil.GetAllInputs(primitive)) { inputs[input.semantic].Add(input); } indexes = new List <int>(); indexList.Add(indexes); int k = 0; string indexKey; List <float> tmpValues; try { while (true) { indexKey = ""; tmpValues = new List <float>(); foreach (string i in channelFlags) { foreach (Document.Input input in inputs[i]) { int j = COLLADAUtil.GetPValue(input, primitive, k); indexKey += j.ToString() + ","; float[] values = COLLADAUtil.GetSourceElement(doc, input, j); for (int l = 0; l < values.Length; l++) { tmpValues.Add(values[l]); } } } k++; if (checkIndex.ContainsKey(indexKey)) { indexes.Add(checkIndex[indexKey]); } else { indexes.Add(index); checkIndex[indexKey] = index++; foreach (float f in tmpValues) { farray.Add(f); } } } } catch { } // catch for index out of range. } // remove old sources and array foreach (Document.Source source in geo.mesh.sources) { if (source.array != null) { doc.dic.Remove(((Document.Array <float>)source.array).id); } doc.dic.Remove(source.id); } // create all the new source int stride = 0; foreach (Document.Source source in geo.mesh.sources) { stride += source.accessor.stride; } List <Document.Source> newSources = new List <Document.Source>(); Document.Source newSource; Document.Accessor newAccessor; Document.Array <float> newArray; int offset = 0; string positionId = ((Document.Source)inputs["POSITION"][0].source).id; foreach (Document.Source source in geo.mesh.sources) { newAccessor = new Document.Accessor(doc, farray.Count / stride, offset, stride, "#" + geo.id + "-vertexArray", source.accessor.parameters); offset += source.accessor.stride; if (source.id == positionId) { newArray = new Document.Array <float>(doc, geo.id + "-vertexArray", farray.ToArray()); } else { newArray = null; } newSource = new Document.Source(doc, source.id, newArray, newAccessor); newSources.Add(newSource); } // Create the new vertices List <Document.Input> newInputs = new List <Document.Input>(); Document.Input newInput; foreach (string i in channelFlags) { foreach (Document.Input input in inputs[i]) { // no offset, all inputs share the same index newInput = new Document.Input(doc, 0, input.semantic, input.set, ((Document.Source)input.source).id); newInputs.Add(newInput); } } Document.Vertices newVertices = new Document.Vertices(doc, geo.mesh.vertices.id, newInputs); // now create the new primitives List <Document.Primitive> newPrimitives = new List <Document.Primitive>(); Document.Primitive newPrimitive; index = 0; offset = 0; foreach (Document.Primitive primitive in geo.mesh.primitives) { newInputs = new List <Document.Input>(); newInput = new Document.Input(doc, 0, "VERTEX", -1, geo.mesh.vertices.id); newInputs.Add(newInput); if (primitive is Document.Triangle) { newPrimitive = new Document.Triangle(doc, primitive.count, newInputs, indexList[index].ToArray()); } else if (primitive is Document.Line) { newPrimitive = new Document.Line(doc, primitive.count, newInputs, indexList[index].ToArray()); } else { throw new Exception("TODO: need to take care of " + primitive.GetType().ToString()); } newPrimitive.material = primitive.material; newPrimitive.extras = primitive.extras; newPrimitive.name = primitive.name; newPrimitives.Add(newPrimitive); index++; } // change the primitive to use the new array and indexes. // 1) - remove the old sources, vertices and primitives geo.mesh.sources.Clear(); geo.mesh.vertices.inputs.Clear(); geo.mesh.primitives.Clear(); // 2) - Add all the sources, only the POSITION will have the values geo.mesh.sources = newSources; geo.mesh.primitives = newPrimitives; geo.mesh.vertices = newVertices; } // foreach geometry } // Reindexor()
/// <summary>This method will create a single index for the primitives /// This will not work on polygons and polylist, since vcount is not taken in count there /// So you need to first run ConvexTriangulator (or equivalent) /// <para>This will make it directly usable as a index vertexArray for drawing</para> /// </summary> public static void Reindexor(Document doc) { String[] channelFlags = { "POSITION", "NORMAL", "TEXCOORD", "COLOR", "TANGENT", "BINORMAL", "UV", "TEXBINORMAL", "TEXTANGENT" }; Dictionary<string,int> channelCount = new Dictionary<string,int>(); Dictionary<string, int> maxChannelCount = new Dictionary<string, int>(); Dictionary<string, List<Document.Input>> inputs = new Dictionary<string, List<Document.Input>>(); ; foreach (Document.Geometry geo in doc.geometries) { // Skip geometry if there are no primitives defined if (geo.mesh.primitives.Count == 0) continue; foreach (string i in channelFlags) maxChannelCount[i] = 0; // Check if all parts have the same vertex definition bool first=true; foreach (Document.Primitive primitive in geo.mesh.primitives) { foreach (string i in channelFlags) channelCount[i] = 0; foreach (Document.Input input in COLLADAUtil.GetAllInputs(primitive)) { channelCount[input.semantic]++; } if (first) { foreach (string i in channelFlags) if (maxChannelCount[i] < channelCount[i]) maxChannelCount[i] = channelCount[i]; first = false; } else { foreach (string i in channelFlags) if (maxChannelCount[i] != channelCount[i]) throw new Exception("TODO: mesh parts have different vertex buffer definition in geometry " + geo.id); } } // create new float array and index List<List<int>> indexList = new List<List<int>>(); List<int> indexes; List<float> farray = new List<float>(); Dictionary<string,int> checkIndex = new Dictionary<string,int>(); int index=0; foreach (Document.Primitive primitive in geo.mesh.primitives) { foreach (string i in channelFlags) inputs[i] = new List<Document.Input>(); foreach (Document.Input input in COLLADAUtil.GetAllInputs(primitive)) inputs[input.semantic].Add(input); indexes = new List<int>(); indexList.Add(indexes); int k=0; string indexKey; List<float> tmpValues; try { while (true) { indexKey = ""; tmpValues = new List<float>(); foreach (string i in channelFlags) foreach (Document.Input input in inputs[i]) { int j = COLLADAUtil.GetPValue(input, primitive, k); indexKey += j.ToString() + ","; float[] values = COLLADAUtil.GetSourceElement(doc,input, j); for (int l = 0; l < values.Length; l++) tmpValues.Add(values[l]); } k++; if (checkIndex.ContainsKey(indexKey)) indexes.Add(checkIndex[indexKey]); else { indexes.Add(index); checkIndex[indexKey] = index++; foreach (float f in tmpValues) farray.Add(f); } } } catch { } // catch for index out of range. } // remove old sources and array foreach (Document.Source source in geo.mesh.sources) { if (source.array != null) doc.dic.Remove(((Document.Array<float>)source.array).id); doc.dic.Remove(source.id); } // create all the new source int stride = 0; foreach (Document.Source source in geo.mesh.sources) { stride += source.accessor.stride; } List<Document.Source> newSources = new List<Document.Source>(); Document.Source newSource; Document.Accessor newAccessor; Document.Array<float> newArray; int offset = 0; string positionId = ((Document.Source)inputs["POSITION"][0].source).id; foreach (Document.Source source in geo.mesh.sources) { newAccessor = new Document.Accessor(doc, farray.Count / stride, offset, stride, "#"+geo.id + "-vertexArray", source.accessor.parameters); offset += source.accessor.stride; if (source.id == positionId) { newArray = new Document.Array<float>(doc, geo.id + "-vertexArray", farray.ToArray()); } else { newArray = null; } newSource = new Document.Source(doc, source.id, newArray, newAccessor); newSources.Add(newSource); } // Create the new vertices List<Document.Input> newInputs = new List<Document.Input>(); Document.Input newInput; foreach (string i in channelFlags) { foreach (Document.Input input in inputs[i]) { // no offset, all inputs share the same index newInput = new Document.Input(doc, 0, input.semantic, input.set, ((Document.Source)input.source).id); newInputs.Add(newInput); } } Document.Vertices newVertices = new Document.Vertices(doc, geo.mesh.vertices.id, newInputs); // now create the new primitives List<Document.Primitive> newPrimitives = new List<Document.Primitive>(); Document.Primitive newPrimitive; index = 0; offset = 0; foreach (Document.Primitive primitive in geo.mesh.primitives) { newInputs = new List<Document.Input>(); newInput = new Document.Input(doc, 0, "VERTEX", -1, geo.mesh.vertices.id); newInputs.Add(newInput); if (primitive is Document.Triangle) newPrimitive = new Document.Triangle(doc, primitive.count, newInputs, indexList[index].ToArray()); else if (primitive is Document.Line) newPrimitive = new Document.Line(doc, primitive.count, newInputs, indexList[index].ToArray()); else throw new Exception("TODO: need to take care of " + primitive.GetType().ToString()); newPrimitive.material = primitive.material; newPrimitive.extras = primitive.extras; newPrimitive.name = primitive.name; newPrimitives.Add(newPrimitive); index++; } // change the primitive to use the new array and indexes. // 1) - remove the old sources, vertices and primitives geo.mesh.sources.Clear(); geo.mesh.vertices.inputs.Clear(); geo.mesh.primitives.Clear(); // 2) - Add all the sources, only the POSITION will have the values geo.mesh.sources = newSources; geo.mesh.primitives = newPrimitives; geo.mesh.vertices = newVertices; } // foreach geometry }