var vgl = require('./vgl');
var inherit = require('../inherit');
var timestamp = require('../timestamp');
/**
* Create a new instance of class texture.
*
* @class
* @alias vgl.texture
* @returns {vgl.texture}
*/
vgl.texture = function () {
'use strict';
if (!(this instanceof vgl.texture)) {
return new vgl.texture();
}
vgl.materialAttribute.call(this, vgl.materialAttributeType.Texture);
this.m_width = 0;
this.m_height = 0;
this.m_depth = 0;
this.m_textureHandle = null;
this.m_textureUnit = 0;
this.m_pixelFormat = vgl.GL.RGBA;
this.m_pixelDataType = vgl.GL.UNSIGNED_BYTE;
this.m_internalFormat = vgl.GL.RGBA;
this.m_nearestPixel = false;
this.m_image = null;
var m_setupTimestamp = timestamp(),
m_that = this;
function activateTextureUnit(renderState) {
if (m_that.m_textureUnit >= 0 && m_that.m_textureUnit < 32) {
renderState.m_context.activeTexture(vgl.GL.TEXTURE0 + m_that.m_textureUnit);
} else {
throw '[error] Texture unit ' + m_that.m_textureUnit + ' is not supported';
}
}
/**
* Create texture, update parameters, and bind data.
*
* @param {vgl.renderState} renderState
*/
this.setup = function (renderState) {
// Activate the texture unit first
activateTextureUnit(renderState);
renderState.m_context.deleteTexture(this.m_textureHandle);
this.m_textureHandle = renderState.m_context.createTexture();
renderState.m_context.bindTexture(vgl.GL.TEXTURE_2D, this.m_textureHandle);
renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D,
vgl.GL.TEXTURE_MIN_FILTER,
this.m_nearestPixel ? vgl.GL.NEAREST : vgl.GL.LINEAR);
renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D,
vgl.GL.TEXTURE_MAG_FILTER,
this.m_nearestPixel ? vgl.GL.NEAREST : vgl.GL.LINEAR);
renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D,
vgl.GL.TEXTURE_WRAP_S, vgl.GL.CLAMP_TO_EDGE);
renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D,
vgl.GL.TEXTURE_WRAP_T, vgl.GL.CLAMP_TO_EDGE);
if (this.m_image !== null) {
renderState.m_context.pixelStorei(vgl.GL.UNPACK_ALIGNMENT, 1);
renderState.m_context.pixelStorei(vgl.GL.UNPACK_FLIP_Y_WEBGL, true);
this.updateDimensions();
this.computeInternalFormatUsingImage();
// console.log('m_internalFormat ' + this.m_internalFormat);
// console.log('m_pixelFormat ' + this.m_pixelFormat);
// console.log('m_pixelDataType ' + this.m_pixelDataType);
// FOR now support only 2D textures
renderState.m_context.texImage2D(vgl.GL.TEXTURE_2D, 0, this.m_internalFormat,
this.m_pixelFormat, this.m_pixelDataType, this.m_image);
} else {
renderState.m_context.texImage2D(vgl.GL.TEXTURE_2D, 0, this.m_internalFormat,
this.m_width, this.m_height, 0, this.m_pixelFormat, this.m_pixelDataType, null);
}
renderState.m_context.bindTexture(vgl.GL.TEXTURE_2D, null);
m_setupTimestamp.modified();
};
/**
* Create texture and if already created use it.
*
* @param {vgl.renderState} renderState
*/
this.bind = function (renderState) {
// TODO Call setup via material setup
if (this.getMTime() > m_setupTimestamp.getMTime()) {
this.setup(renderState);
}
activateTextureUnit(renderState);
renderState.m_context.bindTexture(vgl.GL.TEXTURE_2D, this.m_textureHandle);
};
/**
* Turn off the use of this texture.
*
* @param {vgl.renderState} renderState
*/
this.undoBind = function (renderState) {
renderState.m_context.bindTexture(vgl.GL.TEXTURE_2D, null);
};
/**
* Get image used by the texture.
*
* @returns {vgl.image}
*/
this.image = function () {
return this.m_image;
};
/**
* Set image for the texture.
*
* @param {vgl.image} image
* @returns {boolean}
*/
this.setImage = function (image) {
if (image !== null) {
this.m_image = image;
this.updateDimensions();
this.modified();
return true;
}
return false;
};
/**
* Get nearest pixel flag for the texture.
*
* @returns {boolean}
*/
this.nearestPixel = function () {
return this.m_nearestPixel;
};
/**
* Set nearest pixel flag for the texture.
*
* @param {boolean} nearest pixel flag
* @returns {boolean}
*/
this.setNearestPixel = function (nearest) {
nearest = nearest ? true : false;
if (nearest !== this.m_nearestPixel) {
this.m_nearestPixel = nearest;
this.modified();
return true;
}
return false;
};
/**
* Get texture unit of the texture.
*
* @returns {number}
*/
this.textureUnit = function () {
return this.m_textureUnit;
};
/**
* Set texture unit of the texture. Default is 0.
*
* @param {number} unit
* @returns {boolean}
*/
this.setTextureUnit = function (unit) {
if (this.m_textureUnit === unit) {
return false;
}
this.m_textureUnit = unit;
this.modified();
return true;
};
/**
* Compute internal format of the texture.
*/
this.computeInternalFormatUsingImage = function () {
// Currently image does not define internal format
// and hence it's pixel format is the only way to query
// information on how color has been stored.
// switch (this.m_image.pixelFormat()) {
// case vgl.GL.RGB:
// this.m_internalFormat = vgl.GL.RGB;
// break;
// case vgl.GL.RGBA:
// this.m_internalFormat = vgl.GL.RGBA;
// break;
// case vgl.GL.Luminance:
// this.m_internalFormat = vgl.GL.Luminance;
// break;
// case vgl.GL.LuminanceAlpha:
// this.m_internalFormat = vgl.GL.LuminanceAlpha;
// break;
// // Do nothing when image pixel format is none or undefined.
// default:
// break;
// };
// TODO Fix this
this.m_internalFormat = vgl.GL.RGBA;
this.m_pixelFormat = vgl.GL.RGBA;
this.m_pixelDataType = vgl.GL.UNSIGNED_BYTE;
};
/**
* Update texture dimensions.
*/
this.updateDimensions = function () {
if (this.m_image !== null) {
this.m_width = this.m_image.width;
this.m_height = this.m_image.height;
this.m_depth = 0; // Only 2D images are supported now
}
};
/**
* Return the texture handle.
*
* @returns {number}
*/
this.textureHandle = function () {
return this.m_textureHandle;
};
return this;
};
inherit(vgl.texture, vgl.materialAttribute);
/**
* Create a new instance of class lookupTable.
*
* @class
* @alias vgl.lookupTable
* @returns {vgl.lookupTable}
*/
vgl.lookupTable = function () {
'use strict';
if (!(this instanceof vgl.lookupTable)) {
return new vgl.lookupTable();
}
vgl.texture.call(this);
var m_setupTimestamp = timestamp();
this.m_colorTable = // paraview bwr colortable
[0.07514311, 0.468049805, 1, 1,
0.247872569, 0.498782363, 1, 1,
0.339526309, 0.528909511, 1, 1,
0.409505078, 0.558608486, 1, 1,
0.468487184, 0.588057293, 1, 1,
0.520796675, 0.617435078, 1, 1,
0.568724526, 0.646924167, 1, 1,
0.613686735, 0.676713218, 1, 1,
0.656658579, 0.707001303, 1, 1,
0.698372844, 0.738002964, 1, 1,
0.739424025, 0.769954435, 1, 1,
0.780330104, 0.803121429, 1, 1,
0.821573924, 0.837809045, 1, 1,
0.863634967, 0.874374691, 1, 1,
0.907017747, 0.913245283, 1, 1,
0.936129275, 0.938743558, 0.983038586, 1,
0.943467973, 0.943498599, 0.943398095, 1,
0.990146732, 0.928791426, 0.917447482, 1,
1, 0.88332677, 0.861943246, 1,
1, 0.833985467, 0.803839606, 1,
1, 0.788626485, 0.750707739, 1,
1, 0.746206642, 0.701389973, 1,
1, 0.70590052, 0.654994046, 1,
1, 0.667019783, 0.610806959, 1,
1, 0.6289553, 0.568237474, 1,
1, 0.591130233, 0.526775617, 1,
1, 0.552955184, 0.485962266, 1,
1, 0.513776083, 0.445364274, 1,
1, 0.472800903, 0.404551679, 1,
1, 0.428977855, 0.363073592, 1,
1, 0.380759558, 0.320428137, 1,
0.961891484, 0.313155629, 0.265499262, 1,
0.916482116, 0.236630659, 0.209939162, 1].map(
function (x) { return x * 255; });
/**
* Create lookup table, initialize parameters, and bind data to it.
*
* @param {vgl.renderState} renderState
*/
this.setup = function (renderState) {
if (this.textureUnit() === 0) {
renderState.m_context.activeTexture(vgl.GL.TEXTURE0);
} else if (this.textureUnit() === 1) {
renderState.m_context.activeTexture(vgl.GL.TEXTURE1);
}
renderState.m_context.deleteTexture(this.m_textureHandle);
this.m_textureHandle = renderState.m_context.createTexture();
renderState.m_context.bindTexture(vgl.GL.TEXTURE_2D, this.m_textureHandle);
renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D,
vgl.GL.TEXTURE_MIN_FILTER, vgl.GL.LINEAR);
renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D,
vgl.GL.TEXTURE_MAG_FILTER, vgl.GL.LINEAR);
renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D,
vgl.GL.TEXTURE_WRAP_S, vgl.GL.CLAMP_TO_EDGE);
renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D,
vgl.GL.TEXTURE_WRAP_T, vgl.GL.CLAMP_TO_EDGE);
renderState.m_context.pixelStorei(vgl.GL.UNPACK_ALIGNMENT, 1);
this.m_width = this.m_colorTable.length / 4;
this.m_height = 1;
this.m_depth = 0;
renderState.m_context.texImage2D(vgl.GL.TEXTURE_2D,
0, vgl.GL.RGBA, this.m_width, this.m_height, this.m_depth,
vgl.GL.RGBA, vgl.GL.UNSIGNED_BYTE, new Uint8Array(this.m_colorTable));
renderState.m_context.bindTexture(vgl.GL.TEXTURE_2D, null);
m_setupTimestamp.modified();
};
/**
* Get color table used by the lookup table.
*
* @returns {number[]}
*/
this.colorTable = function () {
return this.m_colorTable;
};
/**
* Set color table used by the lookup table.
*
* @param {number[]} colors
* @returns {boolean}
*/
this.setColorTable = function (colors) {
if (this.m_colorTable === colors) {
return false;
}
this.m_colorTable = colors;
this.modified();
return true;
};
return this;
};
inherit(vgl.lookupTable, vgl.texture);