package away3d.extrusions { import flash.display.BitmapData; import flash.geom.Rectangle; import flash.geom.Point; import flash.geom.Matrix; public class ElevationReader { private var channel:String; private var levelBmd:BitmapData; private var elevate:Number; private var scalingX:Number; private var scalingY:Number; private var buffer:Array; private var level:Number; private var offsetX:Number = 0; private var offsetY:Number = 0; private var smoothness:int; private var _minElevation = 0; private var _maxElevation = 255; /** * Locks elevation factor beneath this level. Default is 0; * */ public function set minElevation(val:Number):void { _minElevation = val; } public function get minElevation():Number { return _minElevation; } /** * Locks elevation factor above this level. Default is 255; * */ public function set maxElevation(val:Number):void { _maxElevation = val; } public function get maxElevation():Number { return _maxElevation; } /** * Class generates a traced representation of the elevation geometry, allowing surface tracking to place or move objects on the elevation geometry. * */ public function ElevationReader(smoothness:int = 0) { buildBuffer(smoothness); } private function buildBuffer(smoothness:int = 0):void { this.smoothness = smoothness; buffer = []; for(var i:int = 0;i> 16 & 0xFF; if(maxElevation < r) r = maxElevation; if(minElevation > r) r = minElevation; if(smoothness == 0) return (r*elevate)+offset; buffer.push((r*elevate)+offset); buffer.shift(); level = 0; for(var i:int = 0;i w-1) { offsetX = (w-i-1)*.5; lockx = w-1; } else { lockx = i+subdivisionX; } for(j = 0; j < h+1; j+=subdivisionY) { if(j+subdivisionY > h-1) { offsetY = (h-j-1)*.5; locky = h-1; } else { locky = j+subdivisionY; } if(j == 0){ switch(channel){ case "a": px1 = sourceBmd.getPixel32(i, j) >> 24 & 0xFF; px2 = sourceBmd.getPixel32(lockx, j) >> 24 & 0xFF; px3 = sourceBmd.getPixel32(lockx, locky) >> 24 & 0xFF; px4 = sourceBmd.getPixel32(i, locky) >> 24 & 0xFF; break; case "r": px1 = sourceBmd.getPixel(i, j) >> 16 & 0xFF; px2 = sourceBmd.getPixel(lockx, j) >> 16 & 0xFF; px3 = sourceBmd.getPixel(lockx, locky) >> 16 & 0xFF; px4 = sourceBmd.getPixel(i, locky) >> 16 & 0xFF; break; case "g": px1 = sourceBmd.getPixel(i, j) >> 8 & 0xFF; px2 = sourceBmd.getPixel(lockx, j) >> 8 & 0xFF; px3 = sourceBmd.getPixel(lockx, locky) >> 8 & 0xFF; px4 = sourceBmd.getPixel(i, locky) >> 8 & 0xFF; break; case "b": px1 = sourceBmd.getPixel(i, j) & 0xFF; px2 = sourceBmd.getPixel(lockx, j) & 0xFF; px3 = sourceBmd.getPixel(lockx, locky) & 0xFF; px4 = sourceBmd.getPixel(i, locky) & 0xFF; break; case "av": px1 = ((sourceBmd.getPixel(i, j) >> 16 & 0xFF)*0.212671) + ((sourceBmd.getPixel(i, j) >> 8 & 0xFF)*0.715160) + ((sourceBmd.getPixel(i, j) & 0xFF)*0.072169); px2 = ((sourceBmd.getPixel(lockx, j) >> 16 & 0xFF)*0.212671) + ((sourceBmd.getPixel(lockx, j) >> 8 & 0xFF)*0.715160) + ((sourceBmd.getPixel(lockx, j) & 0xFF)*0.072169); px3 = ((sourceBmd.getPixel(lockx, locky) >> 16 & 0xFF)*0.212671) + ((sourceBmd.getPixel(lockx, locky) >> 8 & 0xFF)*0.715160) + ((sourceBmd.getPixel(lockx, locky) & 0xFF)*0.072169); px4 = ((sourceBmd.getPixel(i, locky) >> 16 & 0xFF)*0.212671) + ((sourceBmd.getPixel(i, locky) >> 8 & 0xFF)*0.715160) + ((sourceBmd.getPixel(i, locky) & 0xFF)*0.072169); } } else { px1 = px4; px2 = px3; switch(channel){ case "a": px3 = sourceBmd.getPixel32(lockx, locky) >> 24 & 0xFF; px4 = sourceBmd.getPixel32(i, locky) >> 24 & 0xFF; break; case "r": px3 = sourceBmd.getPixel(lockx, locky) >> 16 & 0xFF; px4 = sourceBmd.getPixel(i, locky) >> 16 & 0xFF; break; case "g": px3 = sourceBmd.getPixel(lockx, locky) >> 8 & 0xFF; px4 = sourceBmd.getPixel(i, locky) >> 8 & 0xFF; break; case "b": px3 = sourceBmd.getPixel(lockx, locky) & 0xFF; px4 = sourceBmd.getPixel(i, locky) & 0xFF; break; case "av": px3 = ((sourceBmd.getPixel(lockx, locky) >> 16 & 0xFF)*0.212671) + ((sourceBmd.getPixel(lockx, locky) >> 8 & 0xFF)*0.715160) + ((sourceBmd.getPixel(lockx, locky) & 0xFF)*0.072169); px4 = ((sourceBmd.getPixel(i, locky) >> 16 & 0xFF)*0.212671) + ((sourceBmd.getPixel(i, locky) >> 8 & 0xFF)*0.715160) + ((sourceBmd.getPixel(i, locky) & 0xFF)*0.072169); } } for(k = 0; k < subdivisionX; ++k) { incXL = 1/subdivisionX * k; incXR = 1-incXL; for(l = 0; l < subdivisionY; ++l) { incYL = 1/subdivisionY * l; incYR = 1-incYL; pxx = ((px1*incXR) + (px2*incXL))*incYR; pxy = ((px4*incXR) + (px3*incXL))*incYL; levelBmd.setPixel(k+i, l+j, pxy+pxx << 16 | 0xFF-(pxy+pxx) << 8 | 0xFF-(pxy+pxx) ); } } } } levelBmd.unlock(); } /** * Apply the generated height source to a bitmapdata. The height information is merged to the source creating a smoother look. * * @param src The bitmapdata that will be merged. * @param color [optional] The color that will be applied. Note that 32 bits color will allow alpha. 0x88FF0000 defines a red with .5 alpha while 0xFF0000 defines a red with no alpha. Default is .5 alpha black. * @param reverse [optional] Defines if the color is set using the heightmap from 0-255 or 255-0. Default = true, if a black is used, the darkest are will be at the base of the elevation. * @param blendmode [optional] Blendmode to be applyed in the merge. Possible string values are: lighten, multiply, overlay, screen, substract, add, darken, difference, erase, hardlight, invert and layer.Default = "normal"; */ public function applyHeightGradient(src:BitmapData, color:uint = 0x80000000, reverse:Boolean = true, blendmode:String = "normal"):void { var gs:BitmapData; var scl:Boolean; if(src.width != levelBmd.width || src.height != levelBmd.height){ scl = true; gs = levelBmd.clone(); var sclmat:Matrix = new Matrix(); var Wscl:Number = gs.width/src.width; var Hscl:Number = gs.height/src.height; sclmat.scale(Wscl, Hscl); var sclbmd:BitmapData = new BitmapData(gs.width * Wscl, gs.height * Hscl, true, 0x00FFFFFF); sclbmd.draw(gs, sclmat, null, "normal", sclbmd.rect, true); } else{ gs = levelBmd; } var mskBmd:BitmapData = new BitmapData(gs.width, gs.height, true, color); var z:Point = new Point(0,0); if(reverse){ mskBmd.copyChannel(gs,gs.rect,z,2,8); } else{ mskBmd.copyChannel(gs,gs.rect,z,1,8); } if(blendmode == "normal"){ src.copyPixels(mskBmd,mskBmd.rect,z,mskBmd,z,true); }else{ src.draw(mskBmd, null, null, blendmode, mskBmd.rect, true); } mskBmd.dispose(); if(scl){ sclbmd.dispose(); gs.dispose(); } } } }