model/MyCylinder.js

/**
 * @class Represents a cylinder.
 */
class MyCylinder extends CGFobject {
    /**
     * Instantiates a new cylinder instance.
     * @param  {CGFscene} scene     - the scene in which the cylinder will be shown 
     * @param  {integer} slices     - number of slices around Y axis
     */
    constructor(scene, slices) {
        super(scene);
        this.slices = slices;
        this.initBuffers();
    }

    /**
     * Inits the vertices, indices, normals and texture coordinates.
     */
    initBuffers() {
        this.vertices = [];
        this.indices = [];
        this.normals = [];
        this.texCoords = [];

        this.minAngle = 2 * Math.PI / this.slices;
        this.initSideBuffers();
        this.initTopBottomBuffers();

        this.primitiveType = this.scene.gl.TRIANGLES;
        this.initGLBuffers();
    }

    /**
     * Inits the buffers of the rounded side.
     */
    initSideBuffers() {
        let currentAngle = 0;
        // makes the first edge on xx
        this.vertices.push(Math.cos(currentAngle), 0, -Math.sin(currentAngle),
            Math.cos(currentAngle), 1, -Math.sin(currentAngle));
        this.normals.push(Math.cos(currentAngle), 0, -Math.sin(currentAngle),
            Math.cos(currentAngle), 0, -Math.sin(currentAngle));
        this.texCoords.push(0, 1,
            0, 0);
        currentAngle += this.minAngle;

        for (var i = 0; i < this.slices; ++i) { // the first edge will be processed twice to apply textures
            // makes an edge
            this.vertices.push(Math.cos(currentAngle), 0, -Math.sin(currentAngle),
                Math.cos(currentAngle), 1, -Math.sin(currentAngle));

            // makes the face immediately before the edge
            this.indices.push(2 * i, 2 * i + 2, 2 * i + 3,
                2 * i + 3, 2 * i + 1, 2 * i);

            // makes the normals for both of the vertices of the current edge                    
            this.normals.push(Math.cos(currentAngle), 0, -Math.sin(currentAngle),
                Math.cos(currentAngle), 0, -Math.sin(currentAngle));

            // assigns texture coordinates for the vertices of the edges
            // is expected a rectangular horizontal image to fill the side of the cylinder 
            let texSPosition = (i + 1) / this.slices;
            this.texCoords.push(texSPosition, 1,
                texSPosition, 0);

            currentAngle += this.minAngle;
        }
    }

    /**
     * Inits the top and down faces.
     */
    initTopBottomBuffers() {
        let firstDown = 2 * (this.slices + 1);
        let firstUp = firstDown + 1;
        let currentAngle = 0;

        // replicates the first two edges, with another normals (facing up and down)
        let i = 0;
        for (; i < 2; ++i) {
            this.vertices.push(Math.cos(currentAngle), 0, -Math.sin(currentAngle),
                Math.cos(currentAngle), 1, -Math.sin(currentAngle));
            this.normals.push(0, -1, 0,
                0, 1, 0);
            currentAngle += this.minAngle;
        }

        // replicates the rest of the edges, with another normals (facing up and down)
        for (; i <= this.slices; ++i) {
            this.vertices.push(Math.cos(currentAngle), 0, -Math.sin(currentAngle),
                Math.cos(currentAngle), 1, -Math.sin(currentAngle));

            // makes the face immediately before the edge
            this.indices.push(firstDown + 2 * i, firstDown + 2 * i - 2, firstDown,
                firstUp, firstUp + 2 * i - 2, firstUp + 2 * i);


            // makes the facing up and down normals                  
            this.normals.push(0, -1, 0,
                0, 1, 0);

            currentAngle += this.minAngle;
        }
    }
}