static ColladaSpline GetSpline(CL.UpAxisType up, CL.geometry geo) { var spline = geo.Item as CL.spline; if (spline == null) { return(null); } var conv = new ColladaSpline(); Dictionary <string, float[]> arrays = new Dictionary <string, float[]>(); Dictionary <string, GeometrySource> sources = new Dictionary <string, GeometrySource>(); //Get arrays foreach (var acc in spline.source) { var arr = acc.Item as CL.float_array; arrays.Add(arr.id, FloatArray(arr.Text)); } //Accessors foreach (var acc in spline.source) { sources.Add(acc.id, new GeometrySource(acc, arrays)); } //Process spline /*foreach(var input in spline.control_vertices.input) { * switch(input.semantic) { * * } * } * spline.*/ return(conv); }
static ColladaObject ProcessNode(CL.UpAxisType up, CL.library_geometries geom, CL.node n, CL.library_materials matlib, CL.library_effects fxlib) { var obj = new ColladaObject(); obj.Name = n.name; obj.ID = n.id; if (n.instance_geometry != null && n.instance_geometry.Length > 0) { //Geometry object if (n.instance_geometry.Length != 1) { throw new Exception("How to handle multiple geometries/node?"); } var uri = CheckURI(n.instance_geometry[0].url); var g = geom.geometry.Where((x) => x.id == uri).First(); if (g.Item is CL.mesh) { obj.Geometry = GetGeometry(up, g, matlib, fxlib); } else if (g.Item is CL.spline) { obj.Spline = GetSpline(up, g); } } if (n.Items.OfType <CL.matrix>().Any()) { var tr = n.Items.OfType <CL.matrix>().First(); obj.Transform = GetMatrix(up, tr.Text); } else { Matrix4x4 mat = Matrix4x4.Identity; foreach (var item in n.Items) { if (item is CL.TargetableFloat3) { //var float3 = } } obj.Transform = mat; } if (n.node1 != null && n.node1.Length > 0) { foreach (var node in n.node1) { obj.Children.Add(ProcessNode(up, geom, node, matlib, fxlib)); } } return(obj); }
static Vector3 VecAxis(CL.UpAxisType ax, Vector3 vec) { if (ax == CL.UpAxisType.Z_UP) { return(new Vector3(vec.X, vec.Z, vec.Y) * new Vector3(1, 1, -1)); } else if (ax == CL.UpAxisType.Y_UP) { return(vec); } else { throw new Exception("X_UP Unsupported"); } }
static Matrix4x4 GetMatrix(CL.UpAxisType ax, string text) { var floats = FloatArray(text); Matrix4x4 mat; if (floats.Length == 16) { mat = new Matrix4x4( floats[0], floats[4], floats[8], floats[12], floats[1], floats[5], floats[9], floats[13], floats[2], floats[6], floats[10], floats[14], floats[3], floats[7], floats[11], floats[15] ); } else if (floats.Length == 9) { mat = new Matrix4x4( floats[0], floats[1], floats[2], 0, floats[3], floats[4], floats[5], 0, floats[6], floats[7], floats[8], 0, 0, 0, 0, 1 ); } else { throw new Exception("Invalid Matrix: " + floats.Length + " elements"); } if (ax == CL.UpAxisType.Z_UP) { var translation = mat.Translation; translation = new Vector3(translation.X, translation.Z, translation.Y) * new Vector3(1, 1, -1); var rotq = mat.ExtractRotation(); var rot = Matrix4x4.CreateFromQuaternion( new Quaternion(rotq.X, rotq.Z, -rotq.Y, rotq.W) ); return(rot * Matrix4x4.CreateTranslation(translation)); } else if (ax == CL.UpAxisType.Y_UP) { return(mat); } else { throw new Exception("X_UP Unsupported"); } }
static ColladaObject ProcessNode(CL.UpAxisType up, CL.library_geometries geom, CL.node n) { var obj = new ColladaObject(); obj.Name = n.name; obj.ID = n.id; if (n.instance_geometry != null && n.instance_geometry.Length > 0) { //Geometry object if (n.instance_geometry.Length != 1) { throw new Exception("How to handle multiple geometries/node?"); } var uri = CheckURI(n.instance_geometry[0].url); var g = geom.geometry.Where((x) => x.id == uri).First(); if (g.Item is CL.mesh) { obj.Geometry = GetGeometry(up, g); } else if (g.Item is CL.spline) { obj.Spline = GetSpline(up, g); } } if (n.Items.OfType <CL.matrix>().Any()) { var tr = n.Items.OfType <CL.matrix>().First(); obj.Transform = GetMatrix(tr.Text); } else { //TODO: Non-matrix transforms } if (n.node1 != null && n.node1.Length > 0) { foreach (var node in n.node1) { obj.Children.Add(ProcessNode(up, geom, node)); } } return(obj); }
static ColladaGeometry GetGeometry(CL.UpAxisType up, CL.geometry geo, CL.library_materials matlib, CL.library_effects fxlib) { var conv = new ColladaGeometry() { FVF = D3DFVF.XYZ }; conv.Name = string.IsNullOrEmpty(geo.name) ? geo.id : geo.name; var msh = geo.Item as CL.mesh; if (msh == null) { return(null); } List <VertexPositionNormalDiffuseTextureTwo> vertices = new List <VertexPositionNormalDiffuseTextureTwo>(); List <int> hashes = new List <int>(); List <ushort> indices = new List <ushort>(); List <ColladaDrawcall> drawcalls = new List <ColladaDrawcall>(); Dictionary <string, GeometrySource> sources = new Dictionary <string, GeometrySource>(); Dictionary <string, float[]> arrays = new Dictionary <string, float[]>(); Dictionary <string, GeometrySource> verticesRefs = new Dictionary <string, GeometrySource>(); int placeHolderIdx = 0; //Get arrays foreach (var acc in msh.source) { var arr = acc.Item as CL.float_array; arrays.Add(arr.id, FloatArray(arr.Text)); } //Accessors foreach (var acc in msh.source) { sources.Add(acc.id, new GeometrySource(acc, arrays)); } //Process geometry foreach (var item in msh.Items) { if (!(item is CL.triangles || item is CL.polylist || item is CL.polygons)) { FLLog.Warning("Collada", "Ignoring " + item.GetType().Name + " element."); } } int totalTriangles = 0; foreach (var item in msh.Items.Where(x => x is CL.triangles || x is CL.polylist || x is CL.polygons)) { if (item is CL.triangles) { totalTriangles += (int)((CL.triangles)item).count; } else if (item is CL.polylist plist) { totalTriangles += (int)plist.count; } else { totalTriangles += (int)((CL.polygons)item).count; } } if (totalTriangles > 21845) { throw new Exception(string.Format( "Overflow!\nCollada geometry {0} has {1} triangles\nVMeshData has limit of 21845", string.IsNullOrEmpty(geo.name) ? geo.id : geo.name, totalTriangles)); } foreach (var item in msh.Items.Where(x => x is CL.triangles || x is CL.polylist || x is CL.polygons)) { CL.InputLocalOffset[] inputs; int[] pRefs; int indexCount; string materialRef; ColladaMaterial material; if (item is CL.triangles) { var triangles = (CL.triangles)item; indexCount = (int)(triangles.count * 3); pRefs = IntArray(triangles.p); inputs = triangles.input; materialRef = triangles.material; } else if (item is CL.polygons polygons) { indexCount = (int)(polygons.count * 3); int j = 0; pRefs = new int[indexCount]; foreach (var arr in polygons.Items) { if (!(arr is string)) { throw new Exception("Polygons: ph element unsupported"); } var ints = IntArray((string)arr); if (ints.Length != 3) { throw new Exception("Polygons: non-triangle geometry not supported"); } pRefs[j] = ints[0]; pRefs[j + 1] = ints[1]; pRefs[j + 2] = ints[2]; j += 3; } inputs = polygons.input; materialRef = polygons.material; } else { var plist = (CL.polylist)item; pRefs = IntArray(plist.p); foreach (var c in IntArray(plist.vcount)) { if (c != 3) { throw new Exception("Polylist: non-triangle geometry"); } } materialRef = plist.material; inputs = plist.input; indexCount = (int)(plist.count * 3); } if (indexCount == 0) { continue; //Skip empty } material = ParseMaterial(materialRef, matlib, fxlib); int pStride = 0; foreach (var input in inputs) { pStride = Math.Max((int)input.offset, pStride); } pStride++; GeometrySource sourceXYZ = null; int offXYZ = int.MinValue; GeometrySource sourceNORMAL = null; int offNORMAL = int.MinValue; GeometrySource sourceCOLOR = null; int offCOLOR = int.MinValue; GeometrySource sourceUV1 = null; int offUV1 = int.MinValue; GeometrySource sourceUV2 = null; int offUV2 = int.MinValue; int texCount = 0; int startIdx = indices.Count; foreach (var input in inputs) { switch (input.semantic) { case SEM_VERTEX: if (CheckURI(input.source) != msh.vertices.id) { throw new Exception("VERTEX doesn't match mesh vertices"); } foreach (var ip2 in msh.vertices.input) { switch (ip2.semantic) { case SEM_POSITION: offXYZ = (int)input.offset; sourceXYZ = sources[CheckURI(ip2.source)]; break; case SEM_NORMAL: offNORMAL = (int)input.offset; sourceNORMAL = sources[CheckURI(ip2.source)]; conv.FVF |= D3DFVF.NORMAL; break; case SEM_COLOR: offCOLOR = (int)input.offset; sourceCOLOR = sources[CheckURI(ip2.source)]; conv.FVF |= D3DFVF.DIFFUSE; break; case SEM_TEXCOORD: if (texCount == 2) { throw new Exception("Too many texcoords!"); } if (texCount == 1) { offUV2 = (int)input.offset; sourceUV2 = sources[CheckURI(ip2.source)]; conv.FVF &= ~D3DFVF.TEX1; conv.FVF |= D3DFVF.TEX2; } else { offUV1 = (int)input.offset; sourceUV1 = sources[CheckURI(ip2.source)]; if ((conv.FVF & D3DFVF.TEX2) != D3DFVF.TEX2) { conv.FVF |= D3DFVF.TEX1; } } texCount++; break; } } break; case SEM_POSITION: offXYZ = (int)input.offset; sourceXYZ = sources[CheckURI(input.source)]; break; case SEM_NORMAL: offNORMAL = (int)input.offset; sourceNORMAL = sources[CheckURI(input.source)]; conv.FVF |= D3DFVF.NORMAL; break; case SEM_COLOR: offCOLOR = (int)input.offset; sourceCOLOR = sources[CheckURI(input.source)]; conv.FVF |= D3DFVF.DIFFUSE; break; case SEM_TEXCOORD: if (texCount == 2) { throw new Exception("Too many texcoords!"); } if (texCount == 1) { offUV2 = (int)input.offset; sourceUV2 = sources[CheckURI(input.source)]; conv.FVF &= ~D3DFVF.TEX1; conv.FVF |= D3DFVF.TEX2; } else { offUV1 = (int)input.offset; sourceUV1 = sources[CheckURI(input.source)]; if ((conv.FVF & D3DFVF.TEX2) != D3DFVF.TEX2) { conv.FVF |= D3DFVF.TEX1; } } texCount++; break; } } int vertexOffset = vertices.Count; for (int i = 0; i < indexCount; i++) { int idx = i * pStride; var vert = new VertexPositionNormalDiffuseTextureTwo( VecAxis(up, sourceXYZ.GetXYZ(pRefs[idx + offXYZ])), offNORMAL == int.MinValue ? Vector3.Zero : VecAxis(up, sourceNORMAL.GetXYZ(pRefs[idx + offNORMAL])), offCOLOR == int.MinValue ? (uint)Color4.White.ToRgba() : (uint)sourceCOLOR.GetColor(pRefs[idx + offCOLOR]).ToRgba(), offUV1 == int.MinValue ? Vector2.Zero : sourceUV1.GetUV(pRefs[idx + offUV1]), offUV2 == int.MinValue ? Vector2.Zero : sourceUV2.GetUV(pRefs[idx + offUV2]) ); var hash = HashVert(ref vert); var vertIdx = FindDuplicate(hashes, vertices, vertexOffset, ref vert, hash); if (indices.Count >= ushort.MaxValue) { throw new Exception("Too many indices"); } if (vertIdx == -1) { if (vertices.Count + 1 >= ushort.MaxValue) { throw new Exception("Too many vertices"); } indices.Add((ushort)(vertices.Count - vertexOffset)); vertices.Add(vert); hashes.Add(hash); } else { indices.Add((ushort)(vertIdx - vertexOffset)); } } drawcalls.Add(new ColladaDrawcall() { StartIndex = startIdx, StartVertex = vertexOffset, EndVertex = vertices.Count - 1, TriCount = (indices.Count - startIdx) / 3, Material = material }); } conv.Indices = indices.ToArray(); conv.Vertices = vertices.ToArray(); conv.Drawcalls = drawcalls.ToArray(); conv.CalculateDimensions(); return(conv); }
static ColladaGeometry GetGeometry(CL.UpAxisType up, CL.geometry geo) { var conv = new ColladaGeometry() { FVF = D3DFVF.XYZ }; var msh = geo.Item as CL.mesh; if (msh == null) { return(null); } List <VertexPositionNormalDiffuseTextureTwo> vertices = new List <VertexPositionNormalDiffuseTextureTwo>(); List <ushort> indices = new List <ushort>(); List <ColladaDrawcall> drawcalls = new List <ColladaDrawcall>(); Dictionary <string, GeometrySource> sources = new Dictionary <string, GeometrySource>(); Dictionary <string, float[]> arrays = new Dictionary <string, float[]>(); Dictionary <string, GeometrySource> verticesRefs = new Dictionary <string, GeometrySource>(); //Get arrays foreach (var acc in msh.source) { var arr = acc.Item as CL.float_array; arrays.Add(arr.id, FloatArray(arr.Text)); } //Accessors foreach (var acc in msh.source) { sources.Add(acc.id, new GeometrySource(acc, arrays)); } //Process geometry if (msh.Items.Where(x => x is CL.triangles || x is CL.polylist).Count() != msh.Items.Length) { throw new Exception("Non-triangle geometry"); } foreach (var item in msh.Items.Where(x => x is CL.triangles || x is CL.polylist)) { CL.InputLocalOffset[] inputs; int[] pRefs; int triangleCount; string material; if (item is CL.triangles) { var triangles = (CL.triangles)item; pRefs = IntArray(triangles.p); inputs = triangles.input; triangleCount = (int)(triangles.count * 3); material = triangles.material; } else { var plist = (CL.polylist)item; pRefs = IntArray(plist.p); foreach (var c in IntArray(plist.vcount)) { if (c != 3) { throw new Exception("Polylist: non-triangle geometry"); } } material = plist.material; inputs = plist.input; triangleCount = (int)(plist.count * 3); } int pStride = 0; foreach (var input in inputs) { pStride = Math.Max((int)input.offset, pStride); } pStride++; GeometrySource sourceXYZ = null; int offXYZ = int.MinValue; GeometrySource sourceNORMAL = null; int offNORMAL = int.MinValue; GeometrySource sourceCOLOR = null; int offCOLOR = int.MinValue; GeometrySource sourceUV1 = null; int offUV1 = int.MinValue; GeometrySource sourceUV2 = null; int offUV2 = int.MinValue; int texCount = 0; int startIdx = indices.Count; foreach (var input in inputs) { switch (input.semantic) { case SEM_VERTEX: if (CheckURI(input.source) != msh.vertices.id) { throw new Exception("VERTEX doesn't match mesh vertices"); } foreach (var ip2 in msh.vertices.input) { switch (ip2.semantic) { case SEM_POSITION: offXYZ = (int)input.offset; sourceXYZ = sources[CheckURI(ip2.source)]; break; case SEM_NORMAL: offNORMAL = (int)input.offset; sourceNORMAL = sources[CheckURI(ip2.source)]; conv.FVF |= D3DFVF.NORMAL; break; case SEM_COLOR: offCOLOR = (int)input.offset; sourceCOLOR = sources[CheckURI(ip2.source)]; conv.FVF |= D3DFVF.DIFFUSE; break; case SEM_TEXCOORD: if (texCount == 2) { throw new Exception("Too many texcoords!"); } if (texCount == 1) { offUV2 = (int)input.offset; sourceUV2 = sources[CheckURI(ip2.source)]; conv.FVF &= ~D3DFVF.TEX1; conv.FVF |= D3DFVF.TEX2; } else { offUV1 = (int)input.offset; sourceUV1 = sources[CheckURI(ip2.source)]; if ((conv.FVF & D3DFVF.TEX2) != D3DFVF.TEX2) { conv.FVF |= D3DFVF.TEX1; } } texCount++; break; } } break; case SEM_POSITION: offXYZ = (int)input.offset; sourceXYZ = sources[CheckURI(input.source)]; break; case SEM_NORMAL: offNORMAL = (int)input.offset; sourceNORMAL = sources[CheckURI(input.source)]; conv.FVF |= D3DFVF.NORMAL; break; case SEM_COLOR: offCOLOR = (int)input.offset; sourceCOLOR = sources[CheckURI(input.source)]; conv.FVF |= D3DFVF.DIFFUSE; break; case SEM_TEXCOORD: if (texCount == 2) { throw new Exception("Too many texcoords!"); } if (texCount == 1) { offUV2 = (int)input.offset; sourceUV2 = sources[CheckURI(input.source)]; conv.FVF &= ~D3DFVF.TEX1; conv.FVF |= D3DFVF.TEX2; } else { offUV1 = (int)input.offset; sourceUV1 = sources[CheckURI(input.source)]; if ((conv.FVF & D3DFVF.TEX2) != D3DFVF.TEX2) { conv.FVF |= D3DFVF.TEX1; } } texCount++; break; } } for (int i = 0; i < triangleCount; i++) { int idx = i * pStride; var vert = new VertexPositionNormalDiffuseTextureTwo( VecAxis(up, sourceXYZ.GetXYZ(pRefs[idx + offXYZ])), offNORMAL == int.MinValue ? Vector3.Zero : VecAxis(up, sourceNORMAL.GetXYZ(pRefs[idx + offNORMAL])), offCOLOR == int.MinValue ? Color4.White : sourceCOLOR.GetColor(pRefs[idx + offCOLOR]), offUV1 == int.MinValue ? Vector2.Zero : sourceUV1.GetUV(pRefs[idx + offUV1]), offUV2 == int.MinValue ? Vector2.Zero : sourceUV2.GetUV(pRefs[idx + offUV2]) ); var vertIdx = vertices.IndexOf(vert); if (indices.Count >= ushort.MaxValue) { throw new Exception("Too many indices"); } if (vertIdx == -1) { if (vertices.Count + 1 >= ushort.MaxValue) { throw new Exception("Overflow"); } indices.Add((ushort)vertices.Count); vertices.Add(vert); } else { indices.Add((ushort)vertIdx); } } drawcalls.Add(new ColladaDrawcall() { Start = startIdx, TriCount = (indices.Count - startIdx) / 3, Material = string.IsNullOrEmpty(material) ? "NullMaterial" : material }); } conv.Indices = indices.ToArray(); conv.Vertices = vertices.ToArray(); conv.Drawcalls = drawcalls.ToArray(); conv.CalculateDimensions(); return(conv); }