Hello JF,
The importer in your case would be responsible for taking the and processing the asset file name for your custom asset that is passed on to your custom processor. Since your custom object simply points to a loaded asset then you really do not need to worry about converting or packing that texture data into your custom asset type. What it does sound like you need to do is create a custom class that contains the required fields and properties to support your animation system's requirements and write them to the xnb file so that it can be loaded up at runtime through the content pipeline's Load<>() method. Basically what you will be doing is simple,
1) Import the animation file (Custom importer)
2) Process the animation file and as the name suggests perform any operations required(Custom Processor)
3) Write the custom animation data out to XNB. (Custom Writer)
4) Using the assembly route and method specifed by the processor parse the XNB back into objects as required.
Following if you are still interested is some code that demonstrates an end to end custom content pipeline solution. Note that it does not cover reading the XNB back in at runtime as I do not have any code available to demonstrate the concept.
I hope this helps.
Importer:
// Your custom class defanition
public class YourCustomClass
{
public string Filename;
public int FilenameSize;
}
// Your custom content importer.
// ".ext" the extention this importer supports (use ".ext1", ".ext2", ".etc", ) to support multiple file extensions.
// DefaultProcessor is the actual name of the class that will provide processing for this asset type.
// DisplayName is the name that everyone will see through the VisualStudio IDE when an asset of this type has been added.
[ContentImporter(".ext", DefaultProcessor = "Your_Processor_Class", DisplayName = "Name of your processor. Will be displayed in the VisualStudio IDE")]
public class Your_Importer_Class : ContentImporter<YourCustomClass>
{
public override Your_Importer_Class Import(string filename, ContentImporterContext context)
{
// Process the input filename as required and build up your custom class object with the required values.
YourCustomClass myClass = new YourCustomClass();
myClass.FilenameSize = filename.Length;
myClass.Filename = filename;
// Return your newly populated class object to the next stage, Content processing
return myClass;
}
}
As you will see demonstrated by the code above the custom content importer is where you will do any initial processing of the asset file and build the custom class needed to pass to the content processor. I have not experimented deeply yet but I am fairly sure you can open streams and process other files providing those streams are flushed and closed before exiting the importer method. On nice feature of the importer (and you may want to keep track of context so it can be used in other impoter supporting methods) is access to the ContentImporterContext paramter object. Using this context object you have access to message reporting methods such as, Logger.LogImportantMessage() and Logger.LogMessage() to provide a means to output useful information to the controlling console.
In the above code I simply save the filename and for the sake of example set also the length of the filename before passing it on to the next step. the custom processor.
Processor:
// A simple class that will be passed onto the custom content writer upon completion.
public class Your_Processed_Asset_Class
{
// Just for the sake of example we will pass the importer data on to the writer as well
public string AssetFilename;
public int AssetFilenameSize;
// The following will be filled by the content processor and sent to the content writer when processing is complete.
public string AssetName;
public byte[] AssetData;
}
[ContentProcessor(DisplayName = "Description of your content processor. Will be visible through the Visual Studio IDE")]
public class Your_Processor_Class : ContentProcessor<YourCustomClass, Your_Processed_Asset_Class>
{
// This is the entry point that will be called as soon as the custom asset importing has completed.
public override Your_Processed_Asset_Class Process(YourCustomClass input, ContentProcessorContext context)
{
// Do whatever processing we are going to do with the custom impordata.
Your_Processed_Asset_Class asset = new Your_Processed_Asset_Class();
asset.AssetFilename = input.Filename;
asset.AssetFilenameSize = input.FilenameSize;
// Do the custom processing
asset.AssetName = Path.GetFilenameWithoutExtension(input.Filename);
asset.AssetData = File.ReadAllBytes(input.Filename);
// Now that we have the data we want all packaged into one object we call the writer.
return asset;
}
}
The code above demonstrates a very simple supporting custom processor that is responsible for taking the filename, and filename length provided by the custom content importer and combining it with the internal asset name and the physically read in data of the specified file. Once completed, the asset object is passed on to the custom content writer to be written out to the finalized XNB file. Again we see the context object but this time we see it as a ContentProcessorContext. The overall functionality as described is mutual between the CustomInporterContext, and CustomProcessorContext objects.
Writer:
// Simple custom content writer to support the previous importer and processor.
[ContentTypeWriter]
public class Your_Writer_Class : ContentTypeWriter<Your_Processed_Asset_Class>
{
protected override void Write(ContentWriter output, Your_Processed_Asset_Class value)
{
// By the time you reach here some header information will have already been saved to the XNB file.
// This data is some system information, and the path to the content reader responsible for reading in this asset type at runtime,
// Get the stream already associated with the open XNB file for writing the custom data to.
Stream sw = output.BaseStream;
// Prepare your buffer.
byte[] buffer = new byte[256];
buffer = StringToByteArray(value.Filename);
// Now write your data.
sw.Write(buffer, 0, buffer.Length);
// repeat until your data has been written. I am sure there are more graceful ways to handle this than I have provided as I kept it simple for the sake of example.
}
// This is another method required as part of the content writer class and is responsible for returning to the calling code the
// assembly path to the method resonsible for reading this asset type at runtime.
public override string GetRuntimeReader(TargetPlatform targetPlatform)
{
return "Assembly.Route.To.Your.Custom.Asset.Reader";
}
}
As the code above demonstrates the writers only job is to write out the remaining data (the custom asset) to the XNB file to be loaded up at runtime by XNA. At this stage you simple get the output stream to the xnb file that will contain your custom data, and start writing the data. I have not tried but I see no reason why you would not serialize xml to the xnb or use any of the already available default content processors to convert the data and put it in the xnb file as well.
Reader:
In regards to the reader I do not have any code handy for that. The custom importer/processor/writer I am currently working on does not have a runtime loader component side and in such I haven't attempted to write a custom asset reader. However the idea would not be to much unlike the writer process listed above in that it would take a Your_Processed_Asset_Class object at runtime and parse it back out into the required objects for your game.