Chaos Project

RPG Maker => General Discussion => Topic started by: ForeverZer0 on February 20, 2012, 06:12:47 pm

Title: Sprite Blend Mode
Post by: ForeverZer0 on February 20, 2012, 06:12:47 pm
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.
Title: Re: Sprite Blend Mode
Post by: winkio on February 20, 2012, 07:16:01 pm
it should just be addition/subtraction of components, subject to a min/max value.
Title: Re: Sprite Blend Mode
Post by: ForeverZer0 on February 20, 2012, 07:29:02 pm
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.
Title: Re: Sprite Blend Mode
Post by: Blizzard on February 21, 2012, 02:23:31 am
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);
Title: Re: Sprite Blend Mode
Post by: ForeverZer0 on February 21, 2012, 06:17:32 pm
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
Title: Re: Sprite Blend Mode
Post by: Blizzard on February 22, 2012, 02:13:48 am
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);
Title: Re: Sprite Blend Mode
Post by: ForeverZer0 on February 22, 2012, 05:55:52 pm
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.
Title: Re: Sprite Blend Mode
Post by: Blizzard on February 23, 2012, 02:15:27 am
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.