diff options
author | luchen@google.com <luchen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-14 01:12:11 +0000 |
---|---|---|
committer | luchen@google.com <luchen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-14 01:12:11 +0000 |
commit | d89ea3ced6389f04190eaa5431d32f67bca0056d (patch) | |
tree | c66dcde04e8e73c5d00d7f6fba92d485101e2ecd /o3d/samples/o3d-webgl | |
parent | 7f7506f4f67c880b033d723dd1b7c29eac30dfac (diff) | |
download | chromium_src-d89ea3ced6389f04190eaa5431d32f67bca0056d.zip chromium_src-d89ea3ced6389f04190eaa5431d32f67bca0056d.tar.gz chromium_src-d89ea3ced6389f04190eaa5431d32f67bca0056d.tar.bz2 |
Implemented error texture support in client and ParamArray class. Fixed bug in effect.js that broke checkerboard texture if running using CG shaders.
TODO: Still a bug with render surface sets; will file issue and tackle problem in separate CL.
Review URL: http://codereview.chromium.org/2803007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52248 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/samples/o3d-webgl')
-rw-r--r-- | o3d/samples/o3d-webgl/base.js | 1 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl/client.js | 91 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl/effect.js | 114 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl/param.js | 41 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl/param_array.js | 184 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl/param_object.js | 1 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl/sampler.js | 37 |
7 files changed, 424 insertions, 45 deletions
diff --git a/o3d/samples/o3d-webgl/base.js b/o3d/samples/o3d-webgl/base.js index ba23128..ce46219 100644 --- a/o3d/samples/o3d-webgl/base.js +++ b/o3d/samples/o3d-webgl/base.js @@ -234,6 +234,7 @@ o3d.include('object_base'); o3d.include('named_object_base'); o3d.include('named_object'); o3d.include('param_object'); +o3d.include('param_array'); o3d.include('param'); o3d.include('event'); o3d.include('raw_data'); diff --git a/o3d/samples/o3d-webgl/client.js b/o3d/samples/o3d-webgl/client.js index 798ffe3..ebb28f4 100644 --- a/o3d/samples/o3d-webgl/client.js +++ b/o3d/samples/o3d-webgl/client.js @@ -652,6 +652,31 @@ o3d.Client.prototype.initWithCanvas = function(canvas) { height: canvas.height}; o3d.State.createDefaultState_(gl).push_(); + // Create the default error texture. + var defaultTexture = new o3d.Texture2D(); + defaultTexture.gl = this.gl; + defaultTexture.init_(8, 8, o3d.Texture.ARGB8, 1, false); + var r = [1, 0, 0, 1]; + var Y = [1, 1, 0, 1]; + var error = [r, r, r, r, r, r, r, r, + r, r, Y, Y, Y, Y, r, r, + r, Y, r, r, r, Y, Y, r, + r, Y, r, r, Y, r, Y, r, + r, Y, r, Y, r, r, Y, r, + r, Y, Y, r, r, r, Y, r, + r, r, Y, Y, Y, Y, r, r, + r, r, r, r, r, r, r, r]; + var pixels = []; + for (var i = 0; i < error.length; i++) { + for (var j = 0; j < 4; j++) { + pixels[i * 4 + j] = error[i][j]; + } + } + defaultTexture.set(0, pixels); + defaultTexture.name = 'DefaultTexture'; + this.fallback_error_texture_ = defaultTexture; + this.error_texture_ = defaultTexture; + return true; }; @@ -917,7 +942,7 @@ o3d.Client.prototype.clearEventCallback = */ o3d.Client.prototype.setErrorTexture = function(texture) { - o3d.notImplemented(); + this.error_texture_ = texture; }; @@ -978,14 +1003,32 @@ o3d.Client.prototype.setErrorCallback = function(error_callback) { // Other code expects to not see a null error callback. if (error_callback) { - this.error_callback = error_callback; + this.error_callback = this.wrapErrorCallback_(error_callback); } else { - this.error_callback = function(string) {}; + this.error_callback = function(string) { + this.last_error_ = string; + }; } }; /** + * Wraps a callback function, saving the error string so that the + * lastError variable can access it. + * + * @param {function} error_callback User-defined error callback. + * @return {function} Wrapped error callback. + * @private + */ +o3d.Client.prototype.wrapErrorCallback_ = function(error_callback) { + return function(string) { + this.last_error_ = string; + error_callback(string); + } +} + + +/** * Clears the Error callback * * NOTE: The client takes ownership of the ErrorCallback you @@ -1102,7 +1145,6 @@ o3d.Client.prototype.getState_ = function(name) { o3d.Client.prototype.renderer_init_status = 0; - /** * Gets / Sets the cursor's shape. * @@ -1112,12 +1154,49 @@ o3d.Client.prototype.cursor = null; /** + * The current error texture. + * + * @type {o3d.Texture} + * @private + */ +o3d.Client.prototype.error_texture_ = null; + + +/** + * The fallback error texture. Should only be initialized once per client and + * is read-only. + * + * @type {!o3d.Texture} + * @private + */ +o3d.Client.prototype.fallback_error_texture_ = null; + + +/** * The last error reported by the plugin. * * @type {string} + * @private */ o3d.Client.prototype.last_error_ = ''; +o3d.Client.prototype.__defineGetter__('lastError', + function() { + return this.last_error_; + } +); +/** + * Returns true if missing textures, samplers or ParamSamplers should be + * reported by calling the error callback. We assume that if the user + * explicitly sets the error texture to null, then they want such errors to + * trigger the error callback. + * + * @return {boolean} + * @private + */ +o3d.Client.prototype.reportErrors_ = function() { + return (this.error_texture_ == null); +} /** @@ -1146,7 +1225,7 @@ o3d.Client.prototype.objects = []; * Clears the error returned in lastError. */ o3d.Client.prototype.clearLastError = function () { - o3d.notImplemented(); + this.last_error_ = ''; }; @@ -1190,5 +1269,3 @@ o3d.Client.prototype.clientInfo = null; * @type {Element} */ o3d.Client.prototype.canvas = null; - - diff --git a/o3d/samples/o3d-webgl/effect.js b/o3d/samples/o3d-webgl/effect.js index 4d10b72..93932b0 100644 --- a/o3d/samples/o3d-webgl/effect.js +++ b/o3d/samples/o3d-webgl/effect.js @@ -62,9 +62,9 @@ o3d.EffectParameterInfo = /** * The semantic of the parameter. This is always in UPPERCASE. - * @type {o3d.Stream.Semantic} + * @type {string} */ - this.semantic = semantic || o3d.Stream.UNKNOWN_SEMANTIC; + this.semantic = semantic || ''; /** * If this is a standard parameter (SAS) this will be the name of the type @@ -266,6 +266,24 @@ o3d.Effect.prototype.loadFromFXString = /** + * Generates an array of indexed strings. For example, given 'arr' and a size + * of 10, generates 'arr[0]', 'arr[1]', 'arr[2]' up to 'arr[9]'. + * + * @param {string} base The name of the array. + * @param {number} size The number of elements in the array. + * @return {!Array.<string>} + * @private + */ +o3d.Effect.prototype.getParamArrayNames_ = function(base, size) { + var names = []; + for (var i = 0; i < size; i++) { + names[i] = base + '[' + i + ']'; + } + return names; +} + + +/** * Iterates through the active uniforms of the program and gets the * location of each one and stores them by name in the uniforms * object. @@ -278,8 +296,28 @@ o3d.Effect.prototype.getUniforms_ = this.program_, this.gl.ACTIVE_UNIFORMS); for (var i = 0; i < numUniforms; ++i) { var info = this.gl.getActiveUniform(this.program_, i); - this.uniforms_[info.name] = {info: info, - location: this.gl.getUniformLocation(this.program_, info.name)}; + if (info.name.indexOf('[') != -1) { + // This is an array param and we need to individually query each item in + // the array to get its location. + var baseName = info.name.substring(0, info.name.indexOf('[')); + var names = this.getParamArrayNames_(baseName, info.size); + var locations = []; + for (var j = 0; j < names.length; j++) { + locations[j] = this.gl.getUniformLocation(this.program_, names[j]); + } + this.uniforms_[baseName] = { + info: {name: baseName, size: info.size, type: info.type}, + kind: o3d.Effect.ARRAY, + locations: locations /* mind the s */ + }; + } else { + // Not an array param. + this.uniforms_[info.name] = { + info: info, + kind: o3d.Effect.ELEMENT, + location: this.gl.getUniformLocation(this.program_, info.name) + }; + } } }; @@ -334,6 +372,7 @@ o3d.Effect.getParamTypes_ = function(gl) { return o3d.Effect.paramTypes_; } + /** * A map linking names of certain attributes in the shader to the corresponding * semantic and semantic index. @@ -375,11 +414,21 @@ o3d.Effect.prototype.createUniformParameters = function(param_object) { var sasTypes = o3d.Param.sasTypes_; var paramTypes = o3d.Effect.getParamTypes_(this.gl); - for (var name in this.uniforms_) { - var info = this.uniforms_[name].info; + var uniformData = this.uniforms_[name]; if (!sasTypes[name]) { - param_object.createParam(info.name, paramTypes[info.type]); + switch (uniformData.kind) { + case o3d.Effect.ARRAY: + param_object.createParam(name, 'ParamParamArray'); + break; + case o3d.Effect.STRUCT: + o3d.notImplemented(); + break; + case o3d.Effect.ELEMENT: + default: + param_object.createParam(name, paramTypes[uniformData.info.type]); + break; + } } } }; @@ -422,19 +471,18 @@ o3d.Effect.prototype.createSASParameters = o3d.Effect.prototype.getParameterInfo = function() { var infoArray = []; var sasTypes = o3d.Param.sasTypes_; - var paramTypes = o3d.Effect.getParamTypes_(this.gl); var semanticMap = o3d.Effect.semanticMap_; + var paramTypes = o3d.Effect.getParamTypes_(this.gl); for (var name in this.uniforms_) { - var info = this.uniforms_[name].info; - var sasTypeName = sasTypes[name] || ''; - var className = paramTypes[info.type] || ''; - var numElements = 0; // TODO(petersont): Add array support. - var semantic = (semanticMap[name] && semanticMap[name].semantic) ? - semanticMap[name].semantic : o3d.Stream.UNKNOWN_SEMANTIC; - + var uniformData = this.uniforms_[name]; + var sasClassName = sasTypes[name] || ''; + var dataType = paramTypes[uniformData.info.type] || ''; + var numElements = (uniformData.kind == o3d.Effect.ARRAY) ? + uniformData.info.size : 0; // 0 if a non-array type. + var semantic = semanticMap[name] ? name : ''; infoArray.push(new o3d.EffectParameterInfo( - name, className, numElements, semantic, sasTypeName)); + name, dataType, numElements, semantic.toUpperCase(), sasClassName)); } return infoArray; @@ -461,7 +509,7 @@ o3d.Effect.prototype.getStreamInfo = function() { /** * Searches the objects in the given list for parameters to apply to the * uniforms defined on this effects program, and applies them, favoring - * the objects nearer the begining of the list. + * the objects nearer the beginning of the list. * * @param {!Array.<!o3d.ParamObject>} object_list The param objects to search. * @private @@ -482,7 +530,11 @@ o3d.Effect.prototype.searchForParams_ = function(object_list) { } var param = obj.getParam(name); if (param) { - param.applyToLocation(this.gl, uniformInfo.location); + if (uniformInfo.kind == o3d.Effect.ARRAY) { + param.applyToLocations(this.gl, uniformInfo.locations); + } else { + param.applyToLocation(this.gl, uniformInfo.location); + } filled_map[name] = true; } } @@ -491,10 +543,19 @@ o3d.Effect.prototype.searchForParams_ = function(object_list) { this.updateHelperConstants_(this.gl.displayInfo.width, this.gl.displayInfo.height); filled_map[o3d.Effect.HELPER_CONSTANT_NAME] = true; - for (var name in this.uniforms_) { if (!filled_map[name]) { - throw ('Uniform param not filled: "'+ name + '"'); + if (this.uniforms_[name].info.type == this.gl.SAMPLER_2D) { + if (this.gl.client.reportErrors_()) { + this.gl.client.error_callback("Missing ParamSampler"); + } + var defaultParamSampler = o3d.ParamSampler.defaultParamSampler_; + defaultParamSampler.gl = this.gl; + defaultParamSampler.applyToLocation(this.gl, + this.uniforms_[name].location); + } else { + throw ('Uniform param not filled: "'+ name + '"'); + } } } }; @@ -543,6 +604,17 @@ o3d.Effect.COLUMN_MAJOR = 1; /** + * UniformType, + * ELEMENT, the param is a single gl.* element + * ARRAY, the param is an array of same-typed elements + * STRUCT, not implemented + */ +o3d.Effect.ELEMENT = 0; +o3d.Effect.ARRAY = 1; +o3d.Effect.STRUCT = 2; + + +/** * The order in which matrix data is loaded to the GPU. * @type {o3d.Effect.MatrixLoadOrder} */ @@ -554,5 +626,3 @@ o3d.Effect.prototype.matrix_load_order_ = o3d.Effect.ROW_MAJOR; * @type {string} */ o3d.Effect.prototype.source_ = ''; - - diff --git a/o3d/samples/o3d-webgl/param.js b/o3d/samples/o3d-webgl/param.js index 59c0219..1aae87e 100644 --- a/o3d/samples/o3d-webgl/param.js +++ b/o3d/samples/o3d-webgl/param.js @@ -337,7 +337,7 @@ o3d.inherit('ParamMatrix4', 'Param'); */ o3d.ParamParamArray = function() { o3d.Param.call(this); - this.value = []; + this.value = null; }; o3d.inherit('ParamParamArray', 'Param'); @@ -834,6 +834,23 @@ o3d.ParamMatrix4.prototype.applyToLocation = function(gl, location) { }; /** + * Called to specify the values of a uniform array. + * @param {WebGLContext} gl The current context. + * @param {!Array.<!WebGLUniformLocation>} locationArray An array of locations + * to which to apply the values. + */ +o3d.ParamParamArray.prototype.applyToLocations = function(gl, locationArray) { + if (locationArray.length != this.value.length) { + gl.client.error_callback( + 'Invalid uniform param array: incorrect number of elements.'); + } + for (var i = 0; i < this.value.length; i++) { + // Cannot have a ParamArray of ParamArrays, so safe to call applyToLocation + this.value.getParam(i).applyToLocation(gl, locationArray[i]); + } +}; + +/** * A counter to ensure each texture sampler gets a unqiue id. * @private */ @@ -852,14 +869,30 @@ o3d.ParamSampler.prototype.applyToLocation = function(gl, location) { var value = null; var target = 0; + var sampler = null; if (this.value) { - this.value.bindAndSetParameters_(); - gl.uniform1i(location, i); - o3d.Param.texture_index_++; + sampler = this.value; + } else { + o3d.Sampler.defaultSampler_.gl = gl; + sampler = o3d.Sampler.defaultSampler_; + if (gl.client.reportErrors_()) { + gl.client.error_callback("Missing Sampler for ParamSampler " + this.name); + } } + + sampler.bindAndSetParameters_(); + gl.uniform1i(location, i); + o3d.Param.texture_index_++; }; +/** + * A default ParamSampler to be used if client does not assign one. + * + * @type {!o3d.ParamSampler} + * @private + */ +o3d.ParamSampler.defaultParamSampler_ = new o3d.ParamSampler(); /** * Object to compute all combinations of world/view/projection diff --git a/o3d/samples/o3d-webgl/param_array.js b/o3d/samples/o3d-webgl/param_array.js new file mode 100644 index 0000000..236c45a --- /dev/null +++ b/o3d/samples/o3d-webgl/param_array.js @@ -0,0 +1,184 @@ +/* + * Copyright 2010, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * A ParamArray is an object that holds an array of Params. + * @constructor + */ +o3d.ParamArray = function() { + o3d.NamedObject.call(this); + this.params_ = []; +}; +o3d.inherit('ParamArray', 'NamedObject'); + + +/** + * Creates a Param of the given type at the index requested. If a Param already + * exists at that index the new param will be replace it. If the index is past + * the end of the current array params of the requested type will be created to + * fill out the array to the requested index. + * + * @param {number} index Index at which to create new param. + * @param {string} param_type_name The type of Param to create. For a list of + * valid types see ParamObject.createParam + * @return {!o3d.ParamArray} The newly created Param or null if failure. + */ +o3d.ParamArray.prototype.createParam = function(index, param_type_name) { + param_type_name = o3d.filterTypeName_(param_type_name); + if (!o3d.global.o3d[param_type_name]) + throw ('Invalid param type name: ' + param_type_name); + if (index >= this.params_.length) { + this.resize(index + 1, param_type_name); + } else { + var param = new o3d.global.o3d[param_type_name]; + param.gl = this.gl; + param.owner_ = this; + this.params_[index] = param; + } + + return this.filterResult_(this.params_[index]); +}; + + +/** + * Gets a Param by index. + * + * @param {number} index Index of Param to get. + * @return {!o3d.Param} The Param at index, or null if out of range. + */ +o3d.ParamArray.prototype.getParam = function(index) { + var result = this.params_[index]; + return this.filterResult_(result); +}; + + +/** + * Removes a range of params. This shrinks the array and affects the indices of + * later occurring items. + * + * @param {number} start_index Index of first param to remove. + * @param {number} num_to_remove The number of params to remove starting at + * start_index. + */ +o3d.ParamArray.prototype.removeParams = function(start_index, num_to_remove) { + var paramsNew = []; + var j = 0; + for (var i = 0; i < this.params_.length; i++) { + if (i >= start_index && i < start_index + num_to_remove) { + // Skip these to remove them. + } else { + paramsNew[j] = this.params_[i]; + j++; + } + } + this.params_ = paramsNew; +}; + + +/** + * Resizes the array. + * + * @param {number} num_params The number of params to make the array. + * @param {string} param_type_name The type of Param to create if resizing + * requires params to be created. For a list of valid types see + * ParamObject.createParam. + */ +o3d.ParamArray.prototype.resize = function(num_params, param_type_name) { + param_type_name = o3d.filterTypeName_(param_type_name); + if (!o3d.global.o3d[param_type_name]) + throw ('Invalid param type name: ' + param_type_name); + + for (var i = this.params_.length; i < num_params; i++) { + var param = new o3d.global.o3d[param_type_name]; + param.gl = this.gl; + param.owner_ = this; + this.params_[i] = param; + } +}; + +/** + * The params stored in this ParamArray. + * + * @type {!Array.<!o3d.Param>} + * @private + */ +o3d.ParamArray.prototype.params_ = []; + +/** + * Gets all the param on this param object. + * + * Each access to this field gets the entire list, so it is best to get it + * just once. For example: + * + * var params = ParamArray.params; + * for (var i = 0; i < params.length; i++) { + * var param = params[i]; + * } + * + * Note that modifications to this array [e.g. push()] will not affect + * the underlying ParamArray, while modifications to the array's members + * <b>will</b> affect them. + * + * @type {!Array.<!o3d.Param>} + */ +o3d.ParamArray.prototype.__defineGetter__('params', + function() { + var params = []; + for (var i = 0; i < this.length; i++) { + params[i] = this.params_[i]; + } + return params; + } +); + + +/** + * Returns the number of parameters in this ParamArray. + * + * @type {number} + */ +o3d.ParamArray.prototype.__defineGetter__('length', + function() { + return this.params_.length; + } +); + + +/** + * Filters results, turning 'undefined' into 'null'. + * + * @param {*} result + * @private + */ +o3d.ParamArray.prototype.filterResult_= function(result) { + return (result ? result : null); +}; diff --git a/o3d/samples/o3d-webgl/param_object.js b/o3d/samples/o3d-webgl/param_object.js index 78ee725..61f3fac 100644 --- a/o3d/samples/o3d-webgl/param_object.js +++ b/o3d/samples/o3d-webgl/param_object.js @@ -109,6 +109,7 @@ o3d.ParamObject.prototype.createParam = var param = new o3d.global.o3d[param_type_name]; param.gl = this.gl; param.owner_ = this; + param.name = param_name; this.params_[param_name] = param; return this.filterResult_(this.params_[param_name]); }; diff --git a/o3d/samples/o3d-webgl/sampler.js b/o3d/samples/o3d-webgl/sampler.js index eb0a0e1..4e651a9 100644 --- a/o3d/samples/o3d-webgl/sampler.js +++ b/o3d/samples/o3d-webgl/sampler.js @@ -250,24 +250,37 @@ o3d.Sampler.prototype.convertMagFilter_ = function(o3d_filter) { /** + * A default Sampler that has no texture, thus uses the client's error texture. + * + * @type {!o3d.Sampler} + * @private + */ +o3d.Sampler.defaultSampler_ = new o3d.Sampler(); +o3d.Sampler.defaultSampler_.magFilter = o3d.Sampler.POINT; + +/** * Binds the texture for this sampler and sets texParameters according to the * states of the sampler. */ o3d.Sampler.prototype.bindAndSetParameters_ = function() { + var currentTexture = null; if (this.texture) { - var mip_filter = this.mipFilter; - if (this.texture.levels == 1) { - mip_filter = o3d.Sampler.NONE; - } - - this.texture.bindAndSetParameters_( - this.convertAddressMode_(this.addressModeU), - this.convertAddressMode_(this.addressModeV), - this.convertMinFilter_(this.minFilter, mip_filter), - this.convertMagFilter_(this.magFilter)); + currentTexture = this.texture; + } else if (!this.gl.client.reportErrors_()) { + currentTexture = this.gl.client.error_texture_; } else { - this.gl.client.error_callback("Sampler used with no texture set."); - return; + currentTexture = this.gl.client.fallback_error_texture_; + this.gl.client.error_callback("Missing texture for sampler " + this.name); + } + + var mip_filter = this.mipFilter; + if (currentTexture.levels == 1) { + mip_filter = o3d.Sampler.NONE; } + currentTexture.bindAndSetParameters_( + this.convertAddressMode_(this.addressModeU), + this.convertAddressMode_(this.addressModeV), + this.convertMinFilter_(this.minFilter, mip_filter), + this.convertMagFilter_(this.magFilter)); } |