Core/Geometry.js

/** 
 * A class representing a geometry.
 * 
 * @property {String} type The type name of this object (Lore.Geometry).
 * @property {String} name The name of this geometry.
 * @property {WebGLRenderingContext} gl A WebGL rendering context.
 * @property {Lore.Shader} shader An initialized shader.
 * @property {Object} attributes A map mapping attribute names to Lore.Attrubute objects.
 * @property {Lore.DrawMode} [drawMode=gl.POINTS] The current draw mode of this geometry.
 * @property {Boolean} isVisisble A boolean indicating whether or not this geometry is currently visible.
 */
Lore.Geometry = class Geometry extends Lore.Node {
    constructor(name, gl, shader) {
        super();

        this.type = 'Lore.Geometry';
        this.name = name;
        this.gl = gl;
        this.shader = shader;
        this.attributes = {};
        this.drawMode = this.gl.POINTS;
        this.isVisible = true;
    }

    addAttribute(name, data, length) {
        this.attributes[name] = new Lore.Attribute(data, length, name);
        this.attributes[name].createBuffer(this.gl, this.shader.program);

        return this;
    }

    updateAttribute(name, data) {
        if (data) {
            this.attributes[name].data = data;
        }

        this.attributes[name].update(this.gl);

        return this;
    }

    getAttribute(name) {
        return this.attributes[name];
    }

    removeAttribute(name) {
        delete this.attributes[name];

        return this;
    }

    setMode(drawMode) {
        switch (drawMode) {
        case Lore.DrawModes.points:
            this.drawMode = this.gl.POINTS;
            break;
        case Lore.DrawModes.lines:
            this.drawMode = this.gl.LINES;
            break;
        case Lore.DrawModes.lineStrip:
            this.drawMode = this.gl.LINE_STRIP;
            break;
        case Lore.DrawModes.lineLoop:
            this.drawMode = this.gl.LINE_LOOP;
            break;
        case Lore.DrawModes.triangles:
            this.drawMode = this.gl.TRIANGLES;
            break;
        case Lore.DrawModes.triangleStrip:
            this.drawMode = this.gl.TRIANGLE_STRIP;
            break;
        case Lore.DrawModes.triangleFan:
            this.drawMode = this.gl.TRIANGLE_FAN;
            break;
        }

        return this;
    }

    size() {
        // Is this ok? All attributes should have the same length ...
        if (Object.keys(this.attributes).length > 0) {
            return this.attributes[Object.keys(this.attributes)[0]].size;
        }

        return 0;
    }

    draw(renderer) {
        if (!this.isVisible) return;

        for (let prop in this.attributes)
            if (this.attributes[prop].stale) this.attributes[prop].update(this.gl);

        this.shader.use();

        // Update the modelView and projection matrices
        if (renderer.camera.isProjectionMatrixStale) {
            this.shader.uniforms.projectionMatrix.setValue(renderer.camera.getProjectionMatrix());
        }

        if (renderer.camera.isViewMatrixStale) {
            let modelViewMatrix = Lore.Matrix4f.multiply(renderer.camera.viewMatrix, this.modelMatrix);
            this.shader.uniforms.modelViewMatrix.setValue(modelViewMatrix.entries);
        }

        this.shader.updateUniforms();

        // How exactly does the binding work??
        // What will happen if I want to draw a second geometry?
        for (let prop in this.attributes) {
            this.attributes[prop].bind(this.gl);
        }

        this.gl.drawArrays(this.drawMode, 0, this.size());
    }
}