Blade's Edge -- Paletting works
by William Clark · 05/29/2008 (1:19 am) · 1 comments
Chrono Trigger goblins using my repaletting system.A couple solid hours of work have given me a working repaletting system. As I mentioned in my last .plan, the idea is to allow an artist to draw one set of sprites, and identify the limited set of colors they used to draw it. Then, they can create a small texture that shows alternative color schemes for that character. The effect is exactly like color palette swaps in old school games, back when you had a limited color palette.
Color schemes for the goblins.The first major task was to create an alternative Content Pipeline Processor for handling .png images that I want to allow to be recolored. I read a little bit about the XNA content pipeline, and wrote RecolorTextureContent, RecolorTextureImporter, and RecolorTextureProcessor to take care of things. I didn't need to write a new Writer, since the end result of the Processor is a TextureContent object, which can already be written natively. The Importer simply loads both the texture we're interested in, and the palette texture that goes with it, and passes the two, as a RecolorTextureContent, to the Processor. In the processor is the meat of this system.
RecolorTextureProcessor.cs:
public override TextureContent Process(RecolorTextureContent input, ContentProcessorContext context)
{
// Convert the input to standard Color format, for ease of processing.
input.Texture.ConvertBitmapType(typeof(PixelBitmapContent<Color>));
input.Palette.ConvertBitmapType(typeof(PixelBitmapContent<Color>));
PixelBitmapContent<Color> palette = (PixelBitmapContent<Color>)input.Palette.Faces[0][0];
if (palette.Height > 256)
throw new Exception("Palette textures cannot have more than 256 alternative color schemes");
foreach (MipmapChain imageFace in input.Texture.Faces)
{
for (int i = 0; i < imageFace.Count; i++)
{
PixelBitmapContent<Color> mip = (PixelBitmapContent<Color>)imageFace[i];
for (int color = 0; color < palette.Width; color++)
{
byte intensity = (byte)(((float)color / (palette.Width-1)) * 255);
byte paletteOffset = (byte)((1.0f / palette.Height) * 255);
mip.ReplaceColor(palette.GetPixel(color, 0), new Color(intensity, paletteOffset, 0));
}
}
}
TextureProcessor texProc = new TextureProcessor();
return texProc.Process(input.Texture, context);
}Basically, I look at the first row of the palette texture, and search for each color in the image. I then write, to the Red of the image, intensity, which is the U-texture coordinate in the palette texture corresponding to that color. The Green, in turn, gets a useful little piece of information, which is the gap between each row of the palette texture. This is used later in the shader to compute a texture coordinate.
The other interesting part is the shader. It's pretty simple, and I think the code speaks for itself.
RecolorEffect.fx:
float4 SimplePS(VSOutput input) : COLOR
{
float4 colorData = tex2D(baseTextureSampler, input.texCoord);
float4 color = tex2D(paletteTextureSampler, float2(colorData.r, (0.5 + paletteCoord) * colorData.g));
color.a = colorData.a * input.color.a;
return color;
}With that, and some slightly irritating manual editing of my .txscene file, I get four marching goblins of different colors from one texture.
P.S. I hope the TXB 3D editor extensibility makes it to the 2D editor soon, so I can make the use of RecolorMaterials built in.
About the author
Torque Owner Jason "fireVein" Culwell