FogRenderable.js

/*
 * File: FogRenderable.js
 *  
 * TODO
 */
/*jslint node: true, vars: true */
/*global gEngine: false, TextureRenderable: false */
/* find out more about jslint: http://www.jslint.com/help.html */

// Constructor and object definition
"use strict";  // Operate in Strict mode such that variables must be declared before used!
/**
 * 
 * @constructor
 * @param {Image} myTexture - Image to use as overlay for all unknown areas.
 * @param {Number} fogTranslusivness - Value between 0 and 255 for how translusive Fog state is rendered. 
 * @param {Number} unexploredTranslusivness - Value between 0 and 255 for how translusive Unknown/Unexplored state is rendered. 
 * @returns {FogRenderable}
 */
function FogRenderable(myTexture, fogTranslusivness, unexploredTranslusivness) {
    TextureRenderable.call(this, myTexture);
    this.numRows = null;
    this.multiplyer = 1;
    this.changed = false;
    this.textureID = null;
    this.fogTranslusivness = fogTranslusivness;
    this.unexploredTranslusivness = unexploredTranslusivness;
    this.oldUnexploredTranslusivness = unexploredTranslusivness;
    
}
gEngine.Core.inheritPrototype(FogRenderable, TextureRenderable);

/**
 * Draws the overlay for all unknown and foggy areas.
 * @param {Camera} aCamera - Camera for overlay to be drawn.
 */
FogRenderable.prototype.draw = function (aCamera) {
    // activate the texture
    // 
    //repurposed this so it no longer needs to use the ResourceMap
    //We aren't loading textures from a file, we do shit to a colorArray that starts black
    //->gEngine.Textures.activateTexture(this.mTexture); used to call this, 
    var gl = gEngine.Core.getGL();
    var texInfo = this.mTextureInfo;

    // Binds our texture reference to the current webGL texture functionality
    gl.bindTexture(gl.TEXTURE_2D, texInfo.mGLTexID);

    // To prevent texture wrappings
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

    // Handles how magnification and minimization filters will work.
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);

    // For pixel-graphics where you want the texture to look "sharp" do the following:
    // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    
    
    Renderable.prototype.draw.call(this, aCamera);
};

/**
 * Updates the Pixel Array of the texture to show the current Known area inside a Field of View regardless of previous state.
 * @param {type} x - X position of Viewer object in World Coordinates.
 * @param {type} y - Y position of Viewer object in World Coordinates.
 * @param {type} r - Radius of Field of View in World Coordinates.
 */
FogRenderable.prototype.updatePixelArray = function(x, y, r){
    if(this.mColorArray === null){
        // get this texture as a pixel array        
        this.mColorArray = gEngine.Textures.getColorArray(this.mTexture);   
    }
    
    var rry = [0,0];
    this._wcPositionToIndex(rry, [x,y], [0,-1], [1,0]);
    
    let posy = rry[0];
    let posx = rry[1];
    let height = r*this.mTextureInfo.mHeight/this.getXform().getHeight()*2;
    let width = r*this.mTextureInfo.mWidth/this.getXform().getWidth()*2;

    // Makes a circle Only loops through height covering pixel area
    for (let y = Math.max((posy - Math.floor(height/2)),0);
        y < (posy + Math.floor(height/2)) && y < this.mTextureInfo.mHeight; y++){
        // find the width of the circle at that height
        // takes into account the size ratio of the fog of war object
        let twox = Math.floor(Math.sqrt(Math.pow(width/2, 2)-Math.pow(posy-y,2)));//width/2;
        
        //Math.floor(Math.sqrt(Math.pow(width/2, 2)-Math.pow(posy-y,2)));
        // half the width, needs to be in pixels
        // loop through pixels within that width
        for (let x = Math.max((posx - twox),0);
            x < (posx + twox) && x < this.mTextureInfo.mWidth; x++){
            // find pixel position
            let pos = Math.floor(Math.max(y,0) * 4 
                    * this.mTextureInfo.mWidth
                    + Math.max(x,0) * 4);
            // draw the pixel
            //this.mColorArray[pos + 0] = 0;
            //this.mColorArray[pos + 1] = 0;
            //this.mColorArray[pos + 2] = 0;
            while((pos + 3)%4!== 3)
                pos++;
            this.mColorArray[pos + 3] = 0;
            
        }
    }
    
    this.changed = true;
};

/**
 * Sets the changes made in setAsFoggy and updatePixelArray into a single texture.
 */
FogRenderable.prototype.applyTexture = function(){
    if(this.changed){
        var gl = gEngine.Core.getGL();

        if (this.textureID === null){
            // Generate a texture reference to the webGL context
            this.textureID = gl.createTexture();
        }
        

        // bind the texture reference with the current texture functionality in the webGL
        gl.bindTexture(gl.TEXTURE_2D, this.textureID);

        // these are preset for now TODO fix this shit
        var w = this.mTextureInfo.mWidth;
        var h = this.mTextureInfo.mHeight;

        // Hijack and repurpose code from Engine_Textures.js _processLoadedImage
        // Load the texture into the texture data structure with descriptive info.
        // Parameters:
        //  1: Which "binding point" or target the texture is being loaded to.
        //  2: Level of detail. Used for mipmapping. 0 is base texture level.
        //  3: Internal format. The composition of each element. i.e. pixels.
        //  4: Format of texel data. Must match internal format.
        //  5: The data type of the texel data.
        //  6: Texture Data.
        gl.texImage2D(
            gl.TEXTURE_2D, // target
            0, // mip level
            gl.RGBA, // internal format -> gl.RGBA16UI
            w, h, // width and height
            0, // border
            gl.RGBA, //format -> gm.RGBA_INTEGER
            gl.UNSIGNED_BYTE, // type -> gl.UNSIGNED_SHORT
            this.mColorArray // texture data
        );
    //        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

        // Creates a mipmap for this texture.
        gl.generateMipmap(gl.TEXTURE_2D);
        // Tells WebGL that we are done manipulating data at the mGL.TEXTURE_2D target.
        gl.bindTexture(gl.TEXTURE_2D, null);
    //
        var textureName = "textureName";
        var texInfo = new TextureInfo("textureName", w, h, this.textureID);


        //---->this.setTexture(textureID);
        //this.mTexture = textureName;
        // these two instance variables are to cache texture information
        // for supporting per-pixel accurate collision
        this.mTextureInfo = texInfo;
        //this.mColorArray = null;
        // defined for subclass to override
        this.mTexWidth = this.mTextureInfo.mWidth;
        this.mTexHeight = this.mTextureInfo.mHeight;
        this.mTexLeftIndex = 0;
        this.mTexBottomIndex = 0;
        
        this.changed = false;
    }
};

/**
 * Sets all of the the Seen areas to Foggy.
 */
FogRenderable.prototype.setAsFoggy = function(){
    if(this.mColorArray === null){
        // get this texture as a pixel array        
        this.mColorArray = gEngine.Textures.getColorArray(this.mTexture);   
    }
    
    for (let y = 0; y < this.mTextureInfo.mHeight; y++){
        for (let x = 0; x < this.mTextureInfo.mWidth; x++){
            // find pixel position
            let pos = Math.floor(y * 4 * this.mTextureInfo.mWidth
                    + x * 4);
            // draw the pixel
            //this.mColorArray[pos + 0] = 0;
            //this.mColorArray[pos + 1] = 0;
            //this.mColorArray[pos + 2] = 0;
            while((pos + 3)%4!== 3)
                pos++;
            if (this.mColorArray[pos + 3] !== this.unexploredTranslusivness &&
                    this.mColorArray[pos + 3] !== this.oldUnexploredTranslusivness)
                this.mColorArray[pos + 3] = this.fogTranslusivness;
            else if (this.oldUnexploredTranslusivness !== 
                    this.unexploredTranslusivness && this.mColorArray[pos + 3] 
                    === this.oldUnexploredTranslusivness)
                this.mColorArray[pos + 3] = this.unexploredTranslusivness;
            
        }
    }
    this.oldUnexploredTranslusivness = this.unexploredTranslusivness;
    this.changed = true;
};

/**
 * Changes how dark the Fog state is rendered. A nubmer of 0 has the fog
 * completely transparent. 255 sets the fog to completely opaque.
 * @param {Number} fogTranslusivness - Number between 0 and 255.
 */
FogRenderable.prototype.setFogTranslusiveness = function(fogTranslusivness){
    this.fogTranslusivness = fogTranslusivness;
};

/**
 * Get the current value of Fog visability. 
 * @returns {Number} - Curent value of Fog visability
 */
FogRenderable.prototype.getFogTranslusiveness = function(){
    return this.fogTranslusivness;
};

/**
 * Changes how dark the Unknown/Unexplored state is rendered. A nubmer of 0 has the unknown
 * completely transparent. 255 sets the unknown to completely opaque.
 * @param {Number} unexploredTranslusivness - Number between 0 and 255.
 */
FogRenderable.prototype.setUnexploresTranslusiveness = function(unexploredTranslusivness){
    this.unexploredTranslusivness = unexploredTranslusivness;
};

/**
 * Get the current value of Unknown/Unexplored visability. 
 * @returns {Number} - Curent value of Unknown visability
 */
FogRenderable.prototype.getUnexploresTranslusiveness = function(){
    return this.unexploredTranslusivness;
};