WebGL笔记(五):封装顶点和颜色等数组数据(一)
顶点和颜色数据,均是数组类型,但数据冗长,例如一个立方体的颜色数据长度有96个,顶点为72个,管理比较麻烦。但是二者又有很大的相似性,不同之处仅在于分组的大小和取值范围。按照面向对象编程的思路,应该首先封装一个数组管理基类,然后通过继承和重载来分别实现顶点和颜色类。
基于Javascript面向对象方面的特性,首先建立一个工厂类作为实现继承的工具:
var Inherit = {
/* 对对象进行浅表复制,主要用于重载(覆盖)某些方法或属性 */
extend : function(o, oo){
for(var p in oo){ o[p] = oo[p]; };
p = null;
},
/*
* 通过创建的基类实例建立原型链,实现继承
* target:子类构造函数名
* obj:基类实例
* ext:扩展属性,包括子类独有的属性/方法和需要重载的部分
*/
inherit : function(target, obj, ext){
if(typeof target != 'function') return;
target.prototype = obj;
if(!!ext && ext instanceof Object){
this.extend(target.prototype, ext);
}
}
}
然后建立一个数组管理基类ArrayHelper
/*
* ArrayHelper
* 数组管理基类
* by MK 2011-12-1
*/
function ArrayHelper(){ }
ArrayHelper.prototype = {
IS_ArrayHelper : true,
/* 分组单元长度,初始值为1,颜色应为4,定点应为3,需重载 */
length : 1,
/* 附加到原始数组
@data:原始数组
@offset:位于原始数组的偏移量
*/
attach : function(data, offset){
delete this.data;
delete this.offset;
if(data instanceof Array){
this.data = data;
this.offset = Math.max(offset || 0, 0);
}
},
/* 遍历所位于的数组区域,并执行回调函数 */
each : function(callback){
if(typeof callback == 'function'){
for(var i = 0; i < this.length; i++){
callback(this.data, i + this.offset, i);
}
}
},
/* 获取本区索引位置值,index为相对位置 */
get : function(index){
if(typeof index == 'number' && index < this.length){
return this.data[index + this.offset];
}
},
/* 设置本区索引位置值,index为相对位置。具体执行取决于参数状态。需重载 */
set : function(value, index){
if(typeof index == 'number' && index < this.length){
this.data[index + this.offset] = value;
} else if(value instanceof Array){
this.each(function(data, ii, i){
if(i < value.length){
data[ii] = value[i];
}
});
} else if(value === 0 || !!value){
this.each(function(data, ii){
data[ii] = value;
});
}
},
/* 本区数据归零 */
clear : function(){
this.each(function(data, ii){ data[ii] = 0; });
},
/* 返回本区数据的一个副本 */
array : function(){
return this.data.slice(this.offset, this.offset + this.length);
}
}
下面使用Iherit对其进行继承重载,实现顶点与颜色两个区域管理类。
首先是颜色类
/*
ColorHelper
颜色管理类
by MK 2011-12-2
*/
var ColorHelper = function(data, offset){
/* 尝试附加数据 */
this.attach(data, offset);
/* 重载本区长度值 */
this.length = 4;
}
/* 扩展ColorHelper的静态方法 */
Inherit.extend(ColorHelper, {
/* 对象转换为颜色数据。转换失败则返回0 */
ObjectToNumber : function(s, d){
return (!!s?isNaN(s=Number('0x'+((s=s+'').length>1?s.substr(0,2):s+s)))?d||0:s:s===0?s:d||0)/255;
},
/*
* 将CSS颜色标记转换为颜色数组 [R, G, B, A]。
* 返回一个4个元素的数组,每个元素均在0~1之间
* 仅接受字符串类型参数
* 处理方法:
* 1. #fff/#ffff,以#ffffff或#ffffffff方式解读
* 2. #ffffff/#ffffffff,转换为三组或四组数据,顺序为R G B A。A部分失缺按ff处理
* 3. 5字补齐为6字,7字补齐为8字
* 4. 大于8字取前8字;小于3字,例如#cc,按#ccccccff处理
* 5. 井号不必需,读取时会掠过。
*/
FromCSS : function(v){
if(typeof v != 'string' || !v.length) return null;
if(v.charAt(0) == '#') v = v.substr(1);
if(v.length < 3){
return [v = this.ObjectToNumber(v), v, v, 1];
}
var reg;
switch(v.length){
case 3: case 4:
reg = /[0-f]/ig;
break;
case 6: case 8:
reg = /[0-f]{2}/ig;
break;
case 5: case 7:
return this.FromCSS(v + v.charAt(v.length - 1));
default:
return this.FromCSS(v.substr(0, 8));
}
arr = []
v.replace(reg,function(m){arr.push(ColorHelper.ObjectToNumber(m));});
v = reg = null;
return arr;
},
/* 返回一个0~1之间的数 */
Fix : function(v){
return typeof v != 'number'
? this.ObjectToNumber(v)
: this.Range(v > 1 ? v / 255 : v, 0, 1);
},
/* 返回指定范围的数 */
Range : function(v, mi, ma){
return Math.max(mi, Math.min(ma, v))
}
});
/* ColorHelper 对 ArrayHelper 的继承与重载 */
Inherit.inherit(ColorHelper, new ArrayHelper(), {
/* 随机设置RGB三个值 */
rand : function(){
this.each(function(data, ii){
data[ii] = Math.random();
});
this.set(1, 3);
},
/*
* 重载set
* 动态参数
* 处理方式:
* 1. 没有参数时,RGB归零,A=1
* 2. 1个参数时,字符串类型则尝试转换为CSS颜色,数字类型则调用基类set方法赋值
* 3. 2个或更多参数时,调用基类set方法赋值
*/
set : function(){
var args = Array.prototype.slice.call(arguments, 0)
, _set = ArrayHelper.prototype.set;
;
switch(args.length){
case 0:
this.clear();
_set.apply(this, [1, 3]);
break;
case 1:
if(typeof args[0] == 'string' && args[0].length){
_set.call(this, ColorHelper.FromCSS(args[0]));
} else if(typeof args[0] == 'number'){
_set.call(this, ColorHelper.Fix(args[0]));
}
break;
case 2:
args[0] = ColorHelper.Fix(args[0]);
args[1] = typeof args[1] == 'number' ? ColorHelper.Range(args[1], 0, 3) : 0;
_set.apply(this, args);
break;
default:
var i = 0, len = args.length;
for(; i < len; i++){
args[i] = ColorHelper.Fix(args[i]);
}
_set.call(this, args);
break;
}
args = _set = null;
}
});
顶点类比较简单
/*
* VerticesHelper
* 顶点管理类
* by MK 2011-12-2
*/
function VerticesHelper(data, offset){
this.attach(data, offset);
this.length = 3;
}
/* VerticesHelper 对 ArrayHelper 继承和重载 */
Inherit.inherit(VerticesHelper, new ArrayHelper(), {
/*
* 将本区每个值增长一个值,实现顶点的移动
* index有效时,对指定索引处赋值
* index无效时,对本区全体赋值
*/
move : function(v, index){
if(typeof v != 'number' && (!v || isNaN(v = parseFloat(v)))){
v = 0;
}
if(typeof index == 'number'){
this.set(this.get(index) * v, index);
} else {
this.each(function(data, ii, i){
data[ii] += v;
});
}
}
});
今天先写到这里。关于继承和重载方面欢迎大家多提意见。今天周末,祝大家周末愉快,我得回家了。
下一篇将介绍一个GroupHelper和ArrayHelper结合管理整个数组的应用,并扩展VerticesGroup和ColorGroup。代码文件先不上传了,有些地方还要完善一下,至少注释还没写完整哈!