// This method is optional. By sorting the wad textures it may result ahead of time // we may have better texture space efficency. public void PreloadReplaceWad(IEnumerable <WadMoveable> newMoveables, IEnumerable <WadStatic> newStatics) { Dispose(); try { PreloadReplaceTextures(newMoveables, newStatics); } catch (TextureAtlasFullException) { logger.Error("Unable to preload wad because the texture atlas became too full!"); return; } // Create moveable models Parallel.ForEach(newMoveables, moveable => { var model = AnimatedModel.FromWadMoveable(GraphicsDevice, moveable, AllocateTexture); lock (Moveables) Moveables.Add(moveable, model); }); // Create static meshes Parallel.ForEach(newStatics, @static => { var model = new StaticModel(GraphicsDevice); model.Meshes.Add(ObjectMesh.FromWad2(GraphicsDevice, @static.Mesh, AllocateTexture)); model.UpdateBuffers(); lock (Statics) Statics.Add(@static, model); }); }
protected static void PutObjectVertexAndIndex(Vector3 v, ObjectMesh mesh, Submesh submesh, Vector2 uv, int submeshIndex, short color, Vector2 positionInAtlas) { var newVertex = new ObjectVertex(); newVertex.Position = new Vector3(v.X, v.Y, v.Z); newVertex.UV = new Vector2((positionInAtlas.X + uv.X) / WadRenderer.TextureAtlasSize, (positionInAtlas.Y + uv.Y) / WadRenderer.TextureAtlasSize); var shade = 1.0f - color / 8191.0f; newVertex.Shade = new Vector2(shade, 0.0f); mesh.Vertices.Add(newVertex); submesh.Indices.Add((ushort)(mesh.Vertices.Count - 1)); }
public StaticModel GetStatic(WadStatic @static, bool maybeRebuildAll = true) { // Check if the data is already loaded // If yes attempt to use that one StaticModel model; if (Statics.TryGetValue(@static, out model)) { if (model.Version >= @static.Version) { return(model); } ReclaimTextureSpace(model); model.Dispose(); Statics.Remove(@static); } // The data is either new or has changed, unfortunately we need to reload it try { model = new StaticModel(GraphicsDevice); model.Meshes.Add(ObjectMesh.FromWad2(GraphicsDevice, @static.Mesh, AllocateTexture)); model.UpdateBuffers(); } catch (TextureAtlasFullException exc) { logger.Info(exc.Message); if (maybeRebuildAll) { logger.Info("Starting to rebuild the entire atlas."); Dispose(); return(GetStatic(@static, false)); } } Statics.Add(@static, model); return(model); }
public static ObjectMesh FromWad2(GraphicsDevice device, WadMesh msh, Func <WadTexture, VectorInt2> allocateTexture) { Console.WriteLine(msh.Name); // Initialize the mesh var mesh = new ObjectMesh(device, msh.Name); // Prepare materials var materialOpaque = new Material(Material.Material_Opaque + "_0_0_0_0", null, false, false, 0); var materialOpaqueDoubleSided = new Material(Material.Material_OpaqueDoubleSided + "_0_0_1_0", null, false, true, 0); var materialAdditiveBlending = new Material(Material.Material_AdditiveBlending + "_0_1_0_0", null, true, false, 0); var materialAdditiveBlendingDoubleSided = new Material(Material.Material_AdditiveBlendingDoubleSided + "_0_1_1_0", null, true, true, 0); mesh.Materials = new List <Material>(); mesh.Materials.Add(materialOpaque); mesh.Materials.Add(materialOpaqueDoubleSided); mesh.Materials.Add(materialAdditiveBlending); mesh.Materials.Add(materialAdditiveBlendingDoubleSided); mesh.Submeshes.Add(materialOpaque, new Submesh(materialOpaque)); mesh.Submeshes.Add(materialOpaqueDoubleSided, new Submesh(materialOpaqueDoubleSided)); mesh.Submeshes.Add(materialAdditiveBlending, new Submesh(materialAdditiveBlending)); mesh.Submeshes.Add(materialAdditiveBlendingDoubleSided, new Submesh(materialAdditiveBlendingDoubleSided)); mesh.BoundingBox = msh.BoundingBox; mesh.BoundingSphere = msh.BoundingSphere; // For some reason, wad meshes sometimes may have position count desynced from color count, so we check that too. var hasShades = msh.VerticesShades.Count != 0 && msh.VerticesPositions.Count == msh.VerticesShades.Count; for (int j = 0; j < msh.Polys.Count; j++) { WadPolygon poly = msh.Polys[j]; Vector2 positionInPackedTexture = allocateTexture((WadTexture)poly.Texture.Texture); // Get the right submesh var submesh = mesh.Submeshes[materialOpaque]; if (poly.Texture.BlendMode == BlendMode.Additive) { if (poly.Texture.DoubleSided) { submesh = mesh.Submeshes[materialAdditiveBlendingDoubleSided]; } else { submesh = mesh.Submeshes[materialAdditiveBlending]; } } else { if (poly.Texture.DoubleSided) { submesh = mesh.Submeshes[materialOpaqueDoubleSided]; } } // Do half-pixel correction on texture to prevent bleeding var coords = poly.Texture.TexCoords; var shape = (int)TextureExtensions.GetTextureShapeType(poly.Texture.TexCoords, poly.Shape == WadPolygonShape.Triangle); for (int i = 0; i < (poly.Shape == WadPolygonShape.Triangle /*poly.Texture.TextureIsTriangle*/ ? 3 : 4); i++) { if (poly.Shape == WadPolygonShape.Triangle /*poly.Texture.TextureIsTriangle*/) { coords[i] += TextureExtensions.CompensationTris[shape, i]; } else { coords[i] += TextureExtensions.CompensationQuads[shape, i]; } } if (poly.Shape == WadPolygonShape.Triangle) { int v1 = poly.Index0; int v2 = poly.Index1; int v3 = poly.Index2; PutObjectVertexAndIndex(msh.VerticesPositions[v1], msh.VerticesNormals[v1], mesh, submesh, coords[0], 0, (short)(hasShades ? msh.VerticesShades[v1] : 0), positionInPackedTexture); PutObjectVertexAndIndex(msh.VerticesPositions[v2], msh.VerticesNormals[v2], mesh, submesh, coords[1], 0, (short)(hasShades ? msh.VerticesShades[v2] : 0), positionInPackedTexture); PutObjectVertexAndIndex(msh.VerticesPositions[v3], msh.VerticesNormals[v3], mesh, submesh, coords[2], 0, (short)(hasShades ? msh.VerticesShades[v3] : 0), positionInPackedTexture); } else { int v1 = poly.Index0; int v2 = poly.Index1; int v3 = poly.Index2; int v4 = poly.Index3; PutObjectVertexAndIndex(msh.VerticesPositions[v1], msh.VerticesNormals[v1], mesh, submesh, coords[0], 0, (short)(hasShades ? msh.VerticesShades[v1] : 0), positionInPackedTexture); PutObjectVertexAndIndex(msh.VerticesPositions[v2], msh.VerticesNormals[v2], mesh, submesh, coords[1], 0, (short)(hasShades ? msh.VerticesShades[v2] : 0), positionInPackedTexture); PutObjectVertexAndIndex(msh.VerticesPositions[v4], msh.VerticesNormals[v4], mesh, submesh, coords[3], 0, (short)(hasShades ? msh.VerticesShades[v4] : 0), positionInPackedTexture); PutObjectVertexAndIndex(msh.VerticesPositions[v4], msh.VerticesNormals[v4], mesh, submesh, coords[3], 0, (short)(hasShades ? msh.VerticesShades[v4] : 0), positionInPackedTexture); PutObjectVertexAndIndex(msh.VerticesPositions[v2], msh.VerticesNormals[v2], mesh, submesh, coords[1], 0, (short)(hasShades ? msh.VerticesShades[v2] : 0), positionInPackedTexture); PutObjectVertexAndIndex(msh.VerticesPositions[v3], msh.VerticesNormals[v3], mesh, submesh, coords[2], 0, (short)(hasShades ? msh.VerticesShades[v3] : 0), positionInPackedTexture); } } mesh.UpdateBuffers(); return(mesh); }