User blog:SlackerPrime/Per-Pixel Scroller pt. 3 - Now in color!

This next lesson is a bit of a doozy. We're gonna learn some things and look at some more math. What we're gonna do is create a very specific pulsating color effect on our text. It's gonna be more complicated than it needs to be, but that's just my way.

We're gonna need to make a quick change first. Remember our variable PAL? I use it for a reason, and that reason is now. Set it to something other than 0. 1 is fine. We don't want to rewrite the zero-index palettes because the edit screen uses those.

Alright, ready to dive in and look at some pretty colors? Yes?

No you aren't. I need to explain something first.

An Introduction to the YCbCr Colorspace
RGB, who needs it? For our colorcycler, we're computing colors in the YCbCr colorspace and converting them to RGB. Why did I use this specific color format? It created the most appealing results with the least work (but with admittedly more math). I wanted a colorcycler that cycled through a variation of color tones unlike that of your traditional rainbow. At the same time, I wanted these colors to pulsate darker and lighter. YCbCr had just what I needed, but I needed to understand the conversion math how exactly the colorspace does it's thing.

For your own sake, look at this picture. Really, do it. It's very helpful.



This picture explains the YCbCr colorspace in words I can't even articulate. As they say, a picture is worth a thousand words. Essentially, the Y component controls the brightness, or luminance, of the color. The Cb and Cr components are like coordinates representing a color in a 2D space like the image above (colorspace, get it?). Imagine that our color is a point A on the CbCr plot. What we're doing is rotating this point about the origin at a fixed distance away to get a cycling color effect. At the same time, we're repeatedly altering the Y component to change the brightness of our color. Why do these components work out to these colors? Honestly, I don't understand the conversion math. I just know how to implement.

Now that we know what we want to do, we just have to do it.

Getting Those Colors On-Screen
This next routine is going to be given to you and then explained afterward. That's just how I like to do things, mmkay? @COLOR PY=127+63*SIN(COLC*PI/FLSHR) CB=127+63*COS(COLC*PI/CYCR) CR=127+63*SIN(COLC*PI/CYCR) CBP=CB-128 CRP=CR-128 AR=PY+(1.4*CRP) AG=PY+(-.343*CBP)+(-.711*CRP) AB=PY+(1.765*CBP) IF AR>255 THEN AR=255 IF AR<0 THEN AR=0 IF AG>255 THEN AG=255 IF AG<0 THEN AG=0 IF AB>255 THEN AB=255 IF AB<0 THEN AB=0 R$=HEX$(AR,2) G$=HEX$(AG,2) B$=HEX$(AB,2) COLSET "BG",(PAL*16)+15,R$+G$+B$ RETURN Well, we're doing math in just about every step here. No fear! I can explain.

Those first three equations compute our YCbCr color components. They all use the same base formula. Essentially, we're getting a value based on an angle COLC. By using trig functions (SIN and COS) these values change smoothly and repeat evenly. Notice, if you will, that the equation for PY contains FLSHR but the others contain CYCR. This is because we wan't the color to change at a different phase, or frequency, than the brightness. The brightness pulsates quickly while the color smoothly cycles at a walking pace. We'll have to define FLSHR and CYCR as constants at the beginning. You know how to do that. Set FLSHR to 18 and CYCR to 180.

The next equations convert our PY, CB, and CR values into RGB values. Again, I don't know why or how this works out, it just does. Go with it. All I know is that these equations are written out as matrices almost everywhere else, and PTC can't do the dot product. I wrote them out longform like this so they can actually be used. You can thank me some other time.

The rest of this preps the color and writes it to the palette. We have to clamp our RGB values to the valid range because this math can pass values outside of it. When the Y component passes certain thresholds, colors can be "whiter that white" or "blacker than black". You might notice that we're even doing math in our COLSET! That's okay. This means that we can use any palette given by PAL. Don't mind it.

If you want a more in-depth look at all of this math nonsense, I might do a follow-up blog post.

@LOOP VSYNC 1 GOSUB @COLOR GOSUB @DRAW GOSUB @SINE SWAP PA,PB GPAGE 0,PA,PB SOFS=SOFS-0.05 TEXTX=TEXTX-SPEED COLC=COLC+2 GOTO @LOOP Notice we update COLC every loop. This drives the cyclic nature of our color. Without it, the color would never change.
 * ahem* Anyway, time to put this thing into our main loop. Simple enough.

Run it. Right now. Look at the pretty colors. You did it. Next lesson, we wrap up this gosh-darned tutorial series.