Hello,
I don't know if this has been fixed recently, but in the Elevation
class, generate() method, there is a "break" missing in the switch
statement, for color channel "b".
Also, in the "av" channel equation, I am not sure if this is correct:
cha = ((color >> 16 & 0xFF)*0.212671) + ((color >> 8 & 0xFF)*0.715160)
+ ((color >> 8 & 0xFF)*0.072169);
I think it the blue channel portion should be:
cha = ((color >> 16 & 0xFF)*0.212671) + ((color >> 8 & 0xFF)*0.715160)
+ ((color >> 0xFF)*0.072169);
(Or is that even the blue channel?)
Finally, I would like to submit my re-working of this class for some
minor speed improvements. I have added a generateAverage() method,
since that is the odd one, and removed the switch and inline-if from
inside the for-loop. Also, I have set up the channel bit references
and multipliers as private static const's. These might be moved to a
public static const in a base class, and used elsewhere as needed,
too.
Entire Elevation class follows:
==============
package away3d.extrusions
{
import flash.display.BitmapData;
import away3d.core.math.Number3D;
/**
* Class Elevation returns a multidimentional array of Number3D's to
pass to the SkinClass in order to generate an elevated mesh from
<Elevation></code>
*
*/
public class Elevation {
private var _minElevation:Number = 0;
private var _maxElevation:Number = 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;
}
/**
* Creates a generate <code>Elevation</code> object.
*
*/
public function Elevation()
{
}
/**
* Generate the Array representing the mesh
*
* @param sourceBmd
Bitmapdata. The bitmapData to read from.
* @param channel
[optional] String. The channel information to
read. supported "a", alpha, "r", red, "g", green, "b", blue and
"av" (averages and luminance). Default is red channel "r".
* @param subdivisionX [optional] int.
The subdivision to read the
pixels along the x axis. Default is 10.
* @param subdivisionY [optional] int.
The subdivision to read the
pixels along the y axis. Default is 10.
* @param scalingX
[optional] Number. The scale multiplier along
the x axis. Default is 1.
* @param scalingY
[optional] Number. The scale multiplier along
the y axis. Default is 1.
* @param elevate
[optional] Number. The scale multiplier along
the z axis. Default is .5.
*/
public function generate(sourceBmd:BitmapData, channel:String =
"r",
subdivisionX:int = 10, subdivisionY:int = 10, scalingX:Number = 1,
scalingY:Number = 1, elevate:Number = .5):Array
{
channel = channel.toLowerCase();
var w:int = sourceBmd.width;
var h:int = sourceBmd.height;
var i:int;
var j:int;
var x:Number = 0;
var y:Number = 0;
var z:Number = 0;
var totalArray:Array = [];
var tmpArray:Array = [];
var color:uint;
var cha:Number;
for(j = h-1; j >-subdivisionY; j-=subdivisionY)
{
y = (j<0)? 0 : j;
tmpArray = [];
for(i = 0; i < w+subdivisionX; i+=subdivisionX)
{
x = (i<w-1)? i : w-1;
color = (channel == "a")?
sourceBmd.getPixel32(x, y) :
sourceBmd.getPixel(x, y);
switch(channel){
case "a":
cha = color >> 24 &
0xFF;
break;
case "r":
cha = color >> 16 &
0xFF;
break;
case "g":
cha = color >> 8 & 0xFF;
break;
case "b":
cha = color & 0xFF;
case "av":
cha = ((color >> 16 &
0xFF)*0.212671) + ((color >> 8 & 0xFF)
*0.715160) + ((color >> 8 & 0xFF)*0.072169);
}
if(maxElevation < cha)
cha = maxElevation;
if(minElevation > cha)
cha = minElevation;
z = cha*elevate;
tmpArray.push(new Number3D(x*scalingX,
y*scalingY, z));
}
totalArray.push(tmpArray);
}
return totalArray;
}
// NEW GENERATE FUNCTIONS:
private static const ALPHA_CHANNEL:int = 24 & 0xFF;
private static const RED_CHANNEL:int = 16 & 0xFF;
private static const GREEN_CHANNEL:int = 8 & 0xFF;
private static const BLUE_CHANNEL:int = 0xFF;
private static const RED_AVG:Number = 0.212671;
private static const BLUE_AVG:Number = 0.715160;
private static const GREEN_AVG:Number = 0.072169;
/**
* generate_new
*
* Delfeld, 2009
*
* Generate the Array representing the mesh for RGBA (but not
average) color channel; serves as a passthrough method for
generateAverage.
*
* @param sourceBmd
Bitmapdata. The bitmapData to read from.
* @param channel
[optional] String. The channel information to
read. supported "a", alpha, "r", red, "g", green, "b", blue and
"av" (averages and luminance). Default is red channel "r".
* @param subdivisionX [optional] int.
The subdivision to read the
pixels along the x axis. Default is 10.
* @param subdivisionY [optional] int.
The subdivision to read the
pixels along the y axis. Default is 10.
* @param scalingX
[optional] Number. The scale multiplier along
the x axis. Default is 1.
* @param scalingY
[optional] Number. The scale multiplier along
the y axis. Default is 1.
* @param elevate
[optional] Number. The scale multiplier along
the z axis. Default is .5.
*/
public function generate_new(sourceBmd:BitmapData,
channel:String =
"r", subdivisionX:int = 10, subdivisionY:int = 10, scalingX:Number =
1, scalingY:Number = 1, elevate:Number = .5):Array
{
channel = channel.toLowerCase();
if ( channel == "av" )
{
return generateAverage(sourceBmd, channel,
subdivisionX,
subdivisionY, scalingX, scalingY, elevate);
}
trace("Elevation.generate_new");
var w:int = sourceBmd.width;
var h:int = sourceBmd.height;
var i:int;
var j:int;
var x:Number = 0;
var y:Number = 0;
var z:Number = 0;
var totalArray:Array = [];
var tmpArray:Array = [];
//var color:uint;
var cha:Number;
var bit:int;
switch(channel){
case "a":
bit = ALPHA_CHANNEL;
break;
case "r":
bit = RED_CHANNEL;
break;
case "g":
bit = GREEN_CHANNEL;
break;
case "b":
bit = BLUE_CHANNEL;
break;
default:
throw new Error("Elevation.generate_new:
Invalid channel: " +
channel + "\n");
return null;
}
var getColorFunction:Function = (channel == "a")?
sourceBmd.getPixel32 : sourceBmd.getPixel;
for(j = h-1; j >-subdivisionY; j-=subdivisionY)
{
y = (j<0)? 0 : j;
tmpArray = [];
for(i = 0; i < w+subdivisionX; i+=subdivisionX)
{
x = (i<w-1)? i : w-1;
//color = (channel == "a")?
sourceBmd.getPixel32(x, y) :
sourceBmd.getPixel(x, y);
cha = getColorFunction(x, y) >> bit;
//switch(channel){
//case "a":
//cha = color >> 24 &
0xFF;
//break;
//case "r":
//cha = color >> bit &
0xFF;
//break;
//case "g":
//cha = color >> 8 &
0xFF;
//break;
//case "b":
//cha = color & 0xFF;
//case "av":
//cha = ((color >> 16 &
0xFF)*0.212671) + ((color >> 8 & 0xFF)
*0.715160) + ((color >> 8 & 0xFF)*0.072169);
//}
if(maxElevation < cha)
cha = maxElevation;
if(minElevation > cha)
cha = minElevation;
z = cha*elevate;
tmpArray.push(new Number3D(x*scalingX,
y*scalingY, z));
}
totalArray.push(tmpArray);
}
return totalArray;
}
/**
* generateAverage
*
* Delfeld, 2009
*
* Generate the Array representing the mesh for the average color
channels.
*
* @param sourceBmd
Bitmapdata. The bitmapData to read from.
* @param channel
[optional] String. The channel information to
read. supported "a", alpha, "r", red, "g", green, "b", blue and
"av" (averages and luminance). Default is red channel "r".
* @param subdivisionX [optional] int.
The subdivision to read the
pixels along the x axis. Default is 10.
* @param subdivisionY [optional] int.
The subdivision to read the
pixels along the y axis. Default is 10.
* @param scalingX
[optional] Number. The scale multiplier along
the x axis. Default is 1.
* @param scalingY
[optional] Number. The scale multiplier along
the y axis. Default is 1.
* @param elevate
[optional] Number. The scale multiplier along
the z axis. Default is .5.
*/
public function generateAverage(sourceBmd:BitmapData,
channel:String
= "av", subdivisionX:int = 10, subdivisionY:int = 10, scalingX:Number
= 1, scalingY:Number = 1, elevate:Number = .5):Array
{
channel = channel.toLowerCase();
if ( channel != "av" )
{
return generate_new(sourceBmd, channel,
subdivisionX,
subdivisionY, scalingX, scalingY, elevate);
}
trace("Elevation.generateAverage");
var w:int = sourceBmd.width;
var h:int = sourceBmd.height;
var i:int;
var j:int;
var x:Number = 0;
var y:Number = 0;
var z:Number = 0;
var totalArray:Array = [];
var tmpArray:Array = [];
var color:uint;
var cha:Number;
for(j = h-1; j >-subdivisionY; j-=subdivisionY)
{
y = (j<0)? 0 : j;
tmpArray = [];
for(i = 0; i < w+subdivisionX; i+=subdivisionX)
{
x = (i<w-1)? i : w-1;
color = sourceBmd.getPixel(x, y);
cha =
((color >> RED_CHANNEL) *
RED_AVG)
+ ((color >> GREEN_CHANNEL) *
GREEN_AVG)
+ ((color >> BLUE_CHANNEL) *
BLUE_AVG)
;
if(maxElevation < cha)
cha = maxElevation;
if(minElevation > cha)
cha = minElevation;
z = cha*elevate;
tmpArray.push(new Number3D(x*scalingX,
y*scalingY, z));
}
totalArray.push(tmpArray);
}
return totalArray;
}
}
}