• Advertisement
Sign in to follow this  

[MDX] Replacing specific colors in an image on the fly

This topic is 4305 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I recently acquired the files from a particular old game which I loved. I now can't wait to start working on a game with it. However, the problems I currently have with the original data files: All the units, buildings, etc. are in 1 specific color: Goldish. Now, I wanna use C# and DirectX 9 in 2D mode for this game, but I don't feel like replacing the colors in those images just for the sake of being able to change the side they belong too. What would be my best way to do this, specifically on the fly(So I can keep memory usage down). Toolmaker [Edited by - Toolmaker on April 7, 2006 6:19:27 PM]

Share this post


Link to post
Share on other sites
Advertisement
Well you could easily use a pixel shader to do precise and "soft" colour replacement.

However, if you don't want that then an old trick I used worked through the traditional fixed-function texture blending. I was using it for 2D sprites where I wanted red/blue highlights on units in an RTS so I could identify what team they were on...

At load time (or pre-process) you can create a texture where white=replaced and black=ignored (sort of like an alpha map). You can then render the original artwork with (1-map) and then in a second pass rendering the coloured artwork (multiplied by a TFACTOR to get the desired result) scaled by the 'map' value. I forget the exact combination, but you can usually do this in a single pass by configuring the appropriate states.

hth
Jack

Share this post


Link to post
Share on other sites
I haven't done much with DirectX, so if you could show me SOME example code(Would be nice if it would be in C#), or give me a more thorough explanation.

I have this pic:


I want to replace all the yellowish/goldish colors with different colors. The image itself needs to be replaced with smaller, easier to process images.

The idea is that I can make this game multiplayer, and player can choose from a wide variety of colors for their side.

Toolmaker

Share this post


Link to post
Share on other sites
"Dune 2 : Battle for Arrakis" if I'm not mistaken? [smile]

Spent months playing that on my old Amiga 1200, absolutely loved it. Although I seem to remember that I could never complete the final level though [headshake]

The problem with your image is that the sand is a similar orange/gold colour to the parts that you want to use to identify teams. If you do the colour replacement as you render the individual tiles then it shouldn't be so much of a problem.

I don't have any C# code as I'm not that way inclined [lol] One of the other regulars may well be able to help you out in this case.

What sort of hardware/configuration are you targetting? Will you be able to use a pixel shader? and, to be honest, even duplicating that image 8 ways in memory at load-time is unlikely to cause you that much of a storage problem on any computer from this century [smile]

If you take my idea of an "alpha map" type approach, it might be best to manually create this yourself and ship it alongside. Given the colours in the image you presented, it could be quite easy to create an algorithm that generates a lot of "false positives" and replace the wrong colours. Would look a little odd if bits of sand started turning red/blue/green [lol]

Cheers,
Jack

Share this post


Link to post
Share on other sites
Surely those Dune 2 graphics are still protected by EA's copyright. I doubt one could legally ship anything derived from them without a license.

Share this post


Link to post
Share on other sites
I hadn't thought of that - the game must be 10 years old by now?

Quote:
Original post by Mastaba
Surely those Dune 2 graphics are still protected by EA's copyright. I doubt one could legally ship anything derived from them without a license.
It is indeed a legal minefield [oh]

Best be sure what you can (and can't) do with these assets before you invest too much effort...

Cheers,
Jack

Share this post


Link to post
Share on other sites
Quote:
Original post by jollyjeffers
I hadn't thought of that - the game must be 10 years old by now?

Quote:
Original post by Mastaba
Surely those Dune 2 graphics are still protected by EA's copyright. I doubt one could legally ship anything derived from them without a license.
It is indeed a legal minefield [oh]

Best be sure what you can (and can't) do with these assets before you invest too much effort...

Cheers,
Jack


Don't worry, I won't distribute anything with those graphics ;). I plan on using the original Dune II data files for it. But, that still requires that I replace some of the colors. And the game is 15 years old by now ^_^.

Since I got the extracted files aswell(I do own a copy of the game), I can first attempt to use this technique with the extracted files. This makes it easier to see if the results are ok.

Toolmaker

Share this post


Link to post
Share on other sites
Quote:
I don't have any C# code as I'm not that way inclined


No worries, Jack. Human flaws are charming, I'm told [wink]

Be that as it may, below is a little alpha map I made for this texture. You seem to be missing the tanks, so I guess you're going to need some more of these made. Send me a PM and I'll fix em up for you (this is easily done automatically by loading a new pallette for the image).



To actually make something of this in a game, I'd go with Jack's advice and use a pixel shader for rendering the textures. In this pixel shader you can use the normal texture for the basic rendering and blend the selected player color on it using the alpha map, basically like this:


float mask = tex2D(alphaMap, texCoord0);
OUT.color.rgb = (1 - mask) * tex2D(texture, texCoord0) + mask * selectedColor;
OUT.color.a = 1;


I'm not entirely sure about using the rgb swizzle here, but you will need to blend the selected unit color onto the original texture at full opacity, since you want to overwrite the color value in the original texture. If you don't blend at full opacity, goldish color will show through, which is probably not what you want.

I'll try to fix up a little demo sample tomorrow, the prospect of Dune2 in MDX deserves that [smile]

Share this post


Link to post
Share on other sites
The tiles are made using indexed color.

Unless the palette was changed by photoshop, then indices 192-198 are used to display units. It doesn't matter what color is stored in the palette, when rendering the tile, just replace indices in that range with corresponding side-designating color.

The color index 223 is for palette color cycle effect (used to display pulsation of wind traps).

Key is to take into account the index, not the color.

Since the indices used for blending are c0-c6, you could probably calculate the alpha value directly from (index & 0xf) or something similar.

192 is brightest, 198 is darkest, the distribution between them looks uniform.

Oh and, Dune did this on the fly, so I guess today's terraflop GPUs should be able to do that as well.

Share this post


Link to post
Share on other sites
Ok, I've whipped up a something simple with MDX, and loaded a harvester(Why always the harvesters? [grin]).

Basicly, I have 2 problems at this point:
The colors of the vehicles, and ofcourse, the 'background' of all the images.

So, from what I understood, I can do this with alpha-blending the right color. For that, I need to store the images in a format that supports alpha-blending. Sounds fair to me at this moment.

What would be the best way to alter my pics? I think PNG would suffice as format, and MDX can load those perfect. What tool do I need for this, and in what way do I need to "alter" the images, so the sides of vehicles are more darker than the rest?

Yes, I could ask Remigius to do it, but that would require him to edit quite a few pics. Because, I want to stick with smaller images, per building/vehicle. So, ideas?

Toolmaker

Share this post


Link to post
Share on other sites
I'm assuming the background color, that should be transparent is a single color key. If so, you could just specify a color key when loading up the texture, and it'll be replaced with a transparent color. I think that would be the simplest method.

Hope this helps.

Share this post


Link to post
Share on other sites
I was a bit bored, so I hacked this together:


private void setUnitColor(Color c)
{
System.Drawing.Imaging.ColorPalette palette = TileImage.Image.Palette;

for (int i = 0; i < 7; i++)
{
int newRed = (int)(c.R * (8.0 - i)/8.0);
int newGreen = (int)(c.G * (8.0 - i) / 8.0);
int newBlue = (int)(c.B * (8.0 - i) / 8.0);

// change the 7 palette entries designating the side
palette.Entries[192 + i] = Color.FromArgb(0xff, newRed, newGreen, newBlue);
}
TileImage.Image.Palette = palette;

TileImage.Image.MakeTransparent

TileImage.Refresh();
}

// save routine
private void saveButton_Click(object sender, EventArgs e)
{
saveImageDialog.FileName = openImageDialog.FileName;

if (saveImageDialog.ShowDialog() == DialogResult.OK)
{
// Saving TileImage directly crashes with some generic GDI error
// might be just a fluke
Bitmap b = new Bitmap(TileImage.Image);

// Define the color for transparency
b.MakeTransparent(Color.Black);

// will be RGB format
b.Save(saveImageDialog.FileName);
}
}



TileImage is PictureBox where the image is loaded (the bitmap you provided).
When saving image, you set the color where you want to make the image transparent.


Note that this isn't MDX or on-the-fly. After looking at doing this on the fly (can be done on textures), the support for indexed textures is a bit flaky and not supported enough. Using this, you can preprocess the bitmaps.

You could also use this to generate the alpha blending map (didn't test this):

for (int i = 0; i < 255; i++)
{
// clear the map
palette.Entries = Color.Black;
}
for (int i = 0; i < 7; i++)
{
int alpha = (int)(0xff * (8.0 - i)/8.0);

// change the 7 palette entries for proper shading
palette.Entries[192 + i] = Color.FromArgb(0xff, alpha, alpha, alpha);
}


Share this post


Link to post
Share on other sites
The images I'm currently using do not use palettes. Would you code still work for that? Or do I need the original images and just preprocess those?

And, how do I apply the alphamap with MDX? Or do I draw everything in 2 passes? First the standard bitmap, and then the alpha map over it, using the shader?

I'm a bit confused by this, since I lack the experience with pixel shaders, and this kind of magic :). (you could say I'm stupid)

Toolmaker

Share this post


Link to post
Share on other sites
You'll need the original palettised images for the palette trick to work. Back in "the good old days" it was a fairly common trick to use the index for this sort of replacement trick (amongst other things). As soon as you have the image in regular non-paletised form you lose the original index - which is the bit of information you really need [smile]

I would recommend going with remigius's suggestion if you can't get the original images. You probably want to look into the fixed-function texture blending operations to do it on the fly using remigius's alpha map... the black/white should allow you to mask the relevant pixels and apply the correct operation.

As for saving space... I don't honestly think you're going to need to bother with that unless you're going for some really tight hardware requirements. If you take the Pixel Shader route, any PS capable hardware will have enough VRAM to store 100's if not 1000's of copies of that tile map [smile]

Might well be just as easy to write it up as a pre-process/load-time algorithm if thats more intuitive/easier for you. Load in the data and then process accordingly and store a copy of the results for each team..

hth
Jack

Share this post


Link to post
Share on other sites
Quote:
Original post by jollyjeffers
You'll need the original palettised images for the palette trick to work. Back in "the good old days" it was a fairly common trick to use the index for this sort of replacement trick (amongst other things). As soon as you have the image in regular non-paletised form you lose the original index - which is the bit of information you really need [smile]

I would recommend going with remigius's suggestion if you can't get the original images. You probably want to look into the fixed-function texture blending operations to do it on the fly using remigius's alpha map... the black/white should allow you to mask the relevant pixels and apply the correct operation.

As for saving space... I don't honestly think you're going to need to bother with that unless you're going for some really tight hardware requirements. If you take the Pixel Shader route, any PS capable hardware will have enough VRAM to store 100's if not 1000's of copies of that tile map [smile]

Might well be just as easy to write it up as a pre-process/load-time algorithm if thats more intuitive/easier for you. Load in the data and then process accordingly and store a copy of the results for each team..
Jack


That does sound like a plan. Alternatively, I could assemble all the images for all the buildings, units, UI, etc. and just preprocess them. Alternatively, I got a copy of the alpha map regimius used, so I'm gonna get a trial of PSP later this week, and experiment a bit. Perhaps I can just load the PNGs and use Sprite.Draw() with an alpha color.

Toolmaker

Share this post


Link to post
Share on other sites
You could also use Antheus' code to generate the alpha maps on the fly, which should keep you some more in the clear on the intellectual property rights on the graphics. I was equally bored over lunch as Antheus must have been, so I hacked together a little demo on how to use the Sprite.Draw2D modulation color for this, which should be a bit easier than resorting to pixel shaders.

You can download the source project by clicking here. Have fun! [smile]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement