I'll answer 2) first, as that actually covers your question 1) as well.
The trick is, your ContentTypeWriter and ContentTypeReader don't have to implement the same type! The ContentTypeWriter has a GetRuntimeType method, which can report whatever type this data will be loaded into at runtime. For instance (contrived case) I could have:
ContentTypeWriter MyWriter<string>
{
overrride void Write(string value)
{
output.Write(value);
}
override string GetRuntimeType()
{
return typeof(int).AssemblyQualifiedName;
}
}
and then at runtime:
ContentTypeReader MyReader<int>
{
override int Read()
{
return int.Parse(input.ReadString());
}
}
Ok, so that on isn't particularly useful, but it gets the point across: as long as both the writer and reader agree as to what the format of the data on disk is, you can write one type, and then read that same data back into a different one.
This is not only how ModelContent -> Model works, but also how we handle things like VertexBufferContent -> VertexBuffer, IndexBufferContent -> IndexBuffer, EffectContent -> Effect, Texture2DContent -> Texture2D, etc.
There is never a graphics device during the build process, but instead it can use other related content types that do not require a graphics device. Then when this data is loaded back in, it can be read into the actual type that does use the graphics device.
There are two huge advantages to this separation of types:
- It is much faster, since at build time we can store the data in simple managed types, not bothering to upload it to the graphics card as an actual GPU data type (for instance building large models is much faster if you don't bother to upload all the vertex data to the GPU each time)
- Doing things this way makes it possible to build Xbox format textures and shaders, even though it wouldn't be possible to create an Xbox format GPU object on a Windows PC during the build process.
XNA Framework Developer -
blog -
homepage