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。代码文件先不上传了,有些地方还要完善一下,至少注释还没写完整哈!

posted @ 2011-12-02 18:12  MKing's Kindom  阅读(1916)  评论(0编辑  收藏  举报