dcsimg
A Flash Developer Resource Site

Results 1 to 7 of 7

Thread: palette shift color cycle

  1. #1
    Junior Member
    Join Date
    Feb 2010
    Posts
    4

    palette shift color cycle

    I'm trying to get an old school effect going. A color cycle old games like warcraft used it for ocean animation. Basically the waves were not animated but the blue shades shifted one value looping forever.

    I'm quite new to as3 and am having trouble accomplishing this however I know this is possible with paletteMap().

    I've found this example fla which comes close:
    http://www.fumiononaka.com/Sample/Fl...aletteMap.html
    However this changes the colors way too much I basically want to shift the colors already in the image so blue to different shades of blue and not get red green or yellow waves.

    I've also found this link which seems to be dealing with the same thing:
    http://board.flashkit.com/board/showthread.php?t=797975

    If someone has a simple sample or advise i'd be grateful!
    Attached Images Attached Images

  2. #2
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    You mean something like this? Your 'cycleme' is predominantly red, so that's what I cycled. To minimize the jarring transition from high to low, I only cycle the red values among the values that were present to begin with.

    Code:
    package 
    {
    	import flash.display.Bitmap;
    	import flash.display.BitmapData;
    	import flash.display.Sprite;
    	import flash.events.Event;
    	import flash.geom.Point;
    	
    	/**
    	 * ...
    	 * @author srs
    	 */
    	public class Main extends Sprite 
    	{
    		[Embed(source = '../lib/cycleme.png')]
    		private var imgClass:Class;
    		
    		private var img:Bitmap;
    		
    		private var redarr:Array;
    		private const origin:Point = new Point();
    		
    		public function Main():void 
    		{
    			if (stage) init();
    			else addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    		
    		private function init(e:Event = null):void 
    		{
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    			// entry point
    			img = new imgClass();
    			addChild(img);
    			redarr = new Array();
    			setUpPaletteMap(img.bitmapData);
    			addEventListener(Event.ENTER_FRAME, shiftColor);
    		}
    		
    		private function setUpPaletteMap(bd:BitmapData):void {
    			var i:int;
    			for (i = 0; i < 256; i++){
    				redarr[i] = 0;
    			}
    			var redsInImg:Array = new Array();
    			var seenReds:Array = new Array();
    			var px:Vector.<uint> = bd.getVector(bd.rect);
    			for (i = 0; i < px.length; i++) {
    				var redval:uint = (px[i] & 0x00ff0000) >> 16;
    				if (!seenReds[redval]) {
    					//trace('px: '+px[i].toString(16)+' redval: '+ redval.toString(16));
    					seenReds[redval] = true;
    					redsInImg.push(redval);
    				}
    			}
    			redsInImg.sort(Array.NUMERIC);
    			trace('redsInImg: ' + redsInImg);
    			for (var j:int = 0; j < redsInImg.length -1; j++) {
    				redarr[redsInImg[j]] = (redsInImg[j + 1]) << 16;
    			}
    			redarr[redsInImg[redsInImg.length - 1]] = redsInImg[0] << 16;
    			trace(redarr);
    		}
    		
    		private function shiftColor(e:Event):void {
    			img.bitmapData.paletteMap(img.bitmapData, img.bitmapData.rect, origin, redarr, null, null, null);
    		}
    		
    	}
    	
    }

  3. #3
    Junior Member
    Join Date
    Feb 2010
    Posts
    4
    Cool its getting closer! Thanks!
    This is the desired effect grabbed a screen from this game to test:
    http://www.youtube.com/watch?v=1Y7qOVGN-f8

  4. #4
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    So more like this:
    Code:
    package 
    {
    	import flash.display.Bitmap;
    	import flash.display.BitmapData;
    	import flash.display.Sprite;
    	import flash.events.Event;
    	import flash.geom.Point;
    	
    	/**
    	 * ...
    	 * @author srs
    	 */
    	public class Main extends Sprite 
    	{
    		[Embed(source = '../lib/cycleme.png')]
    		private var imgClass:Class;
    		
    		private var img:Bitmap;
    		private var srcbm:BitmapData;
    		
    		private var redarr:Array;
    		private const origin:Point = new Point();
    		
    		public function Main():void 
    		{
    			if (stage) init();
    			else addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    		
    		private function init(e:Event = null):void 
    		{
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    			// entry point
    			img = new imgClass();
    			srcbm = img.bitmapData.clone();
    			addChild(img);
    			redarr = new Array();
    			setUpPaletteMap(img.bitmapData);
    			addEventListener(Event.ENTER_FRAME, shiftColor);
    		}
    		
    		private function setUpPaletteMap(bd:BitmapData):void {
    			var i:int;
    			var pi:Number = Math.PI;
    			var sin:Function = Math.sin;
    			for (i = 0; i < 256; i++) {
    				redarr[i] = int(sin(i * (pi / 256)) * 255) << 16;
    				trace(redarr[i]);
    			}
    			trace(redarr);
    		}
    		
    		private function shiftColor(e:Event):void {
    			img.bitmapData.paletteMap(srcbm, img.bitmapData.rect, origin, redarr, null, null, null);
    			redarr.push(redarr.shift());
    		}
    		
    	}
    	
    }
    In this case, the values run the whole gamut of red values from 0 to 255. You could alter the frequency and range of the red values by adjusting the math in setUpPaletteMap.

    This one works slightly differently than before. It always uses the original bitmapdata as a source, and shifts the palette around to produce the shifting pattern.

  5. #5
    Junior Member
    Join Date
    Feb 2010
    Posts
    4
    Thats a lot smoother, great!
    I've been trying to figure out how to only loop through the colors in the existing palette. I figured that your first sample was closer to the mark in that reagrd although the second example looks better.

    I tried modifying your first sample to not only cycle the reds but all colors hoping that would fix it. But its not the desired result yet:

    Code:
    package{
    	import flash.display.Bitmap;
    	import flash.display.BitmapData;
    	import flash.display.Sprite;
    	import flash.events.Event;
    	import flash.geom.Point;
    	
    	/**
    	 * ...
    	 * @author srs
    	 */
    	public class Main extends Sprite 
    	{
    		[Embed(source = 'cycleme.png')]
    		private var imgClass:Class;
    		
    		private var img:Bitmap;
    		
    		private var redarr:Array;
    		private var bluearr:Array = new Array;
    		private var greenarr:Array = new Array;
    		private const origin:Point = new Point();
    		
    		public function Main():void 
    		{
    			if (stage) init();
    			else addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    		
    		private function init(e:Event = null):void 
    		{
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    			// entry point
    			img = new imgClass();
    			addChild(img);
    			redarr = new Array();
    			setUpPaletteMap(img.bitmapData);
    			addEventListener(Event.ENTER_FRAME, shiftColor);
    		}
    		
    		private function setUpPaletteMap(bd:BitmapData):void {
    		//red	
    			var i:int;
    			for (i = 0; i < 256; i++){
    				redarr[i] = 0;
    			}
    			var redsInImg:Array = new Array();
    			var seenReds:Array = new Array();
    			var px:Vector.<uint> = bd.getVector(bd.rect);
    			for (i = 0; i < px.length; i++) {
    				var redval:uint = (px[i] & 0x00ff0000) >> 16;
    				if (!seenReds[redval]) {
    					//trace('px: '+px[i].toString(16)+' redval: '+ redval.toString(16));
    					seenReds[redval] = true;
    					redsInImg.push(redval);
    				}
    			}
    			redsInImg.sort(Array.NUMERIC);
    			trace('redsInImg: ' + redsInImg);
    			for (var j:int = 0; j < redsInImg.length -1; j++) {
    				redarr[redsInImg[j]] = (redsInImg[j + 1]) << 16;
    			}
    			redarr[redsInImg[redsInImg.length - 1]] = redsInImg[0] << 16;
    			trace(redarr);
    			
    		//blue
    			for (i = 0; i < 256; i++){
    				bluearr[i] = 0;
    			}
    			var bluesInImg:Array = new Array();
    			var seenBlues:Array = new Array();
    			px = bd.getVector(bd.rect);
    			for (i = 0; i < px.length; i++) {
    				var blueval:uint = (px[i] & 0x000000ff);
    				if (!seenBlues[blueval]) {
    					//trace('px: '+px[i].toString(16)+' blueval: '+ blueval.toString(16));
    					seenBlues[blueval] = true;
    					bluesInImg.push(blueval);
    				}
    			}
    			bluesInImg.sort(Array.NUMERIC);
    			trace('bluesInImg: ' + bluesInImg);
    			for (j = 0; j < bluesInImg.length -1; j++) {
    				bluearr[bluesInImg[j]] = (bluesInImg[j + 1]);
    			}
    			bluearr[bluesInImg[bluesInImg.length - 1]] = bluesInImg[0];
    			trace(bluearr);
    			
    		//green
    			for (i = 0; i < 256; i++){
    				greenarr[i] = 0;
    			}
    			var greensInImg:Array = new Array();
    			var seenGreens:Array = new Array();
    			px = bd.getVector(bd.rect);
    			for (i = 0; i < px.length; i++) {
    				var greenval:uint = (px[i] & 0x00ff00) >> 8;
    				if (!seenGreens[greenval]) {
    					//trace('px: '+px[i].toString(16)+' greenval: '+ greenval.toString(16));
    					seenGreens[greenval] = true;
    					greensInImg.push(greenval);
    				}
    			}
    			greensInImg.sort(Array.NUMERIC);
    			trace('greensInImg: ' + greensInImg);
    			for (j = 0; j < greensInImg.length -1; j++) {
    				greenarr[greensInImg[j]] = (greensInImg[j + 1]) << 8;
    			}
    			greenarr[greensInImg[greensInImg.length - 1]] = greensInImg[0] << 8;
    			trace(greenarr);			
    
    		}
    		
    		private function shiftColor(e:Event):void {
    			img.bitmapData.paletteMap(img.bitmapData, img.bitmapData.rect, origin, redarr, greenarr, bluearr, null);
    		}
    		
    	}
    	
    }
    In this sample http://board.flashkit.com/board/showthread.php?t=797975
    they actually supply a seperate png for the palette and supply the png in only blue so a cycle through the blue channel would suffice. Is this the way to approach it?
    Thanks for bringing me already a lot more closer to my goal!

  6. #6
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I think the second code posted is actually a lot closer to what you want. I'm not sure that you want to cycle the other colors in the first place. If you do, you can do them independently.
    In the second code sample, the original image is cloned, and the red channel is used as indices into the generated palette array, just like the other thread was talking about. The generated palette is simply a looping distribution of red values from 0 - 255 back to 0. If this went from redmin to redmax instead of 0 - 255, the resultant values would more closely match the input.

    For each pixel in the source bitmap, we look up its red value in the generated array and output the smoothly varying generated value. This is an approximation to the ideal, actually, since the mapped value may not be the input value for the first iteration. But because both source and palette vary smoothly, the result also varies smoothly. You could generate an inverse palette when you generate the smoothly varying palette and use that to map the original input into nearest-fit palette indices.

    Every frame, the palette is rotated, with the item at index 0 being shuffled to the end. This means that every frame, every pixel gets a little darker or lighter by marching through the palette array values.

  7. #7
    Junior Member
    Join Date
    Feb 2010
    Posts
    4
    Alright got it. I notice in photoshop that cycleme.png only has 50 or so indexed colors instead of 256 that might be the reason the image turns so red at some states. So I must somehow make it cycle only through does colors.
    I've got to get deeper into the material I guess to figure it all out...
    Thanks a lot for your help! I'm sure that once I get a better understanding of all of this I'll get closer to the endgoal

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center