<?xml version="1.0"?>
<rss version="2.0">
	<channel>
		<title>Saturation blender</title>
		<link>http://www.allegro.cc/forums/view/613054</link>
		<description>Allegro.cc Forum Thread</description>
		<webMaster>matthew@allegro.cc (Matthew Leverton)</webMaster>
		<lastBuildDate>Mon, 05 Aug 2013 10:14:49 +0000</lastBuildDate>
	</channel>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Hey, guys-</p><p>I&#39;d really like being able to blend two bitmaps in such a way that all the recipient bitmap receives from the donor is its saturation. I&#39;m relatively certain it can&#39;t be done with built-in filters, but I&#39;d like to ask the experts to weigh in before I burn a chunk of time writing a per-pixel filter.</p><p>Also, WOO FIRST POST, celebrations, so forth. <img src="http://www.allegro.cc/forums/smileys/wink.gif" alt=";)" /></p><p>W.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Winfield)</author>
		<pubDate>Wed, 31 Jul 2013 13:24:10 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I&#39;d say it&#39;s something that can&#39;t be done with blending, and yes, a very trivial shader to draw the bitmap will work... instead of outputting r/g/b from each texture pixel output s/s/s.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Elias)</author>
		<pubDate>Wed, 31 Jul 2013 14:17:34 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Can you write the equation of what you want?
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (ph03nix)</author>
		<pubDate>Wed, 31 Jul 2013 19:12:32 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Yes, the whole GLSL fragment shader would be something like this:</p><div class="source-code snippet"><div class="inner"><pre>uniform sampler2D tex<span class="k2">;</span>
varying vec2 uv<span class="k2">;</span>

<span class="k1">void</span> main<span class="k2">(</span><span class="k2">)</span> <span class="k2">{</span>
    vec4 c <span class="k3">=</span> texture2D<span class="k2">(</span>tex, uv<span class="k2">)</span><span class="k2">;</span>
    <span class="k1">float</span> s <span class="k3">=</span> <span class="k2">(</span>c.r <span class="k3">+</span> c.g  c.b<span class="k2">)</span> <span class="k3">/</span> <span class="n">3</span><span class="k2">;</span>
    gl_FragColor <span class="k3">=</span> vec4<span class="k2">(</span>s, s, s, c.a<span class="k2">)</span><span class="k2">;</span>
<span class="k2">}</span>
</pre></div></div><p>

With probably a more sophisticated formula to get the saturation <img src="http://www.allegro.cc/forums/smileys/smiley.gif" alt=":)" />
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Elias)</author>
		<pubDate>Wed, 31 Jul 2013 20:06:56 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>The cheap method of returning saturation for an RGB value looks something like:</p><div class="source-code snippet"><div class="inner"><pre>function SaturationFromRGB<span class="k2">(</span><span class="k1">unsigned</span> <span class="k1">char</span> r, <span class="k1">unsigned</span> <span class="k1">char</span> g, <span class="k1">unsigned</span> <span class="k1">char</span> b<span class="k2">)</span><span class="k2">{</span>
  <span class="k1">int</span> Minimum <span class="k3">=</span> min<span class="k2">(</span>b,min<span class="k2">(</span>r,g<span class="k2">)</span><span class="k2">)</span><span class="k2">;</span>
  <span class="k1">int</span> Maximum <span class="k3">=</span> max<span class="k2">(</span>b,max<span class="k2">(</span>r,g<span class="k2">)</span><span class="k2">)</span><span class="k2">;</span>
  <span class="k1">int</span> Saturation <span class="k3">=</span> Minimum-Maximum<span class="k2">;</span>
  <span class="k1">return</span> Saturation<span class="k2">;</span>
<span class="k2">}</span>
</pre></div></div><p>

And the cheap(ish) way of applying a saturation value to something in the RGB colorspace is:</p><div class="source-code snippet"><div class="inner"><pre><span class="k1">void</span> SaturationToRGB<span class="k2">(</span><span class="k1">unsigned</span> <span class="k1">char</span> <span class="k3">*</span>r, <span class="k1">unsigned</span> <span class="k1">char</span> <span class="k3">*</span>g, <span class="k1">unsigned</span> <span class="k1">char</span> <span class="k3">*</span>b, <span class="k1">char</span> Saturation<span class="k2">)</span><span class="k2">{</span>
  <span class="k1">double</span> Pr <span class="k3">=</span> .<span class="n">299</span><span class="k2">;</span>
  <span class="k1">double</span> Pg <span class="k3">=</span> .<span class="n">587</span><span class="k2">;</span>
  <span class="k1">double</span> Pb <span class="k3">=</span> .<span class="n">114</span><span class="k2">;</span>

  <span class="k1">double</span>  P<span class="k3">=</span><a href="http://www.delorie.com/djgpp/doc/libc/libc_738.html" target="_blank">sqrt</a><span class="k2">(</span>
  <span class="k2">(</span><span class="k3">*</span>r<span class="k2">)</span><span class="k3">*</span><span class="k2">(</span><span class="k3">*</span>r<span class="k2">)</span><span class="k3">*</span>Pr<span class="k3">+</span>
  <span class="k2">(</span><span class="k3">*</span>g<span class="k2">)</span><span class="k3">*</span><span class="k2">(</span><span class="k3">*</span>g<span class="k2">)</span><span class="k3">*</span>Pg<span class="k3">+</span>
  <span class="k2">(</span><span class="k3">*</span>b<span class="k2">)</span><span class="k3">*</span><span class="k2">(</span><span class="k3">*</span>b<span class="k2">)</span><span class="k3">*</span>Pb <span class="k2">)</span> <span class="k2">;</span>

  <span class="k3">*</span>r<span class="k3">=</span>P<span class="k3">+</span><span class="k2">(</span><span class="k2">(</span><span class="k3">*</span>r<span class="k2">)</span><span class="k3">-</span>P<span class="k2">)</span><span class="k3">*</span>change<span class="k2">;</span>
  <span class="k3">*</span>g<span class="k3">=</span>P<span class="k3">+</span><span class="k2">(</span><span class="k2">(</span><span class="k3">*</span>g<span class="k2">)</span><span class="k3">-</span>P<span class="k2">)</span><span class="k3">*</span>change<span class="k2">;</span>
  <span class="k3">*</span>b<span class="k3">=</span>P<span class="k3">+</span><span class="k2">(</span><span class="k2">(</span><span class="k3">*</span>b<span class="k2">)</span><span class="k3">-</span>P<span class="k2">)</span><span class="k3">*</span>change<span class="k2">;</span>
<span class="k2">}</span>
</pre></div></div><p>

So ultimately, the algo I&#39;ll be using when I scan through on a per-pixel basis will be something like:</p><div class="source-code snippet"><div class="inner"><pre><span class="k1">unsigned</span> <span class="k1">char</span> sr, sg, sb, ar, ag, ab<span class="k2">;</span>
<span class="k1">for</span> <span class="k2">(</span>i <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span> i <span class="k3">&lt;</span> <span class="k1">sizeof</span><span class="k2">(</span><a href="http://www.allegro.cc/manual/SCREEN_W"><span class="a">SCREEN_W</span></a><span class="k2">)</span><span class="k2">;</span> i<span class="k3">+</span><span class="k3">+</span><span class="k2">)</span> <span class="k2">{</span> <span class="c">//only rendering pixels in the viewport</span>
  <span class="k1">for</span> <span class="k2">(</span>j <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span> j <span class="k3">&lt;</span> <span class="k1">sizeof</span><span class="k2">(</span><a href="http://www.allegro.cc/manual/SCREEN_H"><span class="a">SCREEN_H</span></a><span class="k2">)</span><span class="k2">;</span> j<span class="k3">+</span><span class="k3">+</span><span class="k2">)</span> <span class="k2">{</span>
    PixelToBuffer<span class="k2">(</span><span class="k3">*</span>SourceCanvas, ViewportOffsetX<span class="k3">+</span>i, ViewportOffsetY<span class="k3">+</span>j, <span class="k3">&amp;</span>sr, <span class="k3">&amp;</span>sg, <span class="k3">&amp;</span>sb<span class="k2">)</span><span class="k2">;</span>
    PixelToBuffer<span class="k2">(</span><span class="k3">*</span>AdjustCanvas, ViewportOffsetX<span class="k3">+</span>i, ViewportOffsetY<span class="k3">+</span>j, <span class="k3">&amp;</span>ar, <span class="k3">&amp;</span>ag, <span class="k3">&amp;</span>ab<span class="k2">)</span><span class="k2">;</span>

    SaturationToRGB<span class="k2">(</span><span class="k3">&amp;</span>ar, <span class="k3">&amp;</span>ag, <span class="k3">&amp;</span>ab, SaturationFromRGB<span class="k2">(</span>sr, sg, sb<span class="k2">)</span><span class="k2">)</span><span class="k2">;</span>
  <span class="k2">}</span>
<span class="k2">}</span>
</pre></div></div><p>

For now the project&#39;s strictly 2D, but I&#39;ll look into making GLSL do what I want - it&#39;d be nice to tilt the base layer of the tilemap away from the camera slightly like Diablo 2: Lord of Destruction did. We&#39;ll see. <img src="http://www.allegro.cc/forums/smileys/smiley.gif" alt=":)" /></p><p>In any case, thanks for thinking about the problem. And please forgive any mistakes, I&#39;ve had to write PHP all morning and it takes a few hours for my brain to recover.;D
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Winfield)</author>
		<pubDate>Wed, 31 Jul 2013 22:12:21 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Just use &lt;code&gt;&lt;/code&gt; tags next time.</p><p>&lt;code&gt;<br />void heyThere ()<br />{<br />}<br />&lt;/code&gt;</p><p>Becomes:</p><div class="source-code snippet"><div class="inner"><pre><span class="k1">void</span> heyThere <span class="k2">(</span><span class="k2">)</span>
<span class="k2">{</span>
<span class="k2">}</span>
</pre></div></div><p>
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Vanneto)</author>
		<pubDate>Wed, 31 Jul 2013 22:19:02 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Next time? I totally did that this time. Yep. ;]</p><p>(Thanks for the tip!)
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Winfield)</author>
		<pubDate>Wed, 31 Jul 2013 23:59:48 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p><span class="source-code"><a href="http://www.allegro.cc/manual/al_color_rgb_to_hsl"><span class="a">al_color_rgb_to_hsl</span></a><span class="k2">(</span><span class="k2">)</span></span> already been done for you.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Mark Oates)</author>
		<pubDate>Thu, 01 Aug 2013 00:35:37 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Thanks. <img src="http://www.allegro.cc/forums/smileys/smiley.gif" alt=":)" /> I&#39;m aware of the function, but chose to reimplement it anyway: an authentic HSL conversion may not ultimately be the effect I need, because it doesn&#39;t stand out very much. I&#39;m not making the decision until I&#39;ve implemented the effect, but it&#39;s likely I will need to tweak the formula to make a gray more distinct from the source colors.</p><p>UPDATE: I&#39;ve written a shader to do this - several, in fact. I&#39;ve attached the simplest, most accurate one - it masks the stencil (al_tex) against the texture (tex2), using luminance as opacity. Basically, the brighter the pixel on the mask, the more desaturated the composite result will be. <img src="http://www.allegro.cc/forums/smileys/smiley.gif" alt=":)" /></p><p>Anyone who wants it, feel free to use it under the terms of the <a href="http://opensource.org/licenses/Zlib">zLib license.</a></p><p>Note that the shader used in the attached screenshot is not exactly the same - it&#39;s a less accurate, stylized version which is far less useful as learner code.</p><p>If you want to desaturate the entire texture, this is easily done by replacing tmp.r, tmp.b, and tmp.g by clamping Opacity to the level of desaturation you want (between 0 and 1.)</p><div class="source-code"><div class="toolbar"><span class="button numbers"><b>#</b></span><span class="button select">Select</span><span class="button expand">Expand</span></div><div class="inner"><span class="number">  1</span><span class="p">#version 120</span>
<span class="number">  2</span><span class="p">#ifdef GL_ES</span>
<span class="number">  3</span>precision mediump <span class="k1">float</span><span class="k2">;</span>
<span class="number">  4</span><span class="p">#endif</span>
<span class="number">  5</span>uniform sampler2D al_tex<span class="k2">;</span>
<span class="number">  6</span>uniform sampler2D tex2<span class="k2">;</span>
<span class="number">  7</span>varying vec4 varying_color<span class="k2">;</span>
<span class="number">  8</span>varying vec2 varying_texcoord<span class="k2">;</span>
<span class="number">  9</span><span class="k1">void</span> main<span class="k2">(</span><span class="k2">)</span>
<span class="number"> 10</span><span class="k2">{</span>
<span class="number"> 11</span>   vec4 tmp  <span class="k3">=</span> varying_color <span class="k3">*</span> texture2D<span class="k2">(</span>al_tex,  varying_texcoord<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 12</span>   vec4 art  <span class="k3">=</span> texture2D<span class="k2">(</span>tex2, varying_texcoord<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 13</span>   
<span class="number"> 14</span>   <span class="k1">float</span> des <span class="k3">=</span> <span class="k2">(</span><span class="n">0</span>.<span class="n">299</span><span class="k3">*</span>art.r <span class="k3">+</span> <span class="n">0</span>.<span class="n">587</span><span class="k3">*</span>art.g <span class="k3">+</span> <span class="n">0</span>.<span class="n">114</span><span class="k3">*</span>art.b<span class="k2">)</span><span class="k2">;</span> <span class="c">//desaturated grey value from the base RGB color, weighted for human perception</span>
<span class="number"> 15</span>   
<span class="number"> 16</span>   <span class="k1">float</span> bump <span class="k3">=</span> <span class="n">0</span>.<span class="n">03</span><span class="k2">;</span> <span class="c">// Brighten or darken results by tweaking this - recommend .03 to .1 to make desaturated area "pop"</span>
<span class="number"> 17</span>   
<span class="number"> 18</span>   <span class="k1">float</span> opacity <span class="k3">=</span> <span class="k2">(</span>tmp.r <span class="k3">+</span> tmp.g <span class="k3">+</span> tmp.b<span class="k2">)</span> <span class="k3">/</span> <span class="n">3</span><span class="k2">;</span>
<span class="number"> 19</span>   des <span class="k3">=</span> des <span class="k3">+</span> bump<span class="k2">;</span>
<span class="number"> 20</span>    tmp.r <span class="k3">=</span> <span class="k2">(</span>
<span class="number"> 21</span>      art.r <span class="k3">+</span> <span class="k2">(</span>
<span class="number"> 22</span>        <span class="k2">(</span>des <span class="k3">-</span> art.r<span class="k2">)</span>
<span class="number"> 23</span>        <span class="k3">*</span> opacity
<span class="number"> 24</span>      <span class="k2">)</span>
<span class="number"> 25</span>    <span class="k2">)</span><span class="k2">;</span>
<span class="number"> 26</span>    tmp.g <span class="k3">=</span> <span class="k2">(</span>
<span class="number"> 27</span>      art.g <span class="k3">+</span> <span class="k2">(</span>
<span class="number"> 28</span>        <span class="k2">(</span>des <span class="k3">-</span> art.g<span class="k2">)</span>
<span class="number"> 29</span>        <span class="k3">*</span> opacity
<span class="number"> 30</span>      <span class="k2">)</span>
<span class="number"> 31</span>    <span class="k2">)</span><span class="k2">;</span>
<span class="number"> 32</span>    tmp.b <span class="k3">=</span> <span class="k2">(</span>
<span class="number"> 33</span>      art.b <span class="k3">+</span> <span class="k2">(</span>
<span class="number"> 34</span>        <span class="k2">(</span>des <span class="k3">-</span> art.b<span class="k2">)</span>
<span class="number"> 35</span>        <span class="k3">*</span> opacity
<span class="number"> 36</span>      <span class="k2">)</span>
<span class="number"> 37</span>    <span class="k2">)</span><span class="k2">;</span>
<span class="number"> 38</span>   
<span class="number"> 39</span>   gl_FragColor <span class="k3">=</span> tmp<span class="k2">;</span>
<span class="number"> 40</span><span class="k2">}</span>
</div></div><p>

<a href="https://d1cxvcw9gjxu2x.cloudfront.net/attachments/607867">A screenshot of the shader</a></p><p>A video of the shader is here: <a href="http://www.youtube.com/watch?v=JefzZPhZd0Q">http://www.youtube.com/watch?v=JefzZPhZd0Q</a> (It&#39;s the first brush shader demonstrated)
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Winfield)</author>
		<pubDate>Mon, 05 Aug 2013 04:13:43 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p><s>Do you have some pictures of how that turns out?</s> Oh, right, you attached.  Hey that&#39;s cool.</p><div class="quote_container"><div class="title"><a href="http://www.allegro.cc/forums/thread/613054/988264#target">Winfield</a> said:</div><div class="quote"><p>Anyone who wants it, feel free to use it under the terms of the zLib license. [opensource.org]</p></div></div><p>Thank you sir, I will add this to my arsenal.  I&#39;ve been using a shadow layer (simple multiply blending) but I also want to desaturate the darker areas as well.  This will help.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Mark Oates)</author>
		<pubDate>Mon, 05 Aug 2013 09:06:01 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Sure thing! The other part of the magic is passing a second texture to the shader - the function you want is <a href="http://alleg.sourceforge.net/a5docs/refman/shader.html#al_set_shader_sampler">al_set_shader_sampler()</a>.</p><p>(In the case of using the shader I pasted, unit should be 1 if the stencil bitmap is the first texture.)</p><p>examples/ex_shader_multitex.c contains a good implementation, though it&#39;s kind of hard to follow - it took me a while before I realized that the regions it was creating existed directly on the backbuffer and thus don&#39;t need to be drawn explicitly as long as you&#39;re flipping the display.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Winfield)</author>
		<pubDate>Mon, 05 Aug 2013 10:14:49 +0000</pubDate>
	</item>
</rss>
