<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Crystal Schuller</title>
    <description>The latest articles on Forem by Crystal Schuller (@freerangepixels).</description>
    <link>https://forem.com/freerangepixels</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F163675%2F95312df4-9079-4a73-b60c-a124a0324291.jpg</url>
      <title>Forem: Crystal Schuller</title>
      <link>https://forem.com/freerangepixels</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/freerangepixels"/>
    <language>en</language>
    <item>
      <title>A Probably Terrible Way to Render Gradients</title>
      <dc:creator>Crystal Schuller</dc:creator>
      <pubDate>Sat, 18 May 2019 00:16:51 +0000</pubDate>
      <link>https://forem.com/freerangepixels/a-probably-terrible-way-to-render-gradients-1p3n</link>
      <guid>https://forem.com/freerangepixels/a-probably-terrible-way-to-render-gradients-1p3n</guid>
      <description>&lt;p&gt;My most recent project at &lt;a href="https://www.42.us.org/" rel="noopener noreferrer"&gt;42 Silicon Valley&lt;/a&gt; has me creating a 3-D wireframe rendering engine in C. One of the required capabilities is to smoothly change the color of rendered lines according to their elevation, like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07hvo2p35vwcix8mqhn8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07hvo2p35vwcix8mqhn8.png" width="800" height="638"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I needed to build a C function that can increment colors in a smooth gradient. It needed to work with &lt;a href="https://github.com/crouzet-o" rel="noopener noreferrer"&gt;Olivier Crouzet&lt;/a&gt;'s miniLibX, which interprets RGB colors as a single hexadecimal int (which is probably what every graphics library does? I did not research this).&lt;/p&gt;

&lt;p&gt;So we have one of these bois:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;0xFFFFFF&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;who needs to turn into this boi:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;0x2FA8F9&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;And it needs to look all pretty, like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0gtwn5uee5kigf2igo6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0gtwn5uee5kigf2igo6.png" width="800" height="798"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having not done math since 2002, I had my work cut out for me. &lt;/p&gt;

&lt;p&gt;I was floored to discover that these &lt;strong&gt;random jargon digits&lt;/strong&gt; have &lt;a href="https://www.youtube.com/watch?v=6cJd7eyYBFs" rel="noopener noreferrer"&gt;actually been RGB number values the whole time&lt;/a&gt;, with each two-digit pair representing the value of red, green or blue light. That means hex codes can be broken down like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypouow979tbmo2hpto8z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypouow979tbmo2hpto8z.png" width="734" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Armed with this revelation, it was clear I needed to somehow isolate digit pairs in a hexadecimal number, manipulate them, and re-combine them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Oh no,&lt;/em&gt; I realized, &lt;em&gt;I have to do math with base-16. God, please, no...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;No you don't,&lt;/em&gt; answered Beyoncé from on high via sunbeam, &lt;em&gt;This will actually be super easy because bitshifting exists.&lt;/em&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;Adventures in Bitshifting&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;In &lt;strong&gt;decimal notation,&lt;/strong&gt; 255 looks like this:&lt;br&gt;
&lt;code&gt;255&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and in &lt;strong&gt;hexadecimal notation,&lt;/strong&gt; it looks like this:&lt;br&gt;
&lt;code&gt;FF&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;but in &lt;strong&gt;binary,&lt;/strong&gt; it looks like this:&lt;br&gt;
&lt;code&gt;0000 0000 0000 0000 0000 0000 1111 1111&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Using the magic of &lt;a href="https://www.youtube.com/watch?v=jlQmeyce65Q" rel="noopener noreferrer"&gt;&lt;strong&gt;bitwise operators,&lt;/strong&gt;&lt;/a&gt; we can scooch this value over like this:&lt;br&gt;
&lt;code&gt;FF &amp;lt;&amp;lt; 8&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;which results in this:&lt;br&gt;
&lt;code&gt;0000 0000 0000 0000 1111 1111 0000 0000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;which in hexadecimal looks like this:&lt;br&gt;
&lt;code&gt;FF00&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and that means we can do the same in reverse, which allows us to isolate the first two digits of a hexadecimal number like this:&lt;br&gt;
&lt;code&gt;0x2FA8F9 &amp;gt;&amp;gt; 16 = 0x2F&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;We have our R value!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Isolating the G and B values requires using a &lt;em&gt;bitmask&lt;/em&gt; with the bitwise &lt;em&gt;and&lt;/em&gt;, which &lt;a href="https://www.youtube.com/watch?v=jlQmeyce65Q&amp;amp;t=266s" rel="noopener noreferrer"&gt;Neso Academy&lt;/a&gt; can explain better than I can, but which looks like this:&lt;br&gt;
&lt;code&gt;0x2FA8F9 &amp;amp; 0xFF = 0xF9&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In brief, it works like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;0x2FA8F9&lt;/strong&gt; in binary is:&lt;br&gt;
&lt;code&gt;0000 0000 0010 1111 1010 1000 1111 1001&lt;/code&gt;&lt;br&gt;
and &lt;strong&gt;0xFF&lt;/strong&gt; in binary is:&lt;br&gt;
&lt;code&gt;0000 0000 0000 0000 0000 0000 1111 1111&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The bitwise &lt;em&gt;and&lt;/em&gt; returns an integer containing the bits that both numbers have in common:&lt;br&gt;
&lt;code&gt;0000 0000 0000 0000 0000 0000 1111 1001&lt;/code&gt;&lt;br&gt;
Which is &lt;strong&gt;0xF9&lt;/strong&gt; in hexadecimal!&lt;/p&gt;

&lt;p&gt;We can use a combination of these techniques to isolate the G value, so what we're left with is this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;R = color &amp;gt;&amp;gt; 16&lt;/code&gt;&lt;br&gt;
&lt;code&gt;G = color &amp;gt;&amp;gt; 8 &amp;amp; 0xFF&lt;/code&gt;&lt;br&gt;
&lt;code&gt;B = color &amp;amp; 0xFF&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now that we have all the color values isolated into separate variables, the math can begin.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;The Math Begins&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;To create a gradient, we need to increment each color value by even increments, like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F556amaj4g552weofj845.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F556amaj4g552weofj845.png" width="800" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The increment value is nice and easy to calculate:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;increment = (end_color - start_color) / steps&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Steps&lt;/code&gt; here are just pixels. Since my line-drawing algorithm is &lt;strong&gt;Not Fancy™&lt;/strong&gt;, the number of pixels is just the larger of either x-distance or y-distance. We need the absolute (unsigned) values of these -- an x-change of -16 will evaluate as less than a y-change of 5, but 16 is the greater distance. I made a macro that finds the absolute max like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;steps = ABS_MAX((x1-x0), (y1-y0))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now that we have that, we can describe the color of each pixel as a function of three values: the &lt;code&gt;starting color&lt;/code&gt;, the &lt;code&gt;increment&lt;/code&gt;, and the &lt;code&gt;position&lt;/code&gt; in the line.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;color = (position * increment) + start_color&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If we store &lt;code&gt;position&lt;/code&gt; as a counter in our loop, we can find that piece easily, too.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;int position = 0;&lt;br&gt;
while(condition){&lt;br&gt;
 gradient_stuff(position);&lt;br&gt;
 position++;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;A Gradient Is Born&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Now that we have all the pieces, we can create our gradient!&lt;/p&gt;

&lt;p&gt;If we moved from our example colors &lt;strong&gt;0xFFFFFF&lt;/strong&gt; and &lt;strong&gt;0x2FA8F9&lt;/strong&gt; over 5 steps, our increments would be:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo43ds42yod9wxfu9wsw8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo43ds42yod9wxfu9wsw8.png" width="800" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's what it looks like when we apply our color formula to the individual color channels at each step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpdh409w4vgrao4t57137.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpdh409w4vgrao4t57137.png" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll notice all these values are rounded to the nearest whole number, since RGB values can't handle decimals.&lt;/p&gt;

&lt;p&gt;Once we have the individual values for R, G, and B, we can do the bitwise operations in reverse and add the values together to get the final color.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RGB = (R &amp;lt;&amp;lt; 16) + (G &amp;lt;&amp;lt; 8) + B&lt;/code&gt;&lt;br&gt;
&lt;code&gt;RGB = (0x2F &amp;lt;&amp;lt; 16) + (0xA8 &amp;lt;&amp;lt; 8) + (F9)&lt;/code&gt;&lt;br&gt;
&lt;code&gt;RGB = 0x2F0000 + 0x00A800 + 0x0000F9&lt;/code&gt;&lt;br&gt;
&lt;code&gt;RGB = 0x2FA8F9&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here's what that looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqt5awo25h3a9a299uuxe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqt5awo25h3a9a299uuxe.png" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of this has been done before, and probably a lot more elegantly and efficiently. But this function is my function and I made it all by myself, so I get a popsicle*. If you want to see more of this for some reason, you can view the rest of the project (still in progress) on &lt;a href="https://github.com/tasertasertaser/fdf" rel="noopener noreferrer"&gt;github&lt;/a&gt;.&lt;br&gt;
Here's the function in it's entirety.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# define R(a) (a) &amp;gt;&amp;gt; 16
# define G(a) ((a) &amp;gt;&amp;gt; 8) &amp;amp; 0xFF
# define B(a) (a) &amp;amp; 0xFF
# define RGB(a, b, c) ((a) &amp;lt;&amp;lt; 16) + ((b) &amp;lt;&amp;lt; 8) + (c)

int gradient(int startcolor, int endcolor, int len, int pix)
{
    double increment[3];
    int new[3];
    int newcolor;

    increment[0] = (double)((R(endcolor)) - (R(startcolor))) / (double)len;
    increment[1] = (double)((G(endcolor)) - (G(startcolor))) / (double)len;
    increment[2] = (double)((B(endcolor)) - (B(startcolor))) / (double)len;

    new[0] = (R(startcolor)) + ft_round(pix * increment[0]);
    new[1] = (G(startcolor)) + ft_round(pix * increment[1]);
    new[2] = (B(startcolor)) + ft_round(pix * increment[2]);

    newcolor = RGB(new[0], new[1], new[2]);

    return (newcolor);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;sup&gt;* they do not actually give us popsicles. &lt;/sup&gt;&lt;/p&gt;

</description>
      <category>c</category>
      <category>color</category>
      <category>beginners</category>
      <category>42</category>
    </item>
  </channel>
</rss>
