private static void ImportLayers(ContentImporterContext context, List <TiledMapLayerContent> layers, string path) { for (var i = 0; i < layers.Count; i++) { if (layers[i] is TiledMapImageLayerContent imageLayer) { imageLayer.Image.Source = Path.Combine(path, imageLayer.Image.Source); ContentLogger.Log($"Adding dependency for '{imageLayer.Image.Source}'"); // Tell the pipeline that we depend on this image and need to rebuild the map if the image changes. // (Maybe the image is a different size) context.AddDependency(imageLayer.Image.Source); } if (layers[i] is TiledMapObjectLayerContent objectLayer) { foreach (var obj in objectLayer.Objects) { if (!String.IsNullOrWhiteSpace(obj.TemplateSource)) { obj.TemplateSource = Path.Combine(path, obj.TemplateSource); ContentLogger.Log($"Adding dependency for '{obj.TemplateSource}'"); // Tell the pipeline that we depend on this template and need to rebuild the map if the template changes. // (Templates are loaded into objects on process, so all objects which depend on the template file // need the change to the template) context.AddDependency(obj.TemplateSource); } } } if (layers[i] is TiledMapGroupLayerContent groupLayer) { // Yay recursion! ImportLayers(context, groupLayer.Layers, path); } } }
private TiledMapTilesetContent DeserializeTiledMapTilesetContent(string filePath, ContentImporterContext context) { using (var reader = new StreamReader(filePath)) { var tilesetSerializer = new XmlSerializer(typeof(TiledMapTilesetContent)); var tileset = (TiledMapTilesetContent)tilesetSerializer.Deserialize(reader); tileset.Image.Source = $"{Path.GetDirectoryName(filePath)}/{tileset.Image.Source}"; ContentLogger.Log($"Adding dependency '{tileset.Image.Source}'"); context.AddDependency(tileset.Image.Source); foreach (var tile in tileset.Tiles) { foreach (var obj in tile.Objects) { if (!string.IsNullOrWhiteSpace(obj.TemplateSource)) { obj.TemplateSource = $"{Path.GetDirectoryName(filePath)}/{obj.TemplateSource}"; ContentLogger.Log($"Adding dependency '{obj.TemplateSource}'"); // We depend on the template. context.AddDependency(obj.TemplateSource); } } } return(tileset); } }
private static TiledMapContent DeserializeTiledMapContent(string mapFilePath, ContentImporterContext context) { using (var reader = new StreamReader(mapFilePath)) { var mapSerializer = new XmlSerializer(typeof(TiledMapContent)); var map = (TiledMapContent)mapSerializer.Deserialize(reader); map.FilePath = mapFilePath; for (var i = 0; i < map.Tilesets.Count; i++) { var tileset = map.Tilesets[i]; if (!string.IsNullOrWhiteSpace(tileset.Source)) { tileset.Source = Path.Combine(Path.GetDirectoryName(mapFilePath), tileset.Source); ContentLogger.Log($"Adding dependency for {tileset.Source}"); // We depend on the tileset. If the tileset changes, the map also needs to rebuild. context.AddDependency(tileset.Source); } else { tileset.Image.Source = Path.Combine(Path.GetDirectoryName(mapFilePath), tileset.Image.Source); ContentLogger.Log($"Adding dependency for {tileset.Image.Source}"); context.AddDependency(tileset.Image.Source); } } ImportLayers(context, map.Layers, Path.GetDirectoryName(mapFilePath)); map.Name = mapFilePath; return(map); } }
private IList <Texture2DContent> ImportSLMC(string filename, ContentImporterContext context) { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(filename); var channels = xmlDoc.DocumentElement; if (channels.Name != "channels") { throw new InvalidContentException(String.Format("Root element must be 'channels'.")); } TextureImporter txImporter = new TextureImporter(); List <Texture2DContent> images = new List <Texture2DContent>(); foreach (XmlNode imageNode in channels.ChildNodes) { if (imageNode.Name != "image") { throw new InvalidContentException(String.Format("Element '{0}' not supported in 'channels'.", imageNode.Name)); } var imageSource = GetAttribute(imageNode, "source"); var fullImageSource = Path.Combine(Path.GetDirectoryName(filename), imageSource); context.AddDependency(fullImageSource); var textureContent = (Texture2DContent)txImporter.Import(fullImageSource, context); textureContent.Name = Path.GetFileNameWithoutExtension(fullImageSource); images.Add(textureContent); } return(images); }
public override AtlasDec Import(string filename, ContentImporterContext context) { // TODO: process the input object, and return the modified data. string fileName = Path.GetFileNameWithoutExtension(filename).Trim(); string parentDir = Path.GetDirectoryName(filename); // Look for a folder with the same name as this file... string folder = Path.Combine(parentDir, fileName); bool exists = Directory.Exists(folder); if (!exists) { throw new Exception("Failed to import the atlas, adjacent source folder '" + folder + "' was not found!"); } string search = "*.png"; var found = Directory.EnumerateFiles(folder, search, SearchOption.AllDirectories); var files = found.ToArray(); for (int i = 0; i < files.Length; i++) { var f = files[i]; context.AddDependency(f); } AtlasDec dec = new AtlasDec(folder, fileName, files); context.Logger.LogMessage("Imported atlas with " + files.Length + " files."); return(dec); }
private MaterialContent GetMaterial(aiMesh aiMesh) { aiString difuse = new aiString(); scene.mMaterials[(int)aiMesh.mMaterialIndex].GetTextureDiffuse0(difuse); if (!String.IsNullOrEmpty(difuse.Data)) { String original = difuse.Data; difuse.Data = Path.GetFileName(difuse.Data); importerContext.AddDependency(Path.Combine(directory, difuse.Data)); try { BasicMaterialContent materialContent = new BasicMaterialContent(); materialContent.Name = difuse.Data; materialContent.Texture = new ExternalReference <TextureContent>(difuse.Data); return(materialContent); } catch (InvalidContentException) { // InvalidContentExceptions do not need further processing throw; } catch (Exception e) { // Wrap exception with content identity (includes line number) throw new InvalidContentException(e.ToString()); } } return(null); }
/// <summary> /// Adds a dependency to the specified file. This causes a rebuild of the file, when modified, /// on subsequent incremental builds. /// </summary> /// <param name="filename">The name of an asset file.</param> public void AddDependency(string filename) { if (_importerContext != null) { _importerContext.AddDependency(filename); } if (_processorContext != null) { _processorContext.AddDependency(filename); } }
public override List <byte[]> Import(string filename, ContentImporterContext context) { List <byte[]> imageData = new List <byte[]>(); List <string> imageFilenames; context.AddDependency(Path.Combine(Environment.CurrentDirectory, filename)); using (XmlReader reader = XmlReader.Create(filename)) { imageFilenames = IntermediateSerializer.Deserialize <List <string> >(reader, null); } foreach (string imageFilename in imageFilenames) { byte[] imageBytes = File.ReadAllBytes(imageFilename); imageData.Add(imageBytes); context.AddDependency(Path.Combine(Environment.CurrentDirectory, imageFilename)); } return(imageData); }
private static TiledMapObjectTemplateContent DeserializeTileMapObjectTemplateContent(string filePath, ContentImporterContext context) { using (var reader = new StreamReader(filePath)) { var templateSerializer = new XmlSerializer(typeof(TiledMapObjectTemplateContent)); var template = (TiledMapObjectTemplateContent)templateSerializer.Deserialize(reader); if (!string.IsNullOrWhiteSpace(template.Tileset?.Source)) { template.Tileset.Source = Path.Combine(Path.GetDirectoryName(filePath), template.Tileset.Source); ContentLogger.Log($"Adding dependency '{template.Tileset.Source}'"); // We depend on this tileset. context.AddDependency(template.Tileset.Source); } return(template); } }
public override AtlasDeclaration Import(string filename, ContentImporterContext context) { // TODO: process the input object, and return the modified data. var folders = File.ReadLines(filename); //.Select(s => Path.GetFullPath(Path.Combine(Path.GetDirectoryName(filename), s))); var rootDir = Path.GetDirectoryName(filename); List <string> pngList = new List <string>(); foreach (var f in folders) { var pngs = Directory.EnumerateFiles(Path.GetFullPath(Path.Combine(rootDir, f))).Where(w => w.EndsWith(".png")).Select(s => s.Substring(rootDir.Length + 1));//, SearchOption.TopDirectoryOnly); foreach (var p in pngs) { pngList.Add(p); context.AddDependency(Path.Combine(rootDir, p)); } } return(new AtlasDeclaration(rootDir, Path.GetFileNameWithoutExtension(filename), pngList.Select(s => s.Replace('\\', '/')).ToArray())); }
private static TextureAtlasContent ImportTMX(string filename, ContentImporterContext context) { TextureAtlasContent output = new TextureAtlasContent(); output.Identity = new ContentIdentity(filename); XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(filename); var map = xmlDoc.DocumentElement; var orientation = GetAttribute(map, "orientation"); if (orientation != "orthogonal") { throw new InvalidContentException("Invalid orientation. Only 'orthogonal' is supported for atlases."); } output.Renderorder = GetAttribute(map, "renderorder"); output.MapColumns = GetAttributeAsInt(map, "width").Value; output.MapRows = GetAttributeAsInt(map, "height").Value; output.TileWidth = GetAttributeAsInt(map, "tilewidth").Value; output.TileHeight = GetAttributeAsInt(map, "tileheight").Value; output.Width = output.MapColumns * output.TileWidth; output.Height = output.MapRows * output.TileHeight; XmlNode tileset = map["tileset"]; output.Firstgid = GetAttributeAsInt(tileset, "firstgid").Value; if (tileset.Attributes["source"] != null) { var tsxFilename = tileset.Attributes["source"].Value; var baseDirectory = Path.GetDirectoryName(filename); tsxFilename = Path.Combine(baseDirectory, tsxFilename); var sourceSprites = ImportTSX(tsxFilename, context); output.SourceSprites.AddRange(sourceSprites); context.AddDependency(tsxFilename); } else { var rootDirectory = Path.GetDirectoryName(filename); var sourceSprites = ImportTileset(tileset, context, rootDirectory); output.SourceSprites.AddRange(sourceSprites); } XmlNode layerNode = map["layer"]; var layerColumns = Convert.ToInt32(map.Attributes["width"].Value, CultureInfo.InvariantCulture); var layerRows = Convert.ToInt32(map.Attributes["height"].Value, CultureInfo.InvariantCulture); output.LayerColumns = layerColumns; output.LayerRows = layerRows; XmlNode layerDataNode = layerNode["data"]; var encoding = layerDataNode.Attributes["encoding"].Value; if (encoding != "csv") { throw new InvalidContentException("Invalid encoding. Only 'csv' is supported for data."); } var data = layerDataNode.InnerText; var dataStringList = data.Split(','); var mapData = new int[dataStringList.Length]; for (int i = 0; i < dataStringList.Length; i++) { mapData[i] = Convert.ToInt32(dataStringList[i].Trim(), CultureInfo.InvariantCulture); } output.MapData = mapData; return(output); }
public override TmxMap Import(string filename, ContentImporterContext context) { if (filename == null) { throw new ArgumentNullException(nameof(filename)); } var mapSerializer = new XmlSerializer(typeof(TmxMap)); var tileSetSerializer = new XmlSerializer(typeof(TmxTileSet)); var map = (TmxMap)mapSerializer.Deserialize(new StringReader(File.ReadAllText(filename))); map.OriginalFileName = filename; for (var i = 0; i < map.TileSets.Count; i++) { var baseReferenceFile = filename; if (!string.IsNullOrWhiteSpace(map.TileSets[i].Source)) { var tileSetPath = ImportPathHelper.GetReferencedFilePath( filename, map.TileSets[i].Source); context.AddDependency(tileSetPath); var originalFirstGid = map.TileSets[i].FirstGid; map.TileSets[i] = (TmxTileSet)tileSetSerializer.Deserialize(new StringReader(File.ReadAllText(tileSetPath))); map.TileSets[i].FirstGid = originalFirstGid; baseReferenceFile = tileSetPath; } if (map.TileSets[i].Image != null) { map.TileSets[i].Image.Source = ImportPathHelper.GetReferencedFilePath( baseReferenceFile, map.TileSets[i].Image.Source); context.AddDependency(map.TileSets[i].Image.Source); } foreach (var tile in map.TileSets[i].Tiles) { if (tile.Image != null) { tile.Image.Source = ImportPathHelper.GetReferencedFilePath( baseReferenceFile, tile.Image.Source); } } } foreach (var layer in map.Layers.OfType <TmxTileLayer>()) { var data = layer.Data; if (data.Encoding == "csv") { data.Tiles = data.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(uint.Parse).Select(gid => new TmxDataTile { Gid = gid }).ToList(); } else if (data.Encoding == "base64") { var encodedData = data.Value.Trim(); var decodedData = Convert.FromBase64String(encodedData); using (var stream = OpenStream(decodedData, data.Compression)) using (var reader = new BinaryReader(stream)) { data.Tiles = new List <TmxDataTile>(); for (var y = 0; y < layer.Width; y++) { for (var x = 0; x < layer.Height; x++) { var gid = reader.ReadUInt32(); data.Tiles.Add(new TmxDataTile { Gid = gid }); } } } } } foreach (var layer in map.Layers.OfType <TmxImageLayer>()) { if (layer.Image != null) { layer.Image.Source = ImportPathHelper.GetReferencedFilePath( filename, layer.Image.Source); } } return(map); }
/// <summary> /// Parses and executes an individual line of an OBJ file. /// </summary> /// <param name="lineTokens">Line to parse as tokens</param> private void ParseObjLine(string[] lineTokens) { // Switch by line type switch (lineTokens[0].ToLower()) { // Object case "o": // The next token is the name of the model rootNode.Name = lineTokens[1]; break; // Positions case "v": positions.Add(ParseVector3(lineTokens)); break; // Texture coordinates case "vt": { // u is required, but v and w are optional // Require a Vector2 and ignore the w for the sake of this sample Vector2 vt = ParseVector2(lineTokens); // Flip the v coordinate vt.Y = 1 - vt.Y; texCoords.Add(vt); break; } // Normals case "vn": normals.Add(ParseVector3(lineTokens)); break; // Groups (model meshes) case "g": // End the current mesh if (meshBuilder != null) { FinishMesh(); } // Begin a new mesh // The next token is an optional name if (lineTokens.Length > 1) { StartMesh(lineTokens[1]); } else { StartMesh(null); } break; // Smoothing group case "s": // Ignore; just use the normals as specified with verticies break; // Faces (triangles and quads are supported) case "f": // For triangles int[] polyIndices = { 0, 1, 2 }; // Warn about and ignore polygons which are not triangles or quads if (lineTokens.Length > 4) { Array.Resize(ref polyIndices, 6); polyIndices[2] = 3; polyIndices[3] = 1; polyIndices[4] = 2; polyIndices[5] = 3; /* * Futher faces (if any) will be ignored * importerContext.Logger.LogWarning(null, rootNode.Identity, * "N-sided polygons are not supported; Ignoring face"); * break;*/ } // If the builder is null, this face is outside of a group // Start a new, unnamed group if (meshBuilder == null) { StartMesh(null); } // Loop through every polygon vertex (3 if triangle, 6 if quad) for (int vertexIndex = 0; vertexIndex < polyIndices.Length; vertexIndex++) { // Each vertex is a set of three indices: // position, texture coordinate, and normal // The indices are 1-based, separated by slashes // and only position is required. string[] indices = lineTokens[polyIndices[vertexIndex] + 1].Split('/'); // Required: Position int positionIndex = int.Parse(indices[0], CultureInfo.InvariantCulture) - 1; if (indices.Length > 1) { // Optional: Texture coordinate int texCoordIndex; Vector2 texCoord; if (int.TryParse(indices[1], out texCoordIndex)) { texCoord = texCoords[texCoordIndex - 1]; } else { texCoord = Vector2.Zero; } // Set channel data for texture coordinate for the following // vertex. This must be done before calling AddTriangleVertex meshBuilder.SetVertexChannelData(textureCoordinateDataIndex, texCoord); } if (indices.Length > 2) { // Optional: Normal int normalIndex; Vector3 normal; if (int.TryParse(indices[2], out normalIndex)) { normal = normals[normalIndex - 1]; } else { normal = Vector3.Zero; } // Set channel data for normal for the following vertex. // This must be done before calling AddTriangleVertex meshBuilder.SetVertexChannelData(normalDataIndex, normal); } // Add the vertex with the vertex data that was just set meshBuilder.AddTriangleVertex(positionMap[positionIndex]); } break; // Import a material library file case "mtllib": // Remaining tokens are relative paths to MTL files for (int i = 1; i < lineTokens.Length; i++) { string mtlFileName = lineTokens[i]; // A full path is needed, if (!Path.IsPathRooted(mtlFileName)) { // resolve relative paths string directory = Path.GetDirectoryName(rootNode.Identity.SourceFilename); mtlFileName = Path.GetFullPath( Path.Combine(directory, mtlFileName)); } // By calling AddDependency, we will cause this model // to be rebuilt if its associated MTL files change importerContext.AddDependency(mtlFileName); // Import and record the new materials ImportMaterials(mtlFileName); } break; // Apply a material case "usemtl": { // If the builder is null, OBJ most likely lacks groups // Start a new, unnamed group if (meshBuilder == null) { StartMesh(null); } // Next token is material name string materialName = lineTokens[1]; // Apply the material to the upcoming faces MaterialContent material; if (materials.TryGetValue(materialName, out material)) { meshBuilder.SetMaterial(material); } else { throw new InvalidContentException(String.Format( "Material '{0}' not defined.", materialName), rootNode.Identity); } break; } // Unsupported or invalid line types default: throw new InvalidContentException( "Unsupported or invalid line type '" + lineTokens[0] + "'", rootNode.Identity); } }
void parseObjLine(string[] lineTokens) { switch (lineTokens[0].ToLower( )) { case "o": rootNode.Name = lineTokens[1]; break; case "v": positions.Add(parseVector3(lineTokens)); break; case "vt": { Vector2 vt = parseVector2(lineTokens); vt.Y = 1 - vt.Y; texCoords.Add(vt); break; } case "vn": normals.Add(parseVector3(lineTokens)); break; case "g": if (meshBuilder != null) { this.finishMesh( ); } if (lineTokens.Length > 1) { this.startMesh(lineTokens[1]); } else { this.startMesh(null); } break; case "s": break; case "f": if (lineTokens.Length > 4) { importerContext.Logger.LogWarning(null, rootNode.Identity, "N-sided polygons are not supported! Ignoring vertex."); break; } if (meshBuilder == null) { this.startMesh(null); } for (int vertexIndex = 1; vertexIndex <= 3; vertexIndex++) { string[] indices = lineTokens[vertexIndex].Split('/'); int positionIndex = int.Parse(indices[0], CultureInfo.InvariantCulture) - 1; if (indices.Length > 1) { int texCoordIndex; Vector2 texCoord; if (int.TryParse(indices[1], out texCoordIndex)) { texCoord = texCoords[texCoordIndex - 1]; } else { texCoord = Vector2.Zero; } meshBuilder.SetVertexChannelData(textureCoordinateDataIndex, texCoord); } if (indices.Length > 2) { int normalIndex; Vector3 normal; if (int.TryParse(indices[2], out normalIndex)) { normal = normals[normalIndex - 1]; } else { normal = Vector3.Zero; } meshBuilder.SetVertexChannelData(normalDataIndex, normal); } meshBuilder.AddTriangleVertex(positionMap[positionIndex]); } break; case "mtllib": for (int i = 1; i < lineTokens.Length; i++) { string mtlFileName = lineTokens[i]; if (!Path.IsPathRooted(mtlFileName)) { string directory = Path.GetDirectoryName(rootNode.Identity.SourceFilename); mtlFileName = Path.GetFullPath(Path.Combine(directory, mtlFileName)); } importerContext.AddDependency(mtlFileName); this.importMaterials(mtlFileName); } break; case "usemtl": { if (meshBuilder == null) { this.startMesh(null); } string materialName = lineTokens[1]; MaterialContent material; if (materials.TryGetValue(materialName, out material)) { meshBuilder.SetMaterial(material); } else { throw new InvalidContentException(String.Format("Material '{0}' is not defined.", materialName), rootNode.Identity); } break; } default: throw new InvalidContentException("Unsupported or invalid line type '" + lineTokens[0] + "'", rootNode.Identity); } }