Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Sprite Blend Mode

I am trying to emulate a similar feature to that of RMXP's "blend_type" for the Sprite class, and I can't seem to get it quite right. I was curious, does anyone know the calculation that is performed to do the addition and subtraction blends on an image? I'm using C#, and have been getting familiar with the ColorMatrix class, have created functions for altering brightness, saturation, color blending, opacity, color shearing, contrast, etc., but fail at this seemingly simple function.

I am using for creating a small utility for RMXP, and it is kinda important that it is accurate to the method that RMXP uses. This is basically the final thing to implement, and I can finish up pretty quickly after that.
 
in XNA its:
Code:
 

//swap additive for subtracive as needed, use what ever sort mode you want

spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);

spriteBatch.Draw() //whichever draw you are using

spriteBatch.End();

 
if you want non-xna let me know
 
Here's a description of how PhotoShop does it...

Add and Subtract blending modes

The Add and Subtract blending modes are available only for the Apply Image and Calculations commands.

Add

Adds the pixel values in two channels. This is a good way to combine non-overlapping images in two channels.

Because higher pixel values represent lighter colors, adding channels with overlapping pixels lightens the image. Black areas in both channels remain black (0 + 0 = 0). White in either channel results in white (255 + any value = 255 or greater).

Add mode divides the sum of the pixel values by the Scale amount, and then adds the Offset value to the sum. For example, to find the average of the pixels in two channels, add them, divide by 2, and enter no Offset value.

The Scale factor may be any number between 1.000 and 2.000. Entering a higher Scale value darkens the image.

The Offset value lets you lighten or darken the pixels in the destination channel by any brightness value between +255 and –255. Negative values darken the image; positive values lighten the image.

Subtract

Subtracts the pixel values in the source channel from the corresponding pixels in the target channel. As with Add mode, the result is then divided by the Scale factor and added to the Offset value.

The Scale factor may be any number between 1.000 and 2.000. The Offset value lets you lighten or darken the pixels in the destination channel by any brightness value between +255 and –255.



I can only assume that RM applies it's own "Scaling Factor" & "Offset" to keep the combinations from getting too light or dark.

Try a couple tests with primary colors to determine the factors. (e.g. make a 50% pure red map, and add a 50% pure green sprite to it with both ADD & SUBTRACT modes. Capture the resulting image & analyze the pixels.)
 
It's fairly simple :
Add :
buffer_pixel.red += sprite_pixel.red * sprite_pixel.alpha / 255 * sprite.opacity / 255
buffer_pixel.green += sprite_pixel.green * sprite_pixel.alpha / 255 * sprite.opacity / 255
buffer_pixel.blue += sprite_pixel.blue * sprite_pixel.alpha / 255 * sprite.opacity / 255
And results should be maintened between 0 and 255.

Substract :
same with -=

Blending is not something we can apply to the bitmap, we use it when merging all the sprites for the display.
Anyway I don't know wich library you use but usally you have builtin functions for that.
 
I'm not using DirectX, OpenGL, or anything. I'm simply using GDI+, which doesn't have this function. I have found a few different ways of doing the addition actually, its the subtraction that is eluding me, including the methods above. I'm thinking about simply including an XNA redistributable and making it easy, but I would rather not.

Here's the method I got, it works good for addition, but subtraction is results in always black.

Code:
        private static Color BlendColor(Color destColor, Color srcColor, int mode)

        {

            int r, g, b, a;

            float alpha = (srcColor.A / 255.0f);

            if (mode == ADDITION)

            {

                r = destColor.R + (int)(srcColor.R * alpha);

                g = destColor.G + (int)(srcColor.G * alpha);

                b = destColor.B + (int)(srcColor.B * alpha);

            }

            else if (mode == SUBTRACTION)

            {

                r = (int)(destColor.R * (1 - alpha) + srcColor.R * alpha);

                g = (int)(destColor.G * (1 - alpha) + srcColor.G * alpha);

                b = (int)(destColor.B * (1 - alpha) + srcColor.B * alpha);

            }

            

            else return srcColor;

            a = Util.Clamp<int>((int)(destColor.A * (1 - alpha) + srcColor.A), 0, 255);

            r = Util.Clamp<int>(r, 0, 255);

            g = Util.Clamp<int>(g, 0, 255);

            b = Util.Clamp<int>(b, 0, 255);

            return Color.FromArgb(a, r, g, b);

        }
 
wouldn't the subtract be the same as the add (with the sign changed)???

i.e. r = destColor.R - (int)(srcColor.R * alpha);

if your srcColor.A is 255, then alpha = 1. (1 - alpha) = 0


I don't see the prototype for a GDI+ COLOR object, but isn't color usually returned as (r, g, b, a) ??


and I still don't see any "scaling". The inherent problem with just adding or subtracting is you end up with too many values
less than 0, or greater than 255. Clamp only compresses 'out of limit' values to 0 or 255.

If you have a pixel that's 50% green, and you add 50% green to it, should you get 100% green?
Or, should you get 50% MORE green, resulting in 75% green?
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top