Example #1
0
        public static RoomExportResult ExportRooms(IEnumerable <Room> roomsToExport, string filePath, Level level, bool exportInWorldCoordinates = false)
        {
            RoomExportResult result = new RoomExportResult();

            try
            {
                //Prepare data for export
                var model        = new IOModel();
                var usedTextures = new List <Texture>();
                var splitPages   = new List <SplitPageReference>();

                foreach (var room in roomsToExport)
                {
                    for (int x = 0; x < room.NumXSectors; x++)
                    {
                        for (int z = 0; z < room.NumZSectors; z++)
                        {
                            var block = room.GetBlock(new VectorInt2(x, z));
                            for (int faceType = 0; faceType < (int)BlockFace.Count; faceType++)
                            {
                                var faceTexture = block.GetFaceTexture((BlockFace)faceType);
                                if (faceTexture.TextureIsInvisible || faceTexture.TextureIsUnavailable || faceTexture.Texture == null)
                                {
                                    continue;
                                }
                                if (!usedTextures.Contains(faceTexture.Texture))
                                {
                                    usedTextures.Add(faceTexture.Texture);
                                }
                            }
                        }
                    }
                }

                for (int j = 0; j < usedTextures.Count; j++)
                {
                    var    tex       = usedTextures[j];
                    int    numXPages = getNumXPages(tex.Image.Width);
                    int    numYPages = getNumYPages(tex.Image.Height);
                    string baseName  = Path.GetFileNameWithoutExtension(tex.Image.FileName);

                    for (int y = 0; y < numYPages; y++)
                    {
                        for (int x = 0; x < numXPages; x++)
                        {
                            // Generate future page reference but postpone actual file creation until model is made.
                            string textureFileName = baseName + "_" + x + "_" + y + ".png";
                            var    page            = new SplitPageReference(tex, y * numXPages + x, x, y, Path.Combine(Path.GetDirectoryName(filePath), textureFileName));
                            splitPages.Add(page);

                            var matOpaque                      = new IOMaterial(Material.Material_Opaque + "_" + j + "_" + page.Index, tex, page.Path, false, false, 0, page.Index);
                            var matOpaqueDoubleSided           = new IOMaterial(Material.Material_OpaqueDoubleSided + "_" + j + "_" + page.Index, tex, page.Path, false, true, 0, page.Index);
                            var matAdditiveBlending            = new IOMaterial(Material.Material_AdditiveBlending + "_" + j + "_" + page.Index, tex, page.Path, true, false, 0, page.Index);
                            var matAdditiveBlendingDoubleSided = new IOMaterial(Material.Material_AdditiveBlendingDoubleSided + "_" + j + "_" + page.Index, tex, page.Path, true, true, 0, page.Index);

                            model.Materials.Add(matOpaque);
                            model.Materials.Add(matOpaqueDoubleSided);
                            model.Materials.Add(matAdditiveBlending);
                            model.Materials.Add(matAdditiveBlendingDoubleSided);
                        }
                    }
                }

                foreach (var room in roomsToExport)
                {
                    if (room.RoomGeometry == null)
                    {
                        continue;
                    }

                    Vector3 offset;
                    if (exportInWorldCoordinates)
                    {
                        // If we're in multi-room export, use world position
                        offset = room.WorldPos;
                    }
                    else
                    {
                        // Make room center pivot if we're in single-room export mode
                        offset = -room.GetLocalCenter();
                        int x = (int)-offset.X / 1024;
                        int z = (int)-offset.Z / 1024;
                        offset.Y = -room.GetLowestCorner(new RectangleInt2(x, z, x, z)) * 256;
                    }

                    int index = level.Rooms.ReferenceIndexOf(room);
                    int xOff  = room.Position.X;
                    int yOff  = room.Position.Y;
                    int zOff  = room.Position.Z;

                    // Append the Offset to the Mesh name, we can later calculate the correct position
                    string meshFormat = "TeRoom_{0}_{1}_{2}_{3}";
                    var    mesh       = new IOMesh(string.Format(meshFormat, index, xOff, yOff, zOff));

                    int lastIndex = 0;
                    for (int x = 0; x < room.NumXSectors; x++)
                    {
                        for (int z = 0; z < room.NumZSectors; z++)
                        {
                            var block = room.GetBlock(new VectorInt2(x, z));

                            for (int faceType = 0; faceType < (int)BlockFace.Count; faceType++)
                            {
                                var faceTexture = block.GetFaceTexture((BlockFace)faceType);

                                if (faceTexture.TextureIsInvisible || faceTexture.TextureIsUnavailable)
                                {
                                    continue;
                                }

                                var range = room.RoomGeometry.VertexRangeLookup.TryGetOrDefault(new SectorInfo(x, z, (BlockFace)faceType));
                                var shape = room.GetFaceShape(x, z, (BlockFace)faceType);

                                if (shape == BlockFaceShape.Quad)
                                {
                                    int i = range.Start;

                                    var textureArea1 = room.RoomGeometry.TriangleTextureAreas[i / 3];
                                    var textureArea2 = room.RoomGeometry.TriangleTextureAreas[(i + 3) / 3];

                                    if (textureArea1.TextureIsUnavailable || textureArea1.TextureIsInvisible)
                                    {
                                        continue;
                                    }
                                    if (textureArea2.TextureIsUnavailable || textureArea2.TextureIsInvisible)
                                    {
                                        continue;
                                    }

                                    int textureAreaPage = GetTextureAreaPage(textureArea1, textureArea2);
                                    if (textureAreaPage < 0)
                                    {
                                        result.Warnings.Add(string.Format("Quad at ({0},{1}) in Room {2} has a texture that is beyond the 256px boundary. TexturePage is set to 0", x, z, room));
                                        textureAreaPage = 1;
                                    }

                                    var poly = new IOPolygon(IOPolygonShape.Quad);
                                    poly.Indices.Add(lastIndex + 0);
                                    poly.Indices.Add(lastIndex + 1);
                                    poly.Indices.Add(lastIndex + 2);
                                    poly.Indices.Add(lastIndex + 3);

                                    var uvFactor      = new Vector2(0.5f / (float)textureArea1.Texture.Image.Width, 0.5f / (float)textureArea1.Texture.Image.Height);
                                    int textureWidth  = textureArea1.Texture.Image.Width;
                                    int textureHeight = textureArea1.Texture.Image.Height;

                                    if (faceType != (int)BlockFace.Ceiling)
                                    {
                                        mesh.Positions.Add(room.RoomGeometry.VertexPositions[i + 3] + offset);
                                        mesh.Positions.Add(room.RoomGeometry.VertexPositions[i + 2] + offset);
                                        mesh.Positions.Add(room.RoomGeometry.VertexPositions[i + 0] + offset);
                                        mesh.Positions.Add(room.RoomGeometry.VertexPositions[i + 1] + offset);
                                        mesh.UV.Add(GetNormalizedPageUVs(textureArea2.TexCoord0, textureWidth, textureHeight, textureAreaPage));
                                        mesh.UV.Add(GetNormalizedPageUVs(textureArea1.TexCoord2, textureWidth, textureHeight, textureAreaPage));
                                        mesh.UV.Add(GetNormalizedPageUVs(textureArea1.TexCoord0, textureWidth, textureHeight, textureAreaPage));
                                        mesh.UV.Add(GetNormalizedPageUVs(textureArea1.TexCoord1, textureWidth, textureHeight, textureAreaPage));
                                        mesh.Colors.Add(new Vector4(room.RoomGeometry.VertexColors[i + 3], 1.0f));
                                        mesh.Colors.Add(new Vector4(room.RoomGeometry.VertexColors[i + 2], 1.0f));
                                        mesh.Colors.Add(new Vector4(room.RoomGeometry.VertexColors[i + 0], 1.0f));
                                        mesh.Colors.Add(new Vector4(room.RoomGeometry.VertexColors[i + 1], 1.0f));
                                    }
                                    else
                                    {
                                        mesh.Positions.Add(room.RoomGeometry.VertexPositions[i + 1] + offset);
                                        mesh.Positions.Add(room.RoomGeometry.VertexPositions[i + 2] + offset);
                                        mesh.Positions.Add(room.RoomGeometry.VertexPositions[i + 0] + offset);
                                        mesh.Positions.Add(room.RoomGeometry.VertexPositions[i + 5] + offset);
                                        mesh.UV.Add(GetNormalizedPageUVs(textureArea1.TexCoord1, textureWidth, textureHeight, textureAreaPage));
                                        mesh.UV.Add(GetNormalizedPageUVs(textureArea1.TexCoord2, textureWidth, textureHeight, textureAreaPage));
                                        mesh.UV.Add(GetNormalizedPageUVs(textureArea1.TexCoord0, textureWidth, textureHeight, textureAreaPage));
                                        mesh.UV.Add(GetNormalizedPageUVs(textureArea2.TexCoord2, textureWidth, textureHeight, textureAreaPage));
                                        mesh.Colors.Add(new Vector4(room.RoomGeometry.VertexColors[i + 1], 1.0f));
                                        mesh.Colors.Add(new Vector4(room.RoomGeometry.VertexColors[i + 2], 1.0f));
                                        mesh.Colors.Add(new Vector4(room.RoomGeometry.VertexColors[i + 0], 1.0f));
                                        mesh.Colors.Add(new Vector4(room.RoomGeometry.VertexColors[i + 5], 1.0f));
                                    }

                                    var mat = model.GetMaterial(textureArea1.Texture,
                                                                textureArea1.BlendMode >= BlendMode.Additive,
                                                                textureAreaPage,
                                                                textureArea1.DoubleSided,
                                                                0);

                                    if (!mesh.Submeshes.ContainsKey(mat))
                                    {
                                        mesh.Submeshes.Add(mat, new IOSubmesh(mat));
                                    }

                                    mesh.Submeshes[mat].Polygons.Add(poly);
                                    lastIndex += 4;
                                }
                                else if (shape == BlockFaceShape.Triangle)
                                {
                                    int i = range.Start;

                                    var textureArea = room.RoomGeometry.TriangleTextureAreas[i / 3];
                                    if (textureArea.TextureIsUnavailable || textureArea.TextureIsInvisible || textureArea.Texture == null)
                                    {
                                        continue;
                                    }
                                    int textureAreaPage = GetTextureAreaPage(textureArea, null);
                                    if (textureAreaPage < 0)
                                    {
                                        result.Warnings.Add(string.Format("Triangle at ({0},{1}) in Room {2} has a texture that is beyond the 256px boundary. TexturePage is set to 0", x, z, room));
                                        textureAreaPage = 1;
                                    }
                                    var poly = new IOPolygon(IOPolygonShape.Triangle);
                                    poly.Indices.Add(lastIndex);
                                    poly.Indices.Add(lastIndex + 1);
                                    poly.Indices.Add(lastIndex + 2);

                                    mesh.Positions.Add(room.RoomGeometry.VertexPositions[i] + offset);
                                    mesh.Positions.Add(room.RoomGeometry.VertexPositions[i + 1] + offset);
                                    mesh.Positions.Add(room.RoomGeometry.VertexPositions[i + 2] + offset);

                                    var uvFactor      = new Vector2(0.5f / (float)textureArea.Texture.Image.Width, 0.5f / (float)textureArea.Texture.Image.Height);
                                    int textureWidth  = textureArea.Texture.Image.Width;
                                    int textureHeight = textureArea.Texture.Image.Height;
                                    mesh.UV.Add(GetNormalizedPageUVs(textureArea.TexCoord0, textureWidth, textureHeight, textureAreaPage));
                                    mesh.UV.Add(GetNormalizedPageUVs(textureArea.TexCoord1, textureWidth, textureHeight, textureAreaPage));
                                    mesh.UV.Add(GetNormalizedPageUVs(textureArea.TexCoord2, textureWidth, textureHeight, textureAreaPage));

                                    mesh.Colors.Add(new Vector4(room.RoomGeometry.VertexColors[i], 1.0f));
                                    mesh.Colors.Add(new Vector4(room.RoomGeometry.VertexColors[i + 1], 1.0f));
                                    mesh.Colors.Add(new Vector4(room.RoomGeometry.VertexColors[i + 2], 1.0f));

                                    var mat = model.GetMaterial(textureArea.Texture,
                                                                textureArea.BlendMode >= BlendMode.Additive,
                                                                textureAreaPage,
                                                                textureArea.DoubleSided,
                                                                0);

                                    if (!mesh.Submeshes.ContainsKey(mat))
                                    {
                                        mesh.Submeshes.Add(mat, new IOSubmesh(mat));
                                    }

                                    mesh.Submeshes[mat].Polygons.Add(poly);
                                    lastIndex += 3;
                                }
                            }
                        }
                    }
                    model.Meshes.Add(mesh);
                }

                // Save only texture pages which are actually used in model.
                foreach (var page in splitPages)
                {
                    if (model.UsedMaterials.Any(mat => mat.TexturePath == page.Path))
                    {
                        page.SaveTexture();
                    }
                }

                result.Model = model;

                if (!result.Valid())
                {
                    result.Errors.Add("Nothing was exported. Check if rooms selected for export are textured and has any geometry.");
                }
            }
            catch (Exception e)
            {
                result.Errors.Add(e.Message);
            }
            return(result);
        }
Example #2
0
 protected void CalculateNormals(IOModel model) => model.Meshes.ForEach(mesh => mesh.CalculateNormals());
Example #3
0
 public abstract bool ExportToFile(IOModel model, string filename);