Sprite Blend Mode

Started by ForeverZer0, February 20, 2012, 06:12:47 pm

Previous topic - Next topic

ForeverZer0

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.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

winkio

it should just be addition/subtraction of components, subject to a min/max value.

ForeverZer0

I'm not really sure how much. A simple change in brightness seems to be pretty close, but my version seems to make certain graphics whiter than RMXP's method. I experimented with increasing the contrast along with increasing the brightness, which resulted in some mixed results. Some things looked nearly identical, while others did not, it depended on the particular colors in the graphic.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Blizzard

February 21, 2012, 02:23:31 am #3 Last Edit: February 21, 2012, 02:26:51 am by HK-47
It depends on what you are using. e.g. in DirectX/OpenGL you have to set some specific variables for that.

Add = dest_rgb + src_rgb * src_a
Subtract = dest_rgb - src_rgb * src_a

dest: destination pixel value (the one below the sprite)
src: source pixel value (the one on the sprite)

Code: DirectX, add
// makes sure alpha blending is done independently, requires "d3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE)"
d3dDevice->SetRenderState(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD);
d3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
d3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
// color blending
d3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
d3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
d3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);


Code: DirectX, subtract
// makes sure alpha blending is done independently, requires "d3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE)"
d3dDevice->SetRenderState(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD);
d3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
d3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
// color blending
d3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT);
d3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
d3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

ForeverZer0

February 21, 2012, 06:17:32 pm #4 Last Edit: February 21, 2012, 06:31:03 pm by Darth Dastardly
That works perfectly for "addition", but the subtraction seems to always result in all black. Here's the method I made:

		private static Color BlendColor(Color destColor, Color srcColor, int mode)
{
int r, g, b;
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 = destColor.R - (int)(srcColor.R * alpha);
g = destColor.G - (int)(srcColor.G * alpha);
b = destColor.B - (int)(srcColor.B * alpha);
}
else
return srcColor;
r = Util.Clamp<int>(r, 0, 255);
g = Util.Clamp<int>(g, 0, 255);
b = Util.Clamp<int>(b, 0, 255);
return Color.FromArgb(srcColor.A, r, g, b);
}


Does any of that look incorrect? It seems to me that the RMXP subtraction blend is more of a taking the negative of the image, though I could be wrong.

EDIT:
I removed the alpha calculation from the method by the way. That obviously won't work. :P
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Blizzard

February 22, 2012, 02:13:48 am #5 Last Edit: February 22, 2012, 02:20:37 am by Darth Asshole
Quote from: Darth Dastardly on February 21, 2012, 06:17:32 pm
It seems to me that the RMXP subtraction blend is more of a taking the negative of the image, though I could be wrong.


Quote from: Darth Asshole on February 21, 2012, 02:23:31 am
Subtract = dest_rgb - src_rgb * src_a


EDIT:

Your else branch is incorrect. This is how it hould look like:

else
{
   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);
}


Because this is a linear interpolation that is normally used in alpha blending without any effects.

And the last line is incorrect. It should be:

return Color.FromArgb(destColor.A * (1 - alpha) + srcColor.A, r, g, b);


Because of this:

d3dDevice->SetRenderState(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD);
d3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
d3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

ForeverZer0

This is what I have, and the subtraction is still incorrect.

		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);
}


This is still just turning all the pixels to black. I'm getting frustrated with this...  :facepalmx:

I'm not using DirectX or OpenGL, I'm trying to do this simply with GDI+. I'm basically trying to emulate them methods without using them.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Blizzard

You messed up. xD I fixed the "else" branch there, not the "else if" branch. The "else if" branch was fine. You were supposed to change "else return srcColor;"

As for the rest, I don't see any more mistakes. :/ Try switching dest and src everywhere just to see what happens.
Does ADDITION work right? Also try switching the positions of dest and src in the SUBTRACTION part (basically: "r = (int)(srcColor.R * alpha) - destColor.R;"). This is also just to see what happens.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.