MathGem:Color Operations
From GPWiki
The wiki is now hosted by GameDev.NET at wiki.gamedev.net. All gpwiki.org content has been moved to the new server. However, the GPWiki forums are still active! Come say hello.
[edit] 32 bit DWORD/Long to separate R,G,B,A channelsThese functions will convert a 32bit DWORD/Long value to the R,G,B,A channels it's made of. This allows you to work on individual channels, instead of the entire color. This format is widely used in Microsoft Windows' GDI, where it is known as the COLORREF type. Keep in mind that most graphics libraries already provide functions that do this. [edit] C/C++void DWORD_To_RGBA(DWORD color, BYTE& r, BYTE& g, BYTE& b, BYTE& a) { r = (color & 0xFF000000) >> 24; g = (color & 0x00FF0000) >> 16; b = (color & 0x0000FF00) >> 8; a = (color & 0x000000FF); } [edit] PythonIn Python we do the bitshift first (unlike C/C++) because in Python versions older than 2.4 hex values greater than 0x7FFFFFFF return negative values (unless suffixed with "L" as in 0xFFFFFFFFL). def dword_to_rgba(color): r = (color >> 24) & 0xFF g = (color >> 16) & 0xFF b = (color >> 8) & 0xFF a = color & 0xFF return (r, g, b, a) [edit] Visual BasicIn Visual Basic we use the AND (bitwise), Mod, and division to split a color. This goes like so: Public Sub LongToRGB(Color As Long, Red As Long, Green As Long, Blue As Long) Dim lColor As Long lColor = Color Red = lColor Mod &H100 lColor = lColor \ &H100 Green = lColor Mod &H100 lColor = lColor \ &H100 Blue = lColor Mod &H100 End Sub [edit] R,G,B,A channels to 32 bit DWORD/LongThis code will combine the given RGBA channels to one DWORD/Long. The returning value can be used in DirectX. Note that DirectX provides it's own functions for this, as well. [edit] C/C++void RGBA_To_DWORD(DWORD& color, BYTE r, BYTE g, BYTE b, BYTE a) { color = (r << 24) | (g << 16) | (b << 8) | a; } [edit] Pythondef rgba_to_dword(r, g, b, a): color = (r << 24) | (g << 16) | (b << 8) | a return color [edit] Gamma correctionGamma correction is increasing or decreasing the brightness of a color. A higher gamma value will mean brighter colors, while a lower gamma value will result in darker colors. The code could be put in it's own macro or function. The code below uses the color in a range of 0-255 per channel. Make sure that you actually clamp the value to 0-255 after changing the gamma value, or it could lead to undesirable results. [edit] C/C++You must include math.h (C) or cmath (C++) for pow(). float fGammaCorrection = 2.5f; fR = pow( color.cR, fGammaCorrection ); fG = pow( color.cG, fGammaCorrection ); fB = pow( color.cB, fGammaCorrection ); [edit] PythonfGammaCorrection = 2.5 fR = cR ** fGammaCorrection fG = cG ** fGammaCorrection fB = cB ** fGammaCorrection [edit] Visual BasicDim fGammaCorrection as Single fGammaCorrection = 2.5 fR = color.bR ^ fGammaCorrection fG = color.bG ^ fGammaCorrection fB = color.bB ^ fGammaCorrection [edit] Interpolating colorsInterpolating between two colors, using a simple variable to control the interpolation amount. Note that DirectX8 and newer has their own D3DXColor* functions for all kinds of color operations. [edit] PythonfR = Color1.r + Amount * (Color2.r - Color1.r) fG = Color1.g + Amount * (Color2.g - Color1.g) fB = Color1.b + Amount * (Color2.b - Color1.b) fA = Color1.a + Amount * (Color2.a - Color1.a) [edit] Visual BasicDim fAmount as Single fR = Color1.r + fAmount * (Color2.r - Color1.r) fG = Color1.g + fAmount * (Color2.g - Color1.g) fB = Color1.b + fAmount * (Color2.b - Color1.b) fA = Color1.a + fAmount * (Color2.a - Color1.a) [edit] C/C++float fAmount; fR = Color1.r + fAmount * (Color2.r - Color1.r); fG = Color1.g + fAmount * (Color2.g - Color1.g); fB = Color1.b + fAmount * (Color2.b - Color1.b); fA = Color1.a + fAmount * (Color2.a - Color1.a); [edit] RGB and BGR conversions[edit] C/C++DWORD rgb_to_bgr(DWORD rgb) { int b, g, r; b = rgb & 0xFF; g = (rgb >> 8) & 0xFF; r = rgb >> 16; return (b << 16) | (g << 8) | r; } DWORD bgr_to_rgb(bgr) { int r, g, b; r = bgr & 0xFF; g = (bgr >> 8) & 0xFF; b = bgr >> 16; return (r << 16) | (g << 8) | b; } [edit] Pythondef rgb_to_bgr(rgb): b = rgb & 0xFF g = (rgb >> 8) & 0xFF r = rgb >> 16 return (b << 16) | (g << 8) | r def bgr_to_rgb(bgr): r = bgr & 0xFF g = (bgr >> 8) & 0xFF b = bgr >> 16 return (r << 16) | (g << 8) | b [edit] Working with floating point "scalar" colorsGiven that the color elements are often represented by a single byte, it is sometimes more useful to work with color as a value range of 0 to 1. Thus, a variable representing a color range is divided by the maximum value of a byte (255 or 0xFF for you hex lovers). You'll find this mathematical representation most often in fx, vertex, or pixel shader scripts. In order to use it in your own code you'll need to make some modifications to the standard operations. [edit] RulesSince a monitor can't represent colors brighter than white or darker than black or any elemental combination of brightness thereof, we have to clearly define what our results should be: struct color { double red,green,blue; }; // . . . inline void clipColorElements(const color _in, color &_out) { // Pardon the arcane c++. _out.red=(_in.red > 1.0) ? 1.0 : (_in.red < 0.0) ? 0.0 : _in.red; _out.green=(_in.green > 1.0) ? 1.0 : (_in.green < 0.0) ? 0.0 : _in.green; _out.blue=(_in.blue > 1.0) ? 1.0 : (_in.blue < 0.0) ? 0.0 : _in.blue; } // . . . [edit] ConversionNext we need to convert the standard format colors to scalars. void rgbToScalar(const BYTE red, const BYTE green, const BYTE blue, color &scalar_out) { scalar_out.red=red/255; scalar_out.green=green/255; scalar_out.blue=blue/255; } We also need a way to go back, of course. void scalarToRgb(const color scalar_in, BYTE &red, BYTE &green, BYTE &blue) { red=scalar_in.red*255; green=scalar_in.green*255; blue=scalar_in.blue*255; } [edit] OperationsNow we can throw the new operators into our color structure. Multiplication is the easiest, so we'll start with that. struct color { // . . . color operation * (const color rh) { red*=rh.red; green*=rh.green; blue*=rh.blue; } // . . . }; Addition is a little more difficult. struct color { // . . . color operation + (const color rh) { red+=rh.red; green+=rh.green; blue+=rh.blue; clipColorElements(this, this); } // . . . }; Subtraction is nearly identical struct color { // . . . color operation - (const color rh) { red-=rh.red; green-=rh.green; blue-=rh.blue; clipColorElements(this, this); } // . . . }; Not hard, is it? I don't recommend using this code from anything that will be running several times a second, but it's fine for calculating various effects and rendering fractals. With some modification it can be applied to sound waves as well. Note: I wrote these code samples from memory, so pardon me if it doesn't work "out of the box." Categories: MathGem | C | Python | VB | Programming Techniques |


