private static Node ConvertNode(Assimp.Node aiNode, List <Assimp.Mesh> aiMeshes, List <MaterialBuildInfo> materialBuildInfos) { Node ConvertHierarchyNodeRecursively(Assimp.Node curAiNode, ref Node previousSibling, Node parent, ref Assimp.Matrix4x4 parentNodeWorldTransform) { var nodeWorldTransform = curAiNode.Transform * parentNodeWorldTransform; var nodeInverseWorldTransform = nodeWorldTransform; nodeInverseWorldTransform.Inverse(); curAiNode.Transform.Decompose(out var scale, out var rotation, out var translation); // Create node var node = new Node(AssimpHelper.FromAssimp(translation), AngleVector.FromQuaternion(AssimpHelper.FromAssimp(rotation)), AssimpHelper.FromAssimp(scale), parent); if (curAiNode.HasMeshes) { var geometry = new Geometry(); // Convert meshes var vertexPositions = new List <Assimp.Vector3D>(); var vertexNormals = new List <Assimp.Vector3D>(); var vertexUVs = new List <Assimp.Vector3D>(); var vertexColors = new List <Assimp.Color4D>(); var lastRenderState = new MeshRenderState(); foreach (var aiMeshIndex in curAiNode.MeshIndices) { var aiMesh = aiMeshes[aiMeshIndex]; var material = materialBuildInfos[aiMesh.MaterialIndex]; var mesh = new Mesh(); var renderState = new MeshRenderState(); renderState.IndexFlags = IndexAttributeFlags.HasPosition | IndexAttributeFlags.Position16BitIndex; var useColors = false; var hasColors = aiMesh.HasVertexColors(0); var hasUVs = aiMesh.HasTextureCoords(0); var hasNormals = aiMesh.HasNormals; if (hasColors || !hasNormals) { renderState.IndexFlags |= IndexAttributeFlags.HasColor | IndexAttributeFlags.Color16BitIndex; useColors = true; } else { renderState.IndexFlags |= IndexAttributeFlags.HasNormal | IndexAttributeFlags.Normal16BitIndex; } if (hasUVs) { renderState.IndexFlags |= IndexAttributeFlags.HasUV | IndexAttributeFlags.UV16BitIndex; } // Convert faces var triangleIndices = new Index[aiMesh.FaceCount * 3]; for (var i = 0; i < aiMesh.Faces.Count; i++) { var aiFace = aiMesh.Faces[i]; Debug.Assert(aiFace.IndexCount == 3); for (var j = 0; j < aiFace.Indices.Count; j++) { int aiFaceIndex = aiFace.Indices[j]; var position = aiMesh.Vertices[aiFaceIndex]; var positionIndex = vertexPositions.IndexOf(position); if (positionIndex == -1) { positionIndex = vertexPositions.Count; vertexPositions.Add(position); } var normalIndex = 0; var colorIndex = 0; var uvIndex = 0; if (useColors) { var color = hasColors ? aiMesh.VertexColorChannels[0][aiFaceIndex] : new Assimp.Color4D(); colorIndex = vertexColors.IndexOf(color); if (colorIndex == -1) { colorIndex = vertexColors.Count; vertexColors.Add(color); } } else { var normal = aiMesh.Normals[aiFaceIndex]; normalIndex = vertexNormals.IndexOf(normal); if (normalIndex == -1) { normalIndex = vertexNormals.Count; vertexNormals.Add(normal); } } if (hasUVs) { var uv = aiMesh.TextureCoordinateChannels[0][aiFaceIndex]; uvIndex = vertexUVs.IndexOf(uv); if (uvIndex == -1) { uvIndex = vertexUVs.Count; vertexUVs.Add(uv); } } triangleIndices[(i * 3) + j] = new Index { PositionIndex = ( ushort )positionIndex, NormalIndex = ( ushort )normalIndex, ColorIndex = ( ushort )colorIndex, UVIndex = ( ushort )uvIndex }; } } // Build display list var displayList = new GXDisplayList(GXPrimitive.Triangles, triangleIndices); mesh.DisplayLists.Add(displayList); // Set up render params var indexFlagsParam = new IndexAttributeFlagsParam(renderState.IndexFlags); mesh.Parameters.Add(indexFlagsParam); if (useColors) { mesh.Parameters.Add(new LightingParams(LightingParams.Preset.Colors)); } else { mesh.Parameters.Add(new LightingParams(LightingParams.Preset.Normals)); } mesh.Parameters.Add(new TextureParams(( ushort )(material.TextureId))); mesh.Parameters.Add(new MipMapParams()); geometry.OpaqueMeshes.Add(mesh); } // Build vertex buffers if (vertexPositions.Count > 0) { geometry.VertexBuffers.Add(new VertexPositionBuffer(vertexPositions.Select(x => { Assimp.Unmanaged.AssimpLibrary.Instance.TransformVecByMatrix4(ref x, ref nodeInverseWorldTransform); return(AssimpHelper.FromAssimp(x)); }).ToArray())); } if (vertexNormals.Count > 0) { nodeInverseWorldTransform.Transpose(); geometry.VertexBuffers.Add(new VertexNormalBuffer(vertexNormals.Select(x => { Assimp.Unmanaged.AssimpLibrary.Instance.TransformVecByMatrix4(ref x, ref nodeInverseWorldTransform); return(AssimpHelper.FromAssimp(x)); }).ToArray())); } if (vertexColors.Count > 0) { geometry.VertexBuffers.Add(new VertexColorBuffer(vertexColors.Select(AssimpHelper.FromAssimp).ToArray())); } if (vertexUVs.Count > 0) { geometry.VertexBuffers.Add(new VertexUVBuffer(vertexUVs.Select(x => UVCodec.Encode1023(AssimpHelper .FromAssimpAsVector2(x))) .ToArray())); } } // Set sibling (next) reference of previous if (previousSibling != null) { previousSibling.Sibling = node; } previousSibling = node; if (curAiNode.HasChildren) { Node childPreviousSibling = null; foreach (var aiChildNode in curAiNode.Children) { var childNode = ConvertHierarchyNodeRecursively(aiChildNode, ref childPreviousSibling, node, ref nodeWorldTransform); // Make sure to set the 'first child' reference if we haven't already if (node.Child == null) { node.Child = childNode; } } } return(node); } // Dummy! Node dummy = null; var identity = Assimp.Matrix4x4.Identity; return(ConvertHierarchyNodeRecursively(aiNode, ref dummy, null, ref identity)); }
private static GC.Geometry ConvertBasicToGCGeometry(Basic.Geometry basicGeometry) { var geometry = new GC.Geometry(); geometry.VertexBuffers.Add(new GC.VertexPositionBuffer(basicGeometry.VertexPositions)); var positionFlags = GC.IndexAttributeFlags.HasPosition; if (basicGeometry.VertexCount > byte.MaxValue) { positionFlags |= GC.IndexAttributeFlags.Position16BitIndex; } var indexFlagsParams = new List <GC.IndexAttributeFlagsParam>(); var normals = new List <Vector3>(); var uvs = new List <Vector2 <short> >(); var colors = new List <Color>(); foreach (var basicMesh in basicGeometry.Meshes) { var basicMaterial = basicGeometry.Materials[basicMesh.MaterialId]; var mesh = new GC.Mesh(); var indexFlags = positionFlags; var useColors = false; var hasColors = basicMesh.Colors != null; var hasUVs = basicMesh.UVs != null; var hasVertexNormals = basicGeometry.VertexNormals != null; var hasNormals = hasVertexNormals || basicMesh.Normals != null; if (hasColors || !hasNormals) { indexFlags |= GC.IndexAttributeFlags.HasColor; useColors = true; } else { indexFlags |= GC.IndexAttributeFlags.HasNormal; } if (hasUVs) { indexFlags |= GC.IndexAttributeFlags.HasUV; } //Debug.Assert( indexFlags == ( GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.HasNormal ) || // indexFlags == ( GC.IndexAttributeFlags.Position16BitIndex | GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.Normal16BitIndex | GC.IndexAttributeFlags.HasNormal ) || // indexFlags == ( GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.HasColor ) || // indexFlags == ( GC.IndexAttributeFlags.Position16BitIndex | GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.Color16BitIndex | GC.IndexAttributeFlags.HasColor ) || // indexFlags == ( GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.HasNormal | GC.IndexAttributeFlags.HasUV ) || // indexFlags == ( GC.IndexAttributeFlags.Position16BitIndex | GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.Normal16BitIndex | GC.IndexAttributeFlags.HasNormal | GC.IndexAttributeFlags.HasUV ) || // indexFlags == ( GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.HasColor | GC.IndexAttributeFlags.HasUV ) || // indexFlags == ( GC.IndexAttributeFlags.Position16BitIndex | GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.Color16BitIndex | GC.IndexAttributeFlags.HasColor | GC.IndexAttributeFlags.HasUV ) || // indexFlags == ( GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.HasNormal | GC.IndexAttributeFlags.UV16BitIndex | GC.IndexAttributeFlags.HasUV ) || // indexFlags == ( GC.IndexAttributeFlags.Position16BitIndex | GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.Normal16BitIndex | GC.IndexAttributeFlags.HasNormal | GC.IndexAttributeFlags.UV16BitIndex | GC.IndexAttributeFlags.HasUV ) || // indexFlags == ( GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.HasColor | GC.IndexAttributeFlags.UV16BitIndex | GC.IndexAttributeFlags.HasUV ) || // indexFlags == ( GC.IndexAttributeFlags.Position16BitIndex | GC.IndexAttributeFlags.HasPosition | GC.IndexAttributeFlags.Color16BitIndex | GC.IndexAttributeFlags.HasColor | GC.IndexAttributeFlags.UV16BitIndex | GC.IndexAttributeFlags.HasUV ) ); // Set up parameters var indexFlagsParam = new GC.IndexAttributeFlagsParam(indexFlags); mesh.Parameters.Add(indexFlagsParam); indexFlagsParams.Add(indexFlagsParam); if (useColors) { mesh.Parameters.Add(new GC.LightingParams(GC.LightingParams.Preset.Colors)); } else { mesh.Parameters.Add(new GC.LightingParams(GC.LightingParams.Preset.Normals)); } mesh.Parameters.Add(new GC.TextureParams(( ushort )(basicMaterial.TextureId))); mesh.Parameters.Add(new GC.MipMapParams()); // Build display list var basicTriangles = basicMesh.ToTriangles(); for (int i = 0; i < basicTriangles.Length; i += 3) { var temp = basicTriangles[i]; basicTriangles[i] = basicTriangles[i + 2]; basicTriangles[i + 2] = temp; } var displayListIndices = new GC.Index[basicTriangles.Length]; for (int i = 0; i < basicTriangles.Length; i++) { var index = new GC.Index(); var basicIndex = basicTriangles[i]; index.PositionIndex = basicIndex.VertexIndex; if (useColors) { var color = hasColors ? basicIndex.Color : Color.White; var colorIndex = colors.IndexOf(color); if (colorIndex == -1) { colorIndex = colors.Count; colors.Add(color); } index.ColorIndex = ( ushort )colorIndex; } else { var normal = hasVertexNormals ? basicGeometry.VertexNormals[basicIndex.VertexIndex] : basicIndex.Normal; var normalIndex = normals.IndexOf(normal); if (normalIndex == -1) { normalIndex = normals.Count; normals.Add(normal); } index.NormalIndex = ( ushort )normalIndex; } if (hasUVs) { var uv = basicIndex.UV; var uvIndex = uvs.IndexOf(uv); if (uvIndex == -1) { uvIndex = uvs.Count; uvs.Add(uv); } index.UVIndex = ( ushort )uvIndex; } displayListIndices[i] = index; } var displayList = new GC.GXDisplayList(GC.GXPrimitive.Triangles, displayListIndices); mesh.DisplayLists.Add(displayList); geometry.OpaqueMeshes.Add(mesh); } if (normals.Count > 0) { if (normals.Count > byte.MaxValue) { foreach (var param in indexFlagsParams) { if (param.Flags.HasFlag(GC.IndexAttributeFlags.HasNormal)) { param.Flags |= GC.IndexAttributeFlags.Normal16BitIndex; } } } geometry.VertexBuffers.Add(new GC.VertexNormalBuffer(normals.ToArray())); } if (colors.Count > 0) { if (colors.Count > byte.MaxValue) { foreach (var param in indexFlagsParams) { if (param.Flags.HasFlag(GC.IndexAttributeFlags.HasColor)) { param.Flags |= GC.IndexAttributeFlags.Color16BitIndex; } } } geometry.VertexBuffers.Add(new GC.VertexColorBuffer(colors.ToArray())); } if (uvs.Count > 0) { if (uvs.Count > byte.MaxValue) { foreach (var param in indexFlagsParams) { if (param.Flags.HasFlag(GC.IndexAttributeFlags.HasUV)) { param.Flags |= GC.IndexAttributeFlags.UV16BitIndex; } } } geometry.VertexBuffers.Add(new GC.VertexUVBuffer(uvs.ToArray())); } geometry.Bounds = basicGeometry.Bounds; return(geometry); }
public void Read(EndianBinaryReader reader, MeshContext context) { var meshParamListOffset = reader.ReadInt32(); var meshParamCount = reader.ReadInt32(); var displayListOffset = reader.ReadInt32(); var displayListSize = reader.ReadInt32(); reader.ReadAtOffset(meshParamListOffset, () => { Parameters = new List <Param>(); for (int i = 0; i < meshParamCount; i++) { var type = ( MeshStateParamType )reader.ReadInt32(); Param param; switch (type) { case MeshStateParamType.IndexAttributeFlags: param = new IndexAttributeFlagsParam(); break; case MeshStateParamType.Lighting: param = new LightingParams(); break; case MeshStateParamType.BlendAlpha: param = new BlendAlphaParam(); break; case MeshStateParamType.AmbientColor: param = new AmbientColorParam(); break; case MeshStateParamType.Texture: param = new TextureParams(); break; case MeshStateParamType.MipMap: param = new MipMapParams(); break; default: param = new UnknownParam(); break; } param.ReadBody(type, reader); Parameters.Add(param); } }); // Hack(TGE): look up index attributes flag in params to parse display lists foreach (var param in Parameters) { if (param.Type == MeshStateParamType.IndexAttributeFlags) { context.IndexAttributeFlags = (( IndexAttributeFlagsParam )param).Flags; } } reader.ReadAtOffset(displayListOffset, () => { DisplayLists = new List <GXDisplayList>(); var endPosition = reader.Position + displayListSize; while (reader.ReadByte() != 0 && reader.Position < endPosition) { reader.SeekCurrent(-1); var displayList = reader.ReadObject <GXDisplayList>(context.IndexAttributeFlags); DisplayLists.Add(displayList); } }); }