In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

RGB Color Cube

My friends and I had some discussions about mixing color theory and linear algebra. One of the things we talked about was having color components as base vectors in a coordinate system, and this is pretty much just a visualization of that.

Rendered in some faux-3d kind of way, nothing too interesting there.
package {
    import flash.geom.Point;
    import flash.filters.ConvolutionFilter;
    import flash.filters.ColorMatrixFilter;
    import flash.events.Event;
    import flash.geom.Rectangle;
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    [SWF(width = "465", height = "465", backgroundColor = "0x000000")]
    public class FlashTest extends Sprite {
        public function FlashTest() {
            bmd = new BitmapData(400,400,true,0xff000000);
            stage.addChild(new Bitmap(bmd));
            
            stage.addEventListener(Event.ENTER_FRAME, doStuff);
        }
        
        private var bmd:BitmapData;
        private var time:Number = 0;
        private const TIMESTEP:Number = 0.01;
        private const FRAMES_BETWEEN_ACTIONS:int = 0;
        private var count:int = FRAMES_BETWEEN_ACTIONS;
        
        private const BG_COLOR = 0xff222222;
        private const BMD_HEIGHT:int = 400;
        private const BMD_WIDTH:int = 400;
        private const BMD_NUMPIX:int = 400*400;
        private var pixels:Vector.<uint> = new Vector.<uint>(BMD_HEIGHT*BMD_WIDTH, true);
        
        private var cmf:ColorMatrixFilter = new ColorMatrixFilter(
        [0.9, 0, 0, 0, 0,
         0, 0.9, 0, 0, 0,
         0, 0, 0.9, 0, 0,
         0, 0, 0, 0.97, 0]);
        
        private function drawStuff(theta:Number):void { 
            // A density constant
            var D:int = 10;
            
            // Half width height and depth
            var hW:int, hH:int, hD:int;
            hW = hH = hD = D;
            var X:Number, Y:Number, Z:Number;
            var dispX:int, dispY:int, index:int, color:uint;
            var sc:Number = 95/D;
            
            var x:Number, y:Number, z:Number;
            
            // Clear vector, or use trails?
            if(true) {
                var l:int = pixels.length;
                while(--l >= 0) {
                    pixels[l] = BG_COLOR;
                }
            } else {
                bmd.applyFilter(bmd, bmd.rect, new Point(), cmf);
                pixels = bmd.getVector(bmd.rect);
            }
            
            for (X = -hW; X<=hW; ++X) {
                for (Y = -hH; Y<=hH; ++Y) {
                    for (Z = -hD; Z<=hD; ++Z) {
                        // Set color based on coordinate
                        color = rgbaToHex((X+hW)/(2*hW), (Y+hH)/(2*hH), (Z+hD)/(2*hD), 0.9);
                        
                        // Get transformed coordinate index
                        index = transPtIndex(X,Y,Z,theta,sc);
                        
                        // Color a 2x2 square
                        if(index+BMD_WIDTH+1 < BMD_NUMPIX && index > 0) {
                            pixels[index] = color;
                            pixels[index+1] = color;
                            pixels[index+BMD_WIDTH] = color;
                            pixels[index+BMD_WIDTH+1] = color;
                        }
                    }
                }    
            }
            
            // Time to actually draw stuff
            bmd.lock();
            // Draw all colored points
            bmd.setVector(bmd.rect, pixels);
            
            // Define corners
            var p1:Point = transPt(new Point(-hW, -hH), theta, sc, -hD);
            var p2:Point = transPt(new Point(-hW,  hH), theta, sc, -hD);
            var p3:Point = transPt(new Point( hW,  hH), theta, sc, -hD);
            var p4:Point = transPt(new Point( hW, -hH), theta, sc, -hD);
            var p5:Point = transPt(new Point(-hW, -hH), theta, sc,  hD);
            var p6:Point = transPt(new Point(-hW,  hH), theta, sc,  hD);
            var p7:Point = transPt(new Point( hW,  hH), theta, sc,  hD);
            var p8:Point = transPt(new Point( hW, -hH), theta, sc,  hD);
            
            // Draw lines between corners to create a boundary cube
            
            efla(p1,p2,0xffffff,bmd);
            efla(p2,p3,0xffffff,bmd);
            efla(p3,p4,0xffffff,bmd);
            efla(p4,p1,0xffffff,bmd);
            
            efla(p5,p6,0xffffff,bmd);
            efla(p6,p7,0xffffff,bmd);
            efla(p7,p8,0xffffff,bmd);
            efla(p8,p5,0xffffff,bmd);
            
            efla(p1,p5,0xffffff,bmd);
            efla(p2,p6,0xffffff,bmd);
            efla(p3,p7,0xffffff,bmd);
            efla(p4,p8,0xffffff,bmd);
            
            bmd.unlock();
        }
        
        private function hslaToHex(h:Number,s:Number,l:Number,a:Number):uint {
            var C:Number, X:Number, m:Number, H:Number;
            m = 2*l-1;
            m = m<0 ? -m : m;
            C = (1-m)*s;
            
            H = 6*h;
            m = H%2 - 1;
            m = m<0 ? -m : m;
            X = C*(1-m);
            
            m = l - C/2;
            
            if(H <= 1) {
                return rgbaToHex(C+m,X+m,m,  a);
            } else if (H <= 2) {
                return rgbaToHex(X+m,C+m,m,  a);
            } else if (H <= 3) {
                return rgbaToHex(m,  C+m,X+m,a);
            } else if (H <= 4) {
                return rgbaToHex(m,  X+m,C+m,a);
            } else if (H <= 5) {
                return rgbaToHex(X+m,m,  C+m,a);
            } else {
                return rgbaToHex(C+m,m,  X+m,a);
            }
            
            return 0x00000000;
        }
        
        private function hsvaToHex(h:Number,s:Number,v:Number,a:Number):uint {
            var C:Number, X:Number, m:Number, H:Number;
            C = v*s;
            H = 6*h;
            m = H%2 - 1;
            m = m<0 ? -m : m;
            X = C*(1-m);
            m = v-C;
            
            if(H <= 1) {
                return rgbaToHex(C+m,X+m,m,  a);
            } else if (H <= 2) {
                return rgbaToHex(X+m,C+m,m,  a);
            } else if (H <= 3) {
                return rgbaToHex(m,  C+m,X+m,a);
            } else if (H <= 4) {
                return rgbaToHex(m,  X+m,C+m,a);
            } else if (H <= 5) {
                return rgbaToHex(X+m,m,  C+m,a);
            } else {
                return rgbaToHex(C+m,m,  X+m,a);
            }
            
            return 0x00000000;
        }
        
        private function rgbaToHex(r:Number,g:Number,b:Number,a:Number):uint {
            return (0xff*a << 24) | (0xff*r << 16) | (0xff*g << 8) | 0xff*b;
        }

        
        // Function to transform a single point
        private function transPt(p:Point, theta:Number, sc:Number, z:Number):Point {
            var x:Number = p.x*Math.cos(theta) + p.y*Math.sin(theta);
            var y:Number = p.y*Math.cos(theta) - p.x*Math.sin(theta);
            z = -z;
            
            p.x = 200+(x+y)*sc;
            p.y = 200+((x-y)/3 + 1.2*z)*sc;
            
            return p;
        }
        
        private function transPtIndex(x:Number, y:Number, z:Number, theta:Number, sc:Number):int {
            var p:Point = transPt(new Point(x,y), theta, sc, z);
            
            return int(p.x) + BMD_WIDTH*int(p.y);
        }

        
        private function doStuff(e:Event):void {
            time += TIMESTEP;
            if(++count <= FRAMES_BETWEEN_ACTIONS) {
                return;
            }
            count = 0;
            
            drawStuff(time);
        }
        
        private function efla(p1:Point, p2:Point, color:uint, bmd:BitmapData): void
        {
            var x:int =  p1.x;
            var y:int =  p1.y;
            var x2:int = p2.x;
            var y2:int = p2.y;
            
            var shortLen:int = y2-y;
            var longLen:int = x2-x;
 
            if ((shortLen ^ (shortLen >> 31)) - (shortLen >> 31) > (longLen ^ (longLen >> 31)) - (longLen >> 31))
            {
                shortLen ^= longLen;
                longLen ^= shortLen;
                shortLen ^= longLen;
 
                var yLonger:Boolean = true;
            }
            else
            {
                yLonger = false;
            }
 
            var inc:int = longLen < 0 ? -1 : 1;
 
            var multDiff:Number = longLen == 0 ? shortLen : shortLen / longLen;
 
            if (yLonger)
            {
                for (var i:int = 0; i != longLen; i += inc)
                {
                    bmd.setPixel(x + i*multDiff, y+i, color);
                }
            }
            else
            {
                for (i = 0; i != longLen; i += inc)
                {
                    bmd.setPixel(x+i, y+i*multDiff, color);
                }
            }
        }
    }
}