unsafe private void FillVerticesUV2(FLVER0.Mesh mesh, Span <Vector3> pickingVerts, IntPtr vertBuffer) { Span <FlverLayoutUV2> verts = new Span <FlverLayoutUV2>(vertBuffer.ToPointer(), mesh.Vertices.Count); for (int i = 0; i < mesh.Vertices.Count; i++) { var vert = mesh.Vertices[i]; verts[i] = new FlverLayoutUV2(); pickingVerts[i] = new Vector3(vert.Position.X, vert.Position.Y, vert.Position.Z); fixed(FlverLayoutUV2 *v = &verts[i]) { FillVertex(ref (*v).Position, ref vert); FillNormalSNorm8((*v).Normal, ref vert); FillUVShort((*v).Uv1, ref vert, 0); FillUVShort((*v).Uv2, ref vert, 1); if (vert.TangentCount > 0) { FillBinormalBitangentSNorm8((*v).Binormal, (*v).Bitangent, ref vert, 0); } else { FillBinormalBitangentSNorm8Zero((*v).Binormal, (*v).Bitangent); } } } }
unsafe private void FillVerticesNormalOnly(FLVER0.Mesh mesh, Span <Vector3> pickingVerts, IntPtr vertBuffer) { Span <FlverLayoutSky> verts = new Span <FlverLayoutSky>(vertBuffer.ToPointer(), mesh.Vertices.Count); for (int i = 0; i < mesh.Vertices.Count; i++) { var vert = mesh.Vertices[i]; verts[i] = new FlverLayoutSky(); pickingVerts[i] = new Vector3(vert.Position.X, vert.Position.Y, vert.Position.Z); fixed(FlverLayoutSky *v = &verts[i]) { FillVertex(ref (*v).Position, ref vert); FillNormalSNorm8((*v).Normal, ref vert); } } }
unsafe private void ProcessMesh(FLVER0.Mesh mesh, FlverSubmesh dest) { var factory = Scene.Renderer.Factory; dest.Material = GPUMaterials[mesh.MaterialIndex]; //var MeshVertices = VerticesPool.Rent(mesh.VertexCount); var vSize = dest.Material.VertexSize; var meshVertices = Marshal.AllocHGlobal(mesh.Vertices.Count * (int)vSize); dest.PickingVertices = Marshal.AllocHGlobal(mesh.Vertices.Count * sizeof(Vector3)); var pvhandle = new Span <Vector3>(dest.PickingVertices.ToPointer(), mesh.Vertices.Count); if (dest.Material.LayoutType == MeshLayoutType.LayoutSky) { FillVerticesNormalOnly(mesh, pvhandle, meshVertices); } else if (dest.Material.LayoutType == MeshLayoutType.LayoutUV2) { FillVerticesUV2(mesh, pvhandle, meshVertices); } else { FillVerticesStandard(mesh, pvhandle, meshVertices); } dest.VertexCount = mesh.Vertices.Count; dest.MeshFacesets = new List <FlverSubmesh.FlverSubmeshFaceSet>(); bool is32bit = false;//FlverDeS.Version > 0x20005 && mesh.Vertices.Count > 65535; int indicesTotal = 0; ushort[] fs16 = null; int[] fs32 = null; int idxoffset = 0; if (mesh.VertexIndices.Count != 0) { var indices = mesh.Triangulate(FlverDeS.Version).ToArray(); uint buffersize = (uint)indices.Length * (is32bit ? 4u : 2u); indicesTotal = indices.Length; if (is32bit) { fs32 = new int[indicesTotal]; } else { fs16 = new ushort[indicesTotal]; } var newFaceSet = new FlverSubmesh.FlverSubmeshFaceSet() { BackfaceCulling = true, IsTriangleStrip = false, //IndexBuffer = factory.CreateBuffer(new BufferDescription(buffersize, BufferUsage.IndexBuffer)), IndexOffset = idxoffset, IndexCount = indices.Length, Is32Bit = is32bit, PickingIndicesCount = indices.Length, //PickingIndices = Marshal.AllocHGlobal(indices.Length * 4), }; fixed(void *iptr = indices) { //Unsafe.CopyBlock(newFaceSet.PickingIndices.ToPointer(), iptr, (uint)indices.Length * 4); } if (is32bit) { for (int i = 0; i < indices.Length; i++) { if (indices[i] == 0xFFFF && indices[i] > mesh.Vertices.Count) { fs32[newFaceSet.IndexOffset + i] = -1; } else { fs32[newFaceSet.IndexOffset + i] = indices[i]; } } } else { for (int i = 0; i < indices.Length; i++) { if (indices[i] == 0xFFFF && indices[i] > mesh.Vertices.Count) { fs16[newFaceSet.IndexOffset + i] = 0xFFFF; } else { fs16[newFaceSet.IndexOffset + i] = (ushort)indices[i]; } } } dest.MeshFacesets.Add(newFaceSet); } dest.Bounds = BoundingBox.CreateFromPoints((Vector3 *)dest.PickingVertices.ToPointer(), dest.VertexCount, 12, Quaternion.Identity, Vector3.Zero, Vector3.One); uint vbuffersize = (uint)mesh.Vertices.Count * (uint)vSize; dest.GeomBuffer = Scene.Renderer.GeometryBufferAllocator.Allocate(vbuffersize, (uint)indicesTotal * (is32bit ? 4u : 2u), (int)vSize, 4, (h) => { h.FillVBuffer(meshVertices, vSize * (uint)mesh.Vertices.Count, () => { Marshal.FreeHGlobal(meshVertices); }); if (is32bit) { h.FillIBuffer(fs32); } else { h.FillIBuffer(fs16); } }); if (CaptureMaterialLayouts) { lock (_matLayoutLock) { if (!MaterialLayouts.ContainsKey(dest.Material.MaterialName)) { MaterialLayouts.Add(dest.Material.MaterialName, Flver.BufferLayouts[mesh.LayoutIndex]); } } } }
public FlverSubmeshRenderer(Model parent, FLVER0 flvr, FLVER0.Mesh mesh) { Parent = parent; MaterialName = flvr.Materials[mesh.MaterialIndex].Name; var shortMaterialName = MiscUtil.GetFileNameWithoutDirectoryOrExtension(flvr.Materials[mesh.MaterialIndex].MTD); if (shortMaterialName.EndsWith("_Alp") || shortMaterialName.Contains("_Edge") || shortMaterialName.Contains("_Decal") || shortMaterialName.Contains("_Cloth") || shortMaterialName.Contains("_al") || shortMaterialName.Contains("BlendOpacity")) { DrawStep = GFXDrawStep.AlphaEdge; } else { DrawStep = GFXDrawStep.Opaque; } bool hasLightmap = false; foreach (var matParam in flvr.Materials[mesh.MaterialIndex].Textures) { if (matParam == null || matParam.Type == null) { break; } var paramNameCheck = matParam.Type.ToUpper(); // DS3/BB if (paramNameCheck == "G_DIFFUSETEXTURE") { TexNameDiffuse = matParam.Path; } else if (paramNameCheck == "G_SPECULARTEXTURE") { TexNameSpecular = matParam.Path; } else if (paramNameCheck == "G_BUMPMAPTEXTURE") { TexNameNormal = matParam.Path; } else if (paramNameCheck == "G_DOLTEXTURE1") { TexNameDOL1 = matParam.Path; } else if (paramNameCheck == "G_DOLTEXTURE2") { TexNameDOL2 = matParam.Path; } // DS1 params else if (paramNameCheck == "G_DIFFUSE") { TexNameDiffuse = matParam.Path; } else if (paramNameCheck == "G_SPECULAR") { TexNameSpecular = matParam.Path; } else if (paramNameCheck == "G_BUMPMAP") { TexNameNormal = matParam.Path; } else if (paramNameCheck == "G_LIGHTMAP") { TexNameDOL1 = matParam.Path; hasLightmap = true; } } // MTD lookup MTD mtd = null;// InterrootLoader.GetMTD(flvr.Materials[mesh.MaterialIndex].MTD); var MeshVertices = new VertexPositionColorNormalTangentTexture[mesh.Vertices.Count]; for (int i = 0; i < mesh.Vertices.Count; i++) { var vert = mesh.Vertices[i]; MeshVertices[i] = new VertexPositionColorNormalTangentTexture(); MeshVertices[i].Position = new Vector3(vert.Position.X, vert.Position.Y, vert.Position.Z); if (vert.Normal != null && vert.Tangents != null && vert.Tangents.Count > 0) { MeshVertices[i].Normal = Vector3.Normalize(new Vector3(vert.Normal.X, vert.Normal.Y, vert.Normal.Z)); MeshVertices[i].Binormal = Vector3.Normalize(new Vector3(vert.Bitangent.X, vert.Bitangent.Y, vert.Bitangent.Z)); MeshVertices[i].Tangent = Vector3.Normalize(new Vector3(vert.Tangents[0].X, vert.Tangents[0].Y, vert.Tangents[0].Z)); } if (vert.UVs.Count > 0) { MeshVertices[i].TextureCoordinate = new Vector2(vert.UVs[0].X, vert.UVs[0].Y); if (vert.UVs.Count > 1 && hasLightmap) { if (mtd == null) { // Really stupid heuristic to determine light map UVs without reading mtd files or something if (vert.UVs.Count > 2 && flvr.Materials[mesh.MaterialIndex].Textures.Count > 11) { MeshVertices[i].TextureCoordinate2 = new Vector2(vert.UVs[2].X, vert.UVs[2].Y); } else { MeshVertices[i].TextureCoordinate2 = new Vector2(vert.UVs[1].X, vert.UVs[1].Y); } } else { // Better heuristic with MTDs int uvindex = mtd.Textures.Find(tex => tex.Type.ToUpper() == "G_LIGHTMAP" || tex.Type.ToUpper() == "G_DOLTEXTURE1").UVNumber; int uvoffset = 1; for (int j = 1; j < uvindex; j++) { if (!mtd.Textures.Any(t => (t.UVNumber == j))) { uvoffset++; } } uvindex -= uvoffset; if (vert.UVs.Count > uvindex) { MeshVertices[i].TextureCoordinate2 = new Vector2(vert.UVs[uvindex].X, vert.UVs[uvindex].Y); } else { MeshVertices[i].TextureCoordinate2 = new Vector2(vert.UVs[1].X, vert.UVs[1].Y); } } } else { MeshVertices[i].TextureCoordinate2 = Vector2.Zero; } } else { MeshVertices[i].TextureCoordinate = Vector2.Zero; MeshVertices[i].TextureCoordinate2 = Vector2.Zero; } } VertexCount = MeshVertices.Length; MeshFacesets = new List <FlverSubmeshRendererFaceSet>(); var tlist = mesh.ToTriangleList(); var newFaceSet = new FlverSubmeshRendererFaceSet() { BackfaceCulling = true, IsTriangleStrip = false, IndexBuffer = new IndexBuffer( GFX.Device, IndexElementSize.SixteenBits, tlist.Length, BufferUsage.WriteOnly), IndexCount = tlist.Length, }; newFaceSet.IndexBuffer.SetData(tlist); MeshFacesets.Add(newFaceSet); Bounds = BoundingBox.CreateFromPoints(MeshVertices.Select(x => x.Position)); VertBuffer = new VertexBuffer(GFX.Device, typeof(VertexPositionColorNormalTangentTexture), MeshVertices.Length, BufferUsage.WriteOnly); VertBuffer.SetData(MeshVertices); VertBufferBinding = new VertexBufferBinding(VertBuffer, 0, 0); TryToLoadTextures(); }