summaryrefslogtreecommitdiffstats
path: root/o3d/samples
diff options
context:
space:
mode:
authorpetersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-09 23:48:08 +0000
committerpetersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-09 23:48:08 +0000
commit8fee64afe7ba2867255af94eae719f6f6b5ddc33 (patch)
tree5ab5f082a0fe5f27bdef1b056a024e0384937993 /o3d/samples
parent2c1ca1a516107745daa0a892875d61944dd791f6 (diff)
downloadchromium_src-8fee64afe7ba2867255af94eae719f6f6b5ddc33.zip
chromium_src-8fee64afe7ba2867255af94eae719f6f6b5ddc33.tar.gz
chromium_src-8fee64afe7ba2867255af94eae719f6f6b5ddc33.tar.bz2
Implemented picking, at last. The picking sample is already checked in, but to get the sample to draw the right thing required a bunch of ancillary bug fixes, also in this cl.
Review URL: http://codereview.chromium.org/2874008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52021 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/samples')
-rw-r--r--o3d/samples/o3d-webgl-samples/hellocube-wireframe.html51
-rw-r--r--o3d/samples/o3d-webgl/archive_request.js3
-rw-r--r--o3d/samples/o3d-webgl/base.js36
-rw-r--r--o3d/samples/o3d-webgl/bounding_box.js39
-rw-r--r--o3d/samples/o3d-webgl/buffer.js54
-rw-r--r--o3d/samples/o3d-webgl/client.js161
-rw-r--r--o3d/samples/o3d-webgl/draw_list.js13
-rw-r--r--o3d/samples/o3d-webgl/element.js11
-rw-r--r--o3d/samples/o3d-webgl/object_base.js7
-rw-r--r--o3d/samples/o3d-webgl/pack.js4
-rw-r--r--o3d/samples/o3d-webgl/param.js31
-rw-r--r--o3d/samples/o3d-webgl/param_object.js6
-rw-r--r--o3d/samples/o3d-webgl/primitive.js304
-rw-r--r--o3d/samples/o3d-webgl/shape.js28
-rw-r--r--o3d/samples/o3d-webgl/state.js531
-rw-r--r--o3d/samples/o3d-webgl/state_set.js15
-rw-r--r--o3d/samples/o3d-webgl/stream_bank.js36
-rw-r--r--o3d/samples/o3d-webgl/transform.js3
-rw-r--r--o3d/samples/o3djs/event.js2
19 files changed, 983 insertions, 352 deletions
diff --git a/o3d/samples/o3d-webgl-samples/hellocube-wireframe.html b/o3d/samples/o3d-webgl-samples/hellocube-wireframe.html
index 86eae19..48040b0 100644
--- a/o3d/samples/o3d-webgl-samples/hellocube-wireframe.html
+++ b/o3d/samples/o3d-webgl-samples/hellocube-wireframe.html
@@ -64,12 +64,13 @@ var g_clock = 0;
var g_timeMult = 1;
var g_cubeTransform;
var g_cubePrimitive;
+var g_material;
var g_finished = false; // for selenium testing
/**
* Changes the primitive type of the displayed cube. Some primitive types will
* only draw a partial cube.
- * @param {string} type the desired primitive type
+ * @param {string} type The desired primitive type.
*/
function changePrimitive(type) {
var indicesArray;
@@ -151,6 +152,30 @@ function changePrimitive(type) {
g_cubePrimitive.indexBuffer.set(indicesArray);
}
+
+/**
+ * Changes the fill mode on the state associated with the cube material.
+ * @param {string} type The desired fill mode.
+ */
+function changeFillMode(mode_string) {
+ var mode = o3d.State.SOLID;
+ switch (mode_string) {
+ case 'Point':
+ mode = o3d.State.POINT;
+ break;
+ case 'Wireframe':
+ mode = o3d.State.WIREFRAME;
+ break;
+ case 'Solid':
+ default:
+ mode = o3d.State.SOLID;
+ break;
+ }
+
+ g_material.state.getStateParam('FillMode').value = mode;
+}
+
+
/**
* Creates an O3D shape representing a cube. The shape consists of
* a single primitive with eight vertices.
@@ -277,10 +302,12 @@ function initStep2(clientElements) {
myEffect.loadPixelShaderFromString(pixelShaderString);
// Create a Material for the mesh.
- var myMaterial = g_pack.createObject('Material');
+ g_material = g_pack.createObject('Material');
// Set the material's drawList.
- myMaterial.drawList = viewInfo.performanceDrawList;
+ g_material.drawList = viewInfo.performanceDrawList;
+
+ g_material.state = g_pack.createObject('State');
// Turn off culling.
viewInfo.performanceDrawPassInfo.state.getStateParam('CullMode').value =
@@ -288,13 +315,14 @@ function initStep2(clientElements) {
// Apply our effect to this material. The effect tells the 3D hardware
// which shaders to use.
- myMaterial.effect = myEffect;
+ g_material.effect = myEffect;
// Create the Shape for the cube mesh and assign its material.
- var cubeShape = createCube(myMaterial);
+ var cubeShape = createCube(g_material);
// Render with line lists to begin with.
changePrimitive('LineList');
+ changeFillMode('Solid');
// Create a new transform and parent the Shape under it.
g_cubeTransform = g_pack.createObject('Transform');
@@ -332,7 +360,7 @@ This example shows how to display a cube in O3D using different primitive types.
<form name="default_form" action="#" method="get">
<p>
- Change type:
+ Primitive type:
<select onchange="changePrimitive(this.options[this.selectedIndex].value);">
<option value="PointList">PointList</option>
<option value="LineList" selected>LineList</option>
@@ -340,7 +368,16 @@ This example shows how to display a cube in O3D using different primitive types.
<option value="TriangleList">TriangleList</option>
<option value="TriangleStrip">TriangleStrip</option>
<option value="TriangleFan">TriangleFan</option>
- </select> (PointList may be hard to see.)
+ </select> (PointList might be hard to see.)
+ </p>
+
+ <p>
+ Fill mode:
+ <select onchange="changeFillMode(this.options[this.selectedIndex].value);">
+ <option value="Point">Point</option>
+ <option value="Wireframe">Wireframe</option>
+ <option value="Solid" selected>Solid</option>
+ </select>
</p>
</form>
diff --git a/o3d/samples/o3d-webgl/archive_request.js b/o3d/samples/o3d-webgl/archive_request.js
index aa45ec6..ca2c95e 100644
--- a/o3d/samples/o3d-webgl/archive_request.js
+++ b/o3d/samples/o3d-webgl/archive_request.js
@@ -254,8 +254,7 @@ o3d.ArchiveRequest.prototype.stringEndsWith_ = function(string, suffix) {
* if one is provided, calls onreadystatechange if this is the last of the
* requests.
* @param {o3d.RawData} rawData The current raw data object.
- * @param {function(!o3d.RawData): void} An optional callback to call passing
- * the current raw data as an argument.
+ * @param {Object} opt_exc An optional exception.
* @private
*/
o3d.ArchiveRequest.prototype.resolvePendingRequest_ =
diff --git a/o3d/samples/o3d-webgl/base.js b/o3d/samples/o3d-webgl/base.js
index d5e01cc..ba23128 100644
--- a/o3d/samples/o3d-webgl/base.js
+++ b/o3d/samples/o3d-webgl/base.js
@@ -176,7 +176,40 @@ o3d.removeFromArray = function(array, object) {
if (i >= 0) {
array.splice(i, 1);
}
-}
+};
+
+
+/**
+ * Determine whether a value is an array. Do not use instanceof because that
+ * will not work for V8 arrays (the browser thinks they are Objects).
+ * @param {*} value A value.
+ * @return {boolean} Whether the value is an array.
+ */
+o3d.isArray_ = function(value) {
+ var valueAsObject = /** @type {!Object} **/ (value);
+ return typeof(value) === 'object' && value !== null &&
+ 'length' in valueAsObject && 'splice' in valueAsObject;
+};
+
+
+/**
+ * Utility function to clone an object.
+ *
+ * @param {Object} object The object to clone.
+ * @return {Object} A clone of that object.
+ */
+o3d.clone = function(object) {
+ var result = o3d.isArray_(object) ? [] : {};
+ for (var name in object) {
+ var property = object[name];
+ if (typeof property == 'Object') {
+ result[name] = o3d.clone(property);
+ } else {
+ result[name] = property;
+ }
+ }
+ return result;
+};
/**
@@ -219,6 +252,7 @@ o3d.include('render_surface_set');
o3d.include('render_surface');
o3d.include('state');
o3d.include('draw_context');
+o3d.include('ray_intersection_info');
o3d.include('sampler');
o3d.include('transform');
o3d.include('pack');
diff --git a/o3d/samples/o3d-webgl/bounding_box.js b/o3d/samples/o3d-webgl/bounding_box.js
index ebd7d09..a3da9aa 100644
--- a/o3d/samples/o3d-webgl/bounding_box.js
+++ b/o3d/samples/o3d-webgl/bounding_box.js
@@ -39,14 +39,16 @@
o3d.BoundingBox =
function(opt_minExtent, opt_maxExtent) {
o3d.ParamObject.call(this);
- if (!opt_minExtent) {
- opt_minExtent = [0, 0, 0];
- }
- if (!opt_maxExtent) {
- opt_maxExtent = [0, 0, 0];
+ var minExtent = opt_minExtent || [0, 0, 0];
+ var maxExtent = opt_maxExtent || [0, 0, 0];
+
+ this.minExtent = [minExtent[0], minExtent[1], minExtent[2]];
+ this.maxExtent = [maxExtent[0], maxExtent[1], maxExtent[2]];
+
+ // If there were extents passed in, that validates the box.
+ if (opt_minExtent && opt_maxExtent) {
+ this.valid = true;
}
- this.minExtent = [opt_minExtent[0], opt_minExtent[1], opt_minExtent[2]];
- this.maxExtent = [opt_maxExtent[0], opt_maxExtent[1], opt_maxExtent[2]];
};
o3d.inherit('BoundingBox', 'ParamObject');
@@ -89,6 +91,7 @@ o3d.BoundingBox.fitBoxToPoints_ = function(points, opt_targetBox) {
target.maxExtent[index] = Math.max(target.maxExtent[index], point[index]);
}
}
+ target.valid = true;
return target;
};
@@ -170,7 +173,7 @@ o3d.BoundingBox.prototype.intersectRay =
end = [arguments[3], arguments[4], arguments[5]];
}
- var result = new RayIntersectionInfo;
+ var result = new o3d.RayIntersectionInfo;
if (this.valid) {
result.valid = true;
@@ -181,7 +184,7 @@ o3d.BoundingBox.prototype.intersectRay =
var kLeft = 1;
var kMiddle = 2;
- var dir = [end[0] - start[0], end[1] - start[1], end[2] - start[2]];
+ var direction = [end[0] - start[0], end[1] - start[1], end[2] - start[2]];
var coord = [0, 0, 0];
var inside = true;
@@ -200,13 +203,13 @@ o3d.BoundingBox.prototype.intersectRay =
// Find candidate planes; this loop can be avoided if rays cast all from
// the eye (assumes perpsective view).
for (var i = 0; i < kNumberOfDimensions; ++i) {
- if (start[i] < min_extent_[i]) {
+ if (start[i] < this.minExtent[i]) {
quadrant[i] = kLeft;
- candidate_plane[i] = min_extent_[i];
+ candidate_plane[i] = this.minExtent[i];
inside = false;
- } else if (start[i] > max_extent_[i]) {
+ } else if (start[i] > this.maxExtent[i]) {
quadrant[i] = kRight;
- candidate_plane[i] = max_extent_[i];
+ candidate_plane[i] = this.maxExtent[i];
inside = false;
} else {
quadrant[i] = kMiddle;
@@ -215,13 +218,13 @@ o3d.BoundingBox.prototype.intersectRay =
// Ray origin inside bounding box.
if (inside) {
- result.position = start;
+ result.position = start;
result.inside = true;
} else {
// Calculate T distances to candidate planes.
for (var i = 0; i < kNumberOfDimensions; ++i) {
- if (quadrant[i] != kMiddle && dir[i] != 0.0) {
- max_t[i] = (candidate_plane[i] - start[i]) / dir[i];
+ if (quadrant[i] != kMiddle && direction[i] != 0.0) {
+ max_t[i] = (candidate_plane[i] - start[i]) / direction[i];
} else {
max_t[i] = -1.0;
}
@@ -241,8 +244,8 @@ o3d.BoundingBox.prototype.intersectRay =
} else {
for (var i = 0; i < kNumberOfDimensions; ++i) {
if (which_plane != i) {
- coord[i] = start[i] + max_t[which_plane] * dir[i];
- if (coord[i] < min_extent_[i] || coord[i] > max_extent_[i]) {
+ coord[i] = start[i] + max_t[which_plane] * direction[i];
+ if (coord[i] < this.minExtent[i] || coord[i] > this.maxExtent[i]) {
result.intersected = false;
break;
}
diff --git a/o3d/samples/o3d-webgl/buffer.js b/o3d/samples/o3d-webgl/buffer.js
index d07583f..6cfeb50 100644
--- a/o3d/samples/o3d-webgl/buffer.js
+++ b/o3d/samples/o3d-webgl/buffer.js
@@ -37,17 +37,17 @@
* @constructor
*/
o3d.Buffer = function() {
- this.fields_ = [];
+ this.fields = [];
this.array_ = null;
};
o3d.inherit('Buffer', 'NamedObject');
/**
- * A private array to hold the fields.
+ * The fields currently set on the buffer.
* @type {!Array.<o3d.Field>}
*/
-o3d.Buffer.prototype.fields_ = [];
+o3d.Buffer.prototype.fields = [];
/**
@@ -75,6 +75,19 @@ o3d.Buffer.prototype.__defineGetter__('numElements',
);
/**
+ * Computes and stores the correct total components from the
+ * fields so far.
+ */
+o3d.Buffer.prototype.updateTotalComponents_ = function() {
+ var total = 0;
+ for (var i = 0; i < this.fields.length; ++i) {
+ this.fields[i].offset_ = total;
+ total += this.fields[i].numComponents;
+ }
+ this.totalComponents = total;
+};
+
+/**
* Allocates memory for the data to be stored in the buffer based on
* the types of fields set on the buffer.
*
@@ -83,13 +96,7 @@ o3d.Buffer.prototype.__defineGetter__('numElements',
*/
o3d.Buffer.prototype.allocateElements =
function(numElements) {
- var total = 0;
- for (var i = 0; i < this.fields_.length; ++i) {
- this.fields_[i].offset_ = total;
- total += this.fields_[i].numComponents;
- }
- this.totalComponents = total;
-
+ this.updateTotalComponents_();
this.resize(numElements * this.totalComponents);
};
@@ -126,8 +133,8 @@ o3d.Buffer.prototype.createField =
// Make copies of the existing field data.
if (alreadyAllocated) {
- for (var i = 0; i < this.fields_.length; i++) {
- savedData[i] = this.fields_[i].getAt(0, numElements);
+ for (var i = 0; i < this.fields.length; i++) {
+ savedData[i] = this.fields[i].getAt(0, numElements);
}
}
@@ -136,15 +143,16 @@ o3d.Buffer.prototype.createField =
f.buffer = this;
f.numComponents = numComponents;
f.size = numComponents * (fieldType=='UByteNField' ? 1 : 4);
- this.fields_.push(f);
+ this.fields.push(f);
+ this.updateTotalComponents_();
// Resize the buffer with the new field, and replace data.
if (alreadyAllocated) {
this.allocateElements(numElements);
- for (var i = 0; i < this.fields_.length; i++) {
+ for (var i = 0; i < this.fields.length; i++) {
var fieldData = savedData[i];
if (fieldData) {
- this.fields_[i].setAt(0, fieldData);
+ this.fields[i].setAt(0, fieldData);
}
}
}
@@ -164,18 +172,10 @@ o3d.Buffer.prototype.createField =
*/
o3d.Buffer.prototype.removeField =
function(field) {
- // TODO(luchen): Removing fields does not require a reshuffling, but may want
- // to do it anyways to save space.
- var i = 0;
- for (var j = 0; j < this.fields_.length; ++j) {
- if (this.fields_[i] == field)
- j++;
- this.fields_[j] = this.fields_[i];
- i++;
- }
- if (this.fields_.length > i) {
- this.fields_.pop();
- }
+ o3d.removeFromArray(this.fields, field);
+ // TODO(petersont): Have this function actually shuffle the buffer around to
+ // remove the field properly.
+ this.updateTotalComponents_();
};
diff --git a/o3d/samples/o3d-webgl/client.js b/o3d/samples/o3d-webgl/client.js
index 869320b..877bee4 100644
--- a/o3d/samples/o3d-webgl/client.js
+++ b/o3d/samples/o3d-webgl/client.js
@@ -225,6 +225,20 @@ o3d.Client = function() {
o3d.Renderer.installRenderInterval();
o3d.Renderer.clients_.push(this);
+
+ /**
+ * Stack of objects showing how the state has changed.
+ * @type {!Array.<!Object>}
+ * @private
+ */
+ this.stateMapStack_ = [];
+
+ /**
+ * An object containing an entry for each state variable that has changed.
+ * @type {Object}
+ * @private
+ */
+ this.stateVariableStacks_ = {};
};
o3d.inherit('Client', 'NamedObject');
@@ -426,6 +440,8 @@ o3d.Client.prototype.render = function() {
// Synthesize a render event.
var render_event = new o3d.RenderEvent;
+ this.clearStateStack_();
+
var now = (new Date()).getTime() * 0.001;
if(this.then_ == 0.0)
render_event.elapsedTime = 0.0;
@@ -611,7 +627,9 @@ o3d.Client.prototype.initWithCanvas = function(canvas) {
if (!canvas || !canvas.getContext) {
return false;
}
- try {gl = canvas.getContext("experimental-webgl", standard_attributes) } catch(e) { }
+ try {
+ gl = canvas.getContext("experimental-webgl", standard_attributes)
+ } catch(e) { }
if (!gl) {
try {
gl = canvas.getContext("moz-webgl")
@@ -632,6 +650,7 @@ o3d.Client.prototype.initWithCanvas = function(canvas) {
gl.client = this;
gl.displayInfo = {width: canvas.width,
height: canvas.height};
+ o3d.State.createDefaultState_(gl).push_();
return true;
};
@@ -762,78 +781,34 @@ o3d.Client.getEventInfo_ = function(event) {
/**
- * Returns the absolute position of an element for certain browsers.
+ * Returns the absolute position of an element.
* @param {!HTMLElement} element The element to get a position for.
* @return {!Object} An object containing x and y as the absolute position
* of the given element.
* @private
*/
o3d.Client.getAbsolutePosition_ = function(element) {
- var r = { x: element.offsetLeft, y: element.offsetTop };
- if (element.offsetParent) {
- var tmp = o3d.Client.getAbsolutePosition_(element.offsetParent);
- r.x += tmp.x;
- r.y += tmp.y;
+ var r = {x: 0, y: 0};
+ for (var e = element; e; e = e.offsetParent) {
+ r.x += e.offsetLeft;
+ r.y += e.offsetTop;
}
return r;
};
/**
- * Retrieve the coordinates of the given event relative to the center
- * of the widget.
+ * Compute the x and y of an event with respect to the element which received
+ * the event.
*
* @param {!Object} eventInfo As returned from
* o3d.Client.getEventInfo.
- * @param {HTMLElement} opt_reference A DOM element whose position we want
- * to transform the mouse coordinates to. If it is not passed in the
- * element in the eventInfo will be used.
* @return {!Object} An object containing keys 'x' and 'y'.
* @private
*/
-o3d.Client.getRelativeCoordinates_ = function(eventInfo, opt_reference) {
- var x, y;
+o3d.Client.getLocalXY_ = function(eventInfo) {
var event = eventInfo.event;
- var element = eventInfo.element;
- var reference = opt_reference || eventInfo.element;
- if (!window.opera && typeof event.offsetX != 'undefined') {
- // Use offset coordinates and find common offsetParent
- var pos = { x: event.offsetX, y: event.offsetY };
- // Send the coordinates upwards through the offsetParent chain.
- var e = element;
- while (e) {
- e.mouseX_ = pos.x;
- e.mouseY_ = pos.y;
- pos.x += e.offsetLeft;
- pos.y += e.offsetTop;
- e = e.offsetParent;
- }
- // Look for the coordinates starting from the reference element.
- var e = reference;
- var offset = { x: 0, y: 0 }
- while (e) {
- if (typeof e.mouseX_ != 'undefined') {
- x = e.mouseX_ - offset.x;
- y = e.mouseY_ - offset.y;
- break;
- }
- offset.x += e.offsetLeft;
- offset.y += e.offsetTop;
- e = e.offsetParent;
- }
- // Reset stored coordinates
- e = element;
- while (e) {
- e.mouseX_ = undefined;
- e.mouseY_ = undefined;
- e = e.offsetParent;
- }
- } else {
- // Use absolute coordinates
- var pos = o3d.Client.getAbsolutePosition_(reference);
- x = event.pageX - pos.x;
- y = event.pageY - pos.y;
- }
- return { x: x, y: y };
+ var p = o3d.Client.getAbsolutePosition_(eventInfo.element);
+ return {x: event.x - p.x, y: event.y - p.y};
};
@@ -849,7 +824,9 @@ o3d.Client.wrapEventCallback_ = function(handler, doCancelEvent) {
return function(event) {
event = o3d.Client.getEvent_(event);
var info = o3d.Client.getEventInfo_(event);
- var relativeCoords = o3d.Client.getRelativeCoordinates_(info);
+ var relativeCoords = o3d.Client.getLocalXY_(info);
+ // In a proper event, there are read only properties, so we clone it.
+ event = o3d.clone(event);
event.x = relativeCoords.x;
event.y = relativeCoords.y;
// Invert value to meet contract for deltaY. @see event.js.
@@ -1041,6 +1018,78 @@ o3d.Client.prototype.toDataURL =
/**
+ * Saves data needed to return state to current, then sets the state according
+ * to the given object.
+ * @private
+ */
+o3d.Client.prototype.clearStateStack_ = function() {
+ this.stateMapStack_ = [];
+ for (var name in this.stateVariableStacks_) {
+ var l = this.stateVariableStacks_[name];
+ // Recall there is a default value at the bottom of each of these stacks.
+ if (l.length != 1) {
+ this.stateVariableStacks_[name] = l.slice(0, 1);
+ }
+ }
+};
+
+
+/**
+ * Saves data needed to return state to current, then sets the state according
+ * to the given object.
+ * @param {Object} variable_map A map linking names to values.
+ * @private
+ */
+o3d.Client.prototype.pushState_ = function(variable_map) {
+ // Save the variable map itself in a stack.
+ this.stateMapStack_.push(variable_map);
+
+ // Save each of the state's variable's value in its own stack.
+ for (var name in variable_map) {
+ var value = variable_map[name];
+ if (this.stateVariableStacks_[name] == undefined) {
+ this.stateVariableStacks_[name] = [];
+ }
+ this.stateVariableStacks_[name].push(value);
+ }
+
+ // The value on the top of the stack in stateVariableStacks_
+ // is current at this point.
+ o3d.State.setVariables_(this.gl, variable_map);
+};
+
+
+/**
+ * Returns the state to the way it was before the current state
+ * @private
+ */
+o3d.Client.prototype.popState_ = function() {
+ var variable_map = this.stateMapStack_.pop();
+
+ for (var name in variable_map) {
+ var stack = this.stateVariableStacks_[name];
+ stack.pop();
+ variable_map[name] = stack.length ? stack[stack.length - 1] :
+ o3d.State.stateVariableInfos_[name]['defaultValue'];
+ }
+
+ o3d.State.setVariables_(this.gl, variable_map);
+};
+
+
+/**
+ * Gets the current value of the state variable with the give name.
+ * @param {string} name The name of the state variable in question.
+ * @private
+ */
+o3d.Client.prototype.getState_ = function(name) {
+ var stack = this.stateVariableStacks_[name];
+ return stack.length ? stack[stack.length - 1] :
+ o3d.State.stateVariableInfos_[name]['defaultValue'];
+};
+
+
+/**
* Returns the status of initializing the renderer so we can display the
* appropriate message. We require a certain minimum set of graphics
* capabilities. If the user's computer does not have his minimum
diff --git a/o3d/samples/o3d-webgl/draw_list.js b/o3d/samples/o3d-webgl/draw_list.js
index a9fa9ee..2c79e12 100644
--- a/o3d/samples/o3d-webgl/draw_list.js
+++ b/o3d/samples/o3d-webgl/draw_list.js
@@ -127,9 +127,8 @@ o3d.DrawList.prototype.render = function() {
var projection = drawElementInfo.projection;
var transform = drawElementInfo.transform;
var drawElement = drawElementInfo.drawElement;
- var element = drawElementInfo.drawElement.owner;
- var material = drawElementInfo.drawElement.material ||
- drawElementInfo.drawElement.owner.material;
+ var element = drawElement.owner;
+ var material = drawElement.material || element.material;
var effect = material.effect;
o3d.Param.SAS.setWorld(world);
@@ -148,7 +147,15 @@ o3d.DrawList.prototype.render = function() {
];
effect.searchForParams_(paramObjects);
+
+ var state_on = (material.state != undefined);
+ if (state_on) {
+ material.state.push_();
+ }
element.render();
+ if (state_on) {
+ material.state.pop_();
+ }
}
};
diff --git a/o3d/samples/o3d-webgl/element.js b/o3d/samples/o3d-webgl/element.js
index d190780..bf9c6c9 100644
--- a/o3d/samples/o3d-webgl/element.js
+++ b/o3d/samples/o3d-webgl/element.js
@@ -147,17 +147,18 @@ o3d.Element.prototype.__defineGetter__('owner',
* create more than one element for the same material.
*
* @param {!o3d.Pack} pack pack used to manage created DrawElement.
- * @param {!o3d.Material} material material to use for DrawElement. If you
- * pass null it will use the material on this Element. This allows you
- * to easily setup the default (just draw as is) by passing null or
- * setup a shadow pass by passing in a shadow material.
+ * @param {!o3d.Material} material material to use for DrawElement.
+ * Note: When a DrawElement with a material of null is rendered, the
+ * material on the corresponding Element will get used instead.
+ * This allows you to easily setup the default (just draw as is) by passing
+ * null or setup a shadow pass by passing in a shadow material.
* @return {!o3d.DrawElement} The created draw element.
*/
o3d.Element.prototype.createDrawElement =
function(pack, material) {
drawElement = pack.createObject('DrawElement');
drawElement.owner = this;
- drawElement.material = material || this.material;
+ drawElement.material = material;
this.drawElements.push(drawElement);
return drawElement;
};
diff --git a/o3d/samples/o3d-webgl/object_base.js b/o3d/samples/o3d-webgl/object_base.js
index a0f81b9..feb97bc 100644
--- a/o3d/samples/o3d-webgl/object_base.js
+++ b/o3d/samples/o3d-webgl/object_base.js
@@ -54,13 +54,14 @@ o3d.ObjectBase.prototype.superClass = null;
/**
* Traverses the current object's class and all its superclasses and
* determines if any of them are of the given name.
- * @param {string} className The name of a class.
+ * @param {string} class_type_name The name of a class.
* @return {boolean} Whether this is counts as a className.
*/
-o3d.ObjectBase.prototype.isAClassName = function(className) {
+o3d.ObjectBase.prototype.isAClassName = function(class_type_name) {
+ class_type_name = o3d.filterTypeName_(class_type_name);
var object = this;
while (object != undefined) {
- if (object.className == className) {
+ if (object.className == class_type_name) {
return true;
}
object = object.superClass && object.superClass.prototype;
diff --git a/o3d/samples/o3d-webgl/pack.js b/o3d/samples/o3d-webgl/pack.js
index 987fb9a..a168820 100644
--- a/o3d/samples/o3d-webgl/pack.js
+++ b/o3d/samples/o3d-webgl/pack.js
@@ -294,9 +294,7 @@ o3d.Pack.prototype.getObjects =
*/
o3d.Pack.prototype.getObjectsByClassName =
function(class_type_name) {
- if (class_type_name.substr(0, 4) == 'o3d.') {
- class_type_name = class_type_name.substr(4);
- }
+ class_type_name = o3d.filterTypeName_(class_type_name);
var found = [];
diff --git a/o3d/samples/o3d-webgl/param.js b/o3d/samples/o3d-webgl/param.js
index a7b3e6f..59c0219 100644
--- a/o3d/samples/o3d-webgl/param.js
+++ b/o3d/samples/o3d-webgl/param.js
@@ -767,8 +767,29 @@ o3d.WorldViewProjectionInverseTransposeParamMatrix4 = function() {
o3d.inherit('WorldViewProjectionInverseTransposeParamMatrix4',
'CompositionParamMatrix4');
+
+/**
+ * Called to specify the value of a uniform variable.
+ * @param {WebGLContext} gl The current context.
+ * @param {WebGLUniformLocation} location The location to which to apply.
+ */
+o3d.ParamInteger.prototype.applyToLocation = function(gl, location) {
+ gl.uniform1i(location, this.value);
+};
+
+/**
+ * Called to specify the value of a uniform variable.
+ * @param {WebGLContext} gl The current context.
+ * @param {WebGLUniformLocation} location The location to which to apply.
+ */
+o3d.ParamBoolean.prototype.applyToLocation = function(gl, location) {
+ gl.uniform1i(location, this.value);
+};
+
/**
* Called to specify the value of a uniform variable.
+ * @param {WebGLContext} gl The current context.
+ * @param {WebGLUniformLocation} location The location to which to apply.
*/
o3d.ParamFloat.prototype.applyToLocation = function(gl, location) {
gl.uniform1f(location, this.value);
@@ -776,6 +797,8 @@ o3d.ParamFloat.prototype.applyToLocation = function(gl, location) {
/**
* Called to specify the value of a uniform variable.
+ * @param {WebGLContext} gl The current context.
+ * @param {WebGLUniformLocation} location The location to which to apply.
*/
o3d.ParamFloat2.prototype.applyToLocation = function(gl, location) {
gl.uniform2fv(location, this.value);
@@ -783,6 +806,8 @@ o3d.ParamFloat2.prototype.applyToLocation = function(gl, location) {
/**
* Called to specify the value of a uniform variable.
+ * @param {WebGLContext} gl The current context.
+ * @param {WebGLUniformLocation} location The location to which to apply.
*/
o3d.ParamFloat3.prototype.applyToLocation = function(gl, location) {
gl.uniform3fv(location, this.value);
@@ -790,6 +815,8 @@ o3d.ParamFloat3.prototype.applyToLocation = function(gl, location) {
/**
* Called to specify the value of a uniform variable.
+ * @param {WebGLContext} gl The current context.
+ * @param {WebGLUniformLocation} location The location to which to apply.
*/
o3d.ParamFloat4.prototype.applyToLocation = function(gl, location) {
gl.uniform4fv(location, this.value);
@@ -797,6 +824,8 @@ o3d.ParamFloat4.prototype.applyToLocation = function(gl, location) {
/**
* Called to specify the value of a uniform variable.
+ * @param {WebGLContext} gl The current context.
+ * @param {WebGLUniformLocation} location The location to which to apply.
*/
o3d.ParamMatrix4.prototype.applyToLocation = function(gl, location) {
gl.uniformMatrix4fv(location,
@@ -812,6 +841,8 @@ o3d.Param.texture_index_ = 0;
/**
* Called to specify the value of a uniform variable.
+ * @param {WebGLContext} gl The current context.
+ * @param {WebGLUniformLocation} location The location to which to apply.
*/
o3d.ParamSampler.prototype.applyToLocation = function(gl, location) {
// When before the effect object assigns values to parameters,
diff --git a/o3d/samples/o3d-webgl/param_object.js b/o3d/samples/o3d-webgl/param_object.js
index 253acde..78ee725 100644
--- a/o3d/samples/o3d-webgl/param_object.js
+++ b/o3d/samples/o3d-webgl/param_object.js
@@ -197,8 +197,10 @@ o3d.ParamObject.prototype.params_ = {};
*/
o3d.ParamObject.prototype.copyParams =
function(source_param_object) {
- for (param in source_param_object.params_) {
- this.createParam(param.name, param.className);
+ for (name in source_param_object.params_) {
+ var param = source_param_object.params_[name];
+ this.createParam(name, param.className);
+ this.getParam(name).value = param.value;
}
};
diff --git a/o3d/samples/o3d-webgl/primitive.js b/o3d/samples/o3d-webgl/primitive.js
index 5e8bcf3..d9f7bde 100644
--- a/o3d/samples/o3d-webgl/primitive.js
+++ b/o3d/samples/o3d-webgl/primitive.js
@@ -40,6 +40,13 @@
*/
o3d.Primitive = function(opt_streamBank) {
o3d.Element.call(this);
+
+ /**
+ * The index buffer for the primitive. If null the primitive is non-indexed.
+ * @type {o3d.IndexBuffer}
+ */
+ this.indexBuffer = null;
+
/**
* The stream bank this primitive uses for vertices.
* @type {o3d.StreamBank}
@@ -78,11 +85,11 @@ o3d.Primitive = function(opt_streamBank) {
this.startIndex = 0;
/**
- * The index buffer for the primitive. If null the primitive is non-indexed.
+ * The index buffer for the wireframe version of the primitive.
* @type {o3d.IndexBuffer}
+ * @private
*/
- this.indexBuffer = null;
-
+ this.wireframeIndexBuffer_ = null;
};
o3d.inherit('Primitive', 'Element');
@@ -114,9 +121,9 @@ o3d.Primitive.prototype.render = function() {
var enabled_attribs = [];
for (var semantic = 0;
- semantic < streamBank.vertexStreams.length;
+ semantic < streamBank.vertex_streams_.length;
++semantic) {
- var streams = streamBank.vertexStreams[semantic];
+ var streams = streamBank.vertex_streams_[semantic];
if (streams && streams.length) {
for (var semantic_index = 0;
semantic_index < streams.length;
@@ -178,10 +185,43 @@ o3d.Primitive.prototype.render = function() {
break;
}
+ var use_wireframe_indices = false;
+
+ if (this.gl.fillMode_ == o3d.State.POINT) {
+ // If the fill mode is points, then we just replace the gl primitive type
+ // with POINTS and let the (possibly redundant) list of points draw.
+ glMode = this.gl.POINTS;
+ } else if (this.gl.fillMode_ == o3d.State.WIREFRAME) {
+ // If the fill mode is lines, and the primitive type is some kind of
+ // triangle, then we need to reorder indices to draw the right thing.
+
+ if (this.primitiveType == o3d.Primitive.TRIANGLELIST ||
+ this.primitiveType == o3d.Primitive.TRIANGLEFAN ||
+ this.primitiveType == o3d.Primitive.TRIANGLESTRIP) {
+ use_wireframe_indices = true;
+ glMode = this.gl.LINES;
+ this.computeWireframeIndices_();
+ }
+ }
+
+ if (use_wireframe_indices) {
+ indexBuffer = this.wireframeIndexBuffer_;
+
+ switch(this.primitiveType) {
+ default:
+ case o3d.Primitive.TRIANGLELIST:
+ glNumElements = this.numberPrimitives * 6;
+ break;
+ case o3d.Primitive.TRIANGLESTRIP:
+ case o3d.Primitive.TRIANGLEFAN:
+ glNumElements = (this.numberPrimitives == 0) ? 0 :
+ this.numberPrimitives * 4 + 2;
+ break;
+ }
+ }
+
if (!indexBuffer) {
- this.gl.drawArrays(glMode,
- 0,
- glNumElements);
+ this.gl.drawArrays(glMode, 0, glNumElements);
} else {
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, indexBuffer.gl_buffer_);
this.gl.drawElements(glMode,
@@ -195,6 +235,252 @@ o3d.Primitive.prototype.render = function() {
}
};
+
+/**
+ * Generates an index buffer for a wireframe outline of a triangle-based
+ * primitive.
+ * @private
+ */
+o3d.Primitive.prototype.computeWireframeIndices_ = function() {
+ this.wireframeIndexBuffer_ = new o3d.IndexBuffer;
+ this.wireframeIndexBuffer_.gl = this.gl;
+ var indices = this.indexBuffer.array_;
+
+ // The current index in wireframeIndices.
+ var j = 0;
+
+ switch (this.primitiveType) {
+ default:
+ case o3d.Primitive.TRIANGLELIST: {
+ this.wireframeIndexBuffer_.resize(2 * indices.length);
+ var wireframeIndices = this.wireframeIndexBuffer_.array_;
+ this.wireframeIndexBuffer_.lock();
+ // Iterate through triangles.
+ for (var i = 0; i < indices.length / 3; ++i) {
+ // Indices the vertices of the triangle a, b, c.
+ var a = indices[3 * i];
+ var b = indices[3 * i + 1];
+ var c = indices[3 * i + 2];
+ wireframeIndices[j++] = a;
+ wireframeIndices[j++] = b;
+ wireframeIndices[j++] = b;
+ wireframeIndices[j++] = c;
+ wireframeIndices[j++] = c;
+ wireframeIndices[j++] = a;
+ }
+ this.wireframeIndexBuffer_.unlock();
+ }
+ break;
+
+ case o3d.Primitive.TRIANGLEFAN: {
+ this.wireframeIndexBuffer_.resize(Math.max(0, 4 * indices.length - 4));
+ var wireframeIndices = this.wireframeIndexBuffer_.array_;
+ this.wireframeIndexBuffer_.lock();
+ // The first two points make a line.
+ var z;
+ if (indices.length > 1) {
+ z = indices[0];
+ wireframeIndices[j++] = z;
+ wireframeIndices[j++] = indices[1];
+ }
+ // Each additional point forms a new triangle by adding two lines.
+ for (var i = 2; i < indices.length; ++i) {
+ var a = indices[i];
+ wireframeIndices[j++] = z;
+ wireframeIndices[j++] = a;
+ wireframeIndices[j++] = a;
+ wireframeIndices[j++] = indices[i - 1];
+ }
+ this.wireframeIndexBuffer_.unlock();
+ }
+ break;
+
+ case o3d.Primitive.TRIANGLESTRIP: {
+ this.wireframeIndexBuffer_.resize(Math.max(0, 4 * indices.length - 4));
+ var wireframeIndices = this.wireframeIndexBuffer_.array_;
+ this.wireframeIndexBuffer_.lock();
+ // The frist two points make a line.
+ var a;
+ var b;
+ if (indices.length > 1) {
+ a = indices[0];
+ b = indices[1];
+ wireframeIndices[j++] = a;
+ wireframeIndices[j++] = b;
+ }
+ // Each additional point forms a new triangle by adding two lines.
+ for (var i = 2; i < indices.length; ++i) {
+ var c = indices[i];
+ wireframeIndices[j++] = b;
+ wireframeIndices[j++] = c;
+ wireframeIndices[j++] = c;
+ wireframeIndices[j++] = a;
+ a = b;
+ b = c;
+ }
+ this.wireframeIndexBuffer_.unlock();
+ }
+ break;
+ }
+};
+
+
+/**
+ * Computes the intersection of a ray in the coordinate system of
+ * the specified POSITION stream.
+ * @param {number} position_stream_index Index of POSITION stream.
+ * @param {o3d.Cull} cull which side of the triangles to ignore.
+ * @param {!o3d.math.Point3} start position of start of ray in local space.
+ * @param {!o3d.math.Point3} end position of end of ray. in local space.
+ * @return {!o3d.RayIntersectionInfo} RayIntersectionInfo class. If valid()
+ * is false then something was wrong, Check GetLastError(). If
+ * intersected() is true then the ray intersected a something. position()
+ * is the exact point of intersection.
+ */
+o3d.Primitive.prototype.intersectRay =
+ function(position_stream_index, cull, start, end) {
+ var result = new o3d.RayIntersectionInfo;
+ result.valid = true;
+
+ var streamBank = this.streamBank;
+ var indexBuffer = this.indexBuffer;
+ var stream =
+ this.streamBank.vertex_streams_[o3d.Stream.POSITION][position_stream_index];
+
+ var field = stream.field;
+ var buffer = field.buffer;
+ var numPoints = buffer.array_.length / buffer.totalComponents;
+ var elements = field.getAt(0, numPoints);
+
+ // The direction of the vector of the ray.
+ var x = end[0] - start[0];
+ var y = end[1] - start[1];
+ var z = end[2] - start[2];
+
+ // Find two vectors orthogonal to direction for use in quickly eliminating
+ // triangles which can't possibly intersect the ray.
+ var direction = [x, y, z];
+
+ // Pick a vector orthogonal to direction called u.
+ var ux = -y;
+ var uy = x;
+ var uz = 0;
+ if (x * x + y * y < z * z) {
+ ux = -z;
+ uy = 0;
+ uz = x;
+ }
+
+ // Cross product direction and u get a third orthogonal vector v.
+ var vx = y * uz - z * uy;
+ var vy = z * ux - x * uz;
+ var vz = x * uy - y * ux;
+
+ var udotstart = ux * start[0] + uy * start[1] + uz * start[2];
+ var vdotstart = vx * start[0] + vy * start[1] + vz * start[2];
+
+ // As we search for an intersection point, we keep track of how far out
+ // from the start the point with this variable.
+ var min_distance = 0;
+
+ // Iterate through the indices three at a time. Each triple of indices
+ // defines a triangle. For each triangle, we test for intersection with
+ // the ray. We need to find the closest one to start, so we have to
+ // check them all.
+ var a = indexBuffer.array_;
+ for (var i = 0; i < a.length / 3; ++i) {
+ // Indices of the triangle.
+ var t = 3 * i;
+ var indices = [a[t], a[t + 1], a[t + 2]];
+
+ // Check if the current triangle is too far to one side of the ray
+ // to intersect at all. (This is what the orthogonal vectors are for)
+ var u_sides = [false, false, false];
+ var v_sides = [false, false, false];
+ for (var j = 0; j < 3; ++j) {
+ var t = 3 * indices[j];
+ var r = elements.slice(t, t + 3);
+ u_sides[j] = ux * r[0] + uy * r[1] + uz * r[2] - udotstart > 0;
+ v_sides[j] = vx * r[0] + vy * r[1] + vz * r[2] - vdotstart > 0;
+ }
+
+ // All vertices of the triangle are on the same side of the start point,
+ // the ray cannot intersect, so we move on.
+ if (((u_sides[0] == u_sides[1]) && (u_sides[0] == u_sides[2])) ||
+ ((v_sides[0] == v_sides[1]) && (v_sides[0] == v_sides[2]))) {
+ continue;
+ }
+
+ // Compute a matrix that transforms the unit triangle
+ // (1, 0, 0)..(0, 1, 0)..(0, 0, 1) into the current triangle.
+ var t;
+ t = 3 * indices[0];
+ var m00 = elements[t] - start[0];
+ var m01 = elements[t + 1] - start[1];
+ var m02 = elements[t + 2] - start[2];
+ t = 3 * indices[1];
+ var m10 = elements[t] - start[0];
+ var m11 = elements[t + 1] - start[1];
+ var m12 = elements[t + 2] - start[2];
+ t = 3 * indices[2];
+ var m20 = elements[t] - start[0];
+ var m21 = elements[t + 1] - start[1];
+ var m22 = elements[t + 2] - start[2];
+
+ var t00 = m11 * m22 - m12 * m21;
+ var t10 = m01 * m22 - m02 * m21;
+ var t20 = m01 * m12 - m02 * m11;
+
+ // Compute the determinant of the matrix. The sign (+/-) tells us
+ // if it's culled.
+ var d = m00 * t00 - m10 * t10 + m20 * t20;
+
+ if ((cull == o3d.State.CULL_CW && d < 0) ||
+ (cull == o3d.State.CULL_CCW && d > 0)) {
+ continue;
+ }
+
+ // Transform the direction vector by the inverse of that matrix.
+ // If the end point is in the first octant, it's a hit.
+ var v0 = (t00 * x -
+ (m10 * m22 - m12 * m20) * y +
+ (m10 * m21 - m11 * m20) * z) / d;
+ var v1 = (-t10 * x +
+ (m00 * m22 - m02 * m20) * y -
+ (m00 * m21 - m01 * m20) * z) / d;
+ var v2 = (t20 * x -
+ (m00 * m12 - m02 * m10) * y +
+ (m00 * m11 - m01 * m10) * z) / d;
+
+ if (v0 > 0 && v1 > 0 && v2 > 0) {
+ // Rescale by the one-norm to find the intersection of the transformed.
+ // ray with the unit triangle.
+ var one_norm = v0 + v1 + v2;
+ v0 /= one_norm;
+ v1 /= one_norm;
+ v2 /= one_norm;
+ // Multiply m to get back to the original triangle.
+ var px = m00 * v0 + m10 * v1 + m20 * v2;
+ var py = m01 * v0 + m11 * v1 + m21 * v2;
+ var pz = m02 * v0 + m12 * v1 + m22 * v2;
+ // Compute the distance (actually distance squared) from the start point
+ // to the intersection.
+ var distance = px * px + py * py + pz * pz;
+ if (!result.intersected || distance < min_distance) {
+ min_distance = distance;
+ result.position[0] = px + start[0];
+ result.position[1] = py + start[1];
+ result.position[2] = pz + start[2];
+ result.primitiveIndex = i;
+ }
+ result.intersected = true;
+ }
+ }
+
+ return result;
+};
+
+
/**
* Computes the bounding box in same coordinate system as the specified
* POSITION stream.
@@ -206,7 +492,7 @@ o3d.Primitive.prototype.getBoundingBox =
var streamBank = this.streamBank;
var indexBuffer = this.indexBuffer;
var stream =
- this.streamBank.vertexStreams[o3d.Stream.POSITION][position_stream_index];
+ this.streamBank.getVertexStream(o3d.Stream.POSITION, position_stream_index);
var points = [];
var field = stream.field;
diff --git a/o3d/samples/o3d-webgl/shape.js b/o3d/samples/o3d-webgl/shape.js
index e58f1f4..a0ad16e 100644
--- a/o3d/samples/o3d-webgl/shape.js
+++ b/o3d/samples/o3d-webgl/shape.js
@@ -62,12 +62,30 @@ o3d.Shape.prototype.elements = [];
/**
+ * Finds a draw element in the given list of draw elements that uses the given
+ * material if such a draw element exists. Returns null otherwise.
+ * @param {Array.<!o3d.DrawElements>} drawElements An array of draw elements.
+ * @param {o3d.Material} material A material to search for.
+ * @private
+ */
+o3d.Shape.findDrawElementWithMaterial_ = function(drawElements, material) {
+ for (var j = 0; j < drawElements.length; ++j) {
+ if (drawElements[j].material == material) {
+ return drawElements[j];
+ }
+ }
+ return null;
+};
+
+
+/**
* Creates a DrawElement for each Element owned by this Shape.
- * If an Element already has a DrawElement that uses \a material a new
+ * If an Element already has a DrawElement that uses material a new
* DrawElement will not be created.
* @param {o3d.Pack} pack pack used to manage created DrawElements.
* @param {o3d.Material} material material to use for each DrawElement.
- * If you pass null it will use the material on the corresponding Element.
+ * Note: When a DrawElement with a material of null is rendered, the
+ * material on the corresponding Element will get used instead.
* This allows you to easily setup the default (just draw as is) by
* passing null or setup a shadow pass by passing in a shadow material.
*/
@@ -75,7 +93,11 @@ o3d.Shape.prototype.createDrawElements =
function(pack, material) {
var elements = this.elements;
for (var i = 0; i < elements.length; ++i) {
- elements[i].createDrawElement(pack, material);
+ var element = elements[i];
+ if (!o3d.Shape.findDrawElementWithMaterial_(element.drawElements,
+ material)) {
+ element.createDrawElement(pack, material);
+ }
}
};
diff --git a/o3d/samples/o3d-webgl/state.js b/o3d/samples/o3d-webgl/state.js
index 632e88a..a09ab36 100644
--- a/o3d/samples/o3d-webgl/state.js
+++ b/o3d/samples/o3d-webgl/state.js
@@ -37,93 +37,91 @@
o3d.State = function() {
o3d.ParamObject.call(this);
- // TODO(petersont): Only some of these have been implemented.
- var stateInfos = [
- {name: 'AlphaBlendEnable', paramType: 'ParamBoolean',
- defaultValue: false},
- {name: 'AlphaComparisonFunction', paramType: 'ParamInteger',
- defaultValue: o3d.State.CMP_ALWAYS},
- {name: 'AlphaReference', paramType: 'ParamFloat',
- defaultValue: 0},
- {name: 'AlphaTestEnable', paramType: 'ParamBoolean',
- defaultValue: false},
- {name: 'BlendAlphaEquation', paramType: 'ParamInteger',
- defaultValue: o3d.State.BLEND_ADD},
- {name: 'BlendEquation', paramType: 'ParamInteger',
- defaultValue: o3d.State.BLEND_ADD},
- {name: 'CCWStencilComparisonFunction', paramType: 'ParamInteger',
- defaultValue: o3d.State.CMP_ALWAYS},
- {name: 'CCWStencilFailOperation', paramType: 'ParamInteger',
- defaultValue: o3d.State.STENCIL_KEEP},
- {name: 'CCWStencilPassOperation', paramType: 'ParamInteger',
- defaultValue: o3d.State.STENCIL_KEEP},
- {name: 'CCWStencilZFailOperation', paramType: 'ParamInteger',
- defaultValue: o3d.State.STENCIL_KEEP},
- {name: 'ColorWriteEnable', paramType: 'ParamInteger',
- defaultValue: 15},
- {name: 'CullMode', paramType: 'ParamInteger',
- defaultValue: o3d.State.CULL_CW},
- {name: 'DestinationBlendAlphaFunction', paramType: 'ParamInteger',
- defaultValue: o3d.State.BLENDFUNC_ZERO},
- {name: 'DestinationBlendFunction', paramType: 'ParamInteger',
- defaultValue: o3d.State.BLENDFUNC_ZERO},
- {name: 'DitherEnable', paramType: 'ParamBoolean',
- defaultValue: false},
- {name: 'FillMode', paramType: 'ParamInteger',
- defaultValue: o3d.State.SOLID},
- {name: 'LineSmoothEnable', paramType: 'ParamBoolean',
- defaultValue: false},
- {name: 'PointSize', paramType: 'ParamFloat',
- defaultValue: 0},
- {name: 'PointSpriteEnable', paramType: 'ParamBoolean',
- defaultValue: false},
- {name: 'PolygonOffset1', paramType: 'ParamFloat',
- defaultValue: 0},
- {name: 'PolygonOffset2', paramType: 'ParamFloat',
- defaultValue: 0},
- {name: 'SeparateAlphaBlendEnable', paramType: 'ParamBoolean',
- defaultValue: false},
- {name: 'SourceBlendAlphaFunction', paramType: 'ParamInteger',
- defaultValue: o3d.State.BLENDFUNC_ONE},
- {name: 'SourceBlendFunction', paramType: 'ParamInteger',
- defaultValue: o3d.State.BLENDFUNC_ONE},
- {name: 'StencilComparisonFunction', paramType: 'ParamInteger',
- defaultValue: o3d.State.CMP_ALWAYS},
- {name: 'StencilEnable', paramType: 'ParamBoolean',
- defaultValue: false},
- {name: 'StencilFailOperation', paramType: 'ParamInteger',
- defaultValue: o3d.State.STENCIL_KEEP},
- {name: 'StencilMask', paramType: 'ParamInteger',
- defaultValue: 255},
- {name: 'StencilPassOperation', paramType: 'ParamInteger',
- defaultValue: o3d.State.STENCIL_KEEP},
- {name: 'StencilReference', paramType: 'ParamInteger',
- defaultValue: 0},
- {name: 'StencilWriteMask', paramType: 'ParamInteger',
- defaultValue: 255},
- {name: 'StencilZFailOperation', paramType: 'ParamInteger',
- defaultValue: o3d.State.STENCIL_KEEP},
- {name: 'TwoSidedStencilEnable', paramType: 'ParamBoolean',
- defaultValue: false},
- {name: 'ZComparisonFunction', paramType: 'ParamInteger',
- defaultValue: o3d.State.CMP_LESS},
- {name: 'ZEnable', paramType: 'ParamBoolean',
- defaultValue: true},
- {name: 'ZWriteEnable', paramType: 'ParamBoolean',
- defaultValue: true}
- ];
-
this.state_params_ = {};
- for (var i = 0; i < stateInfos.length; ++i) {
- var info = stateInfos[i];
- var param = new o3d.global.o3d[info.paramType];
- param.value = info.defaultValue;
- this.state_params_[info.name] = param;
- }
+ /**
+ * The names types and default values of all the state variables.
+ * @type {Object}
+ * @private
+ */
+ o3d.State.stateVariableInfos_ = o3d.State.stateVariableInfos_ || {
+ 'AlphaBlendEnable':
+ {paramType: 'ParamBoolean', defaultValue: false},
+ 'AlphaComparisonFunction':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.CMP_ALWAYS},
+ 'AlphaReference':
+ {paramType: 'ParamFloat', defaultValue: 0},
+ 'AlphaTestEnable':
+ {paramType: 'ParamBoolean', defaultValue: false},
+ 'BlendAlphaEquation':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.BLEND_ADD},
+ 'BlendEquation':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.BLEND_ADD},
+ 'CCWStencilComparisonFunction':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.CMP_ALWAYS},
+ 'CCWStencilFailOperation':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.STENCIL_KEEP},
+ 'CCWStencilPassOperation':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.STENCIL_KEEP},
+ 'CCWStencilZFailOperation':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.STENCIL_KEEP},
+ 'ColorWriteEnable':
+ {paramType: 'ParamInteger', defaultValue: 15},
+ 'CullMode':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.CULL_CW},
+ 'DestinationBlendAlphaFunction':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.BLENDFUNC_ZERO},
+ 'DestinationBlendFunction':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.BLENDFUNC_ZERO},
+ 'DitherEnable':
+ {paramType: 'ParamBoolean', defaultValue: false},
+ 'FillMode':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.SOLID},
+ 'LineSmoothEnable':
+ {paramType: 'ParamBoolean', defaultValue: false},
+ 'PointSize':
+ {paramType: 'ParamFloat', defaultValue: 0},
+ 'PointSpriteEnable':
+ {paramType: 'ParamBoolean', defaultValue: false},
+ 'PolygonOffset1':
+ {paramType: 'ParamFloat', defaultValue: 0},
+ 'PolygonOffset2':
+ {paramType: 'ParamFloat', defaultValue: 0},
+ 'SeparateAlphaBlendEnable':
+ {paramType: 'ParamBoolean', defaultValue: false},
+ 'SourceBlendAlphaFunction':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.BLENDFUNC_ONE},
+ 'SourceBlendFunction':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.BLENDFUNC_ONE},
+ 'StencilComparisonFunction':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.CMP_ALWAYS},
+ 'StencilEnable':
+ {paramType: 'ParamBoolean', defaultValue: false},
+ 'StencilFailOperation':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.STENCIL_KEEP},
+ 'StencilMask':
+ {paramType: 'ParamInteger', defaultValue: 255},
+ 'StencilPassOperation':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.STENCIL_KEEP},
+ 'StencilReference':
+ {paramType: 'ParamInteger', defaultValue: 0},
+ 'StencilWriteMask':
+ {paramType: 'ParamInteger', defaultValue: 255},
+ 'StencilZFailOperation':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.STENCIL_KEEP},
+ 'TwoSidedStencilEnable':
+ {paramType: 'ParamBoolean', defaultValue: false},
+ 'ZComparisonFunction':
+ {paramType: 'ParamInteger', defaultValue: o3d.State.CMP_LESS},
+ 'ZEnable':
+ {paramType: 'ParamBoolean', defaultValue: true},
+ 'ZWriteEnable':
+ {paramType: 'ParamBoolean', defaultValue: true}
+ };
};
o3d.inherit('State', 'ParamObject');
+
/**
* A private object containing the the state params by name.
*/
@@ -377,189 +375,326 @@ o3d.State.STENCIL_DECREMENT = 7;
*/
o3d.State.prototype.getStateParam =
function(state_name) {
+ if (!this.state_params_[state_name]) {
+ var info = o3d.State.stateVariableInfos_[state_name];
+ var param = new o3d.global.o3d[info.paramType];
+ param.value = info.defaultValue;
+ this.state_params_[state_name] = param;
+ }
return this.state_params_[state_name];
};
+/**
+ * Constructs a state to set all state variables to their default value.
+ * This is meant to be called once at client initialization.
+ * @param {WebGLContext} gl The context associated with the calling client.
+ * @return {o3d.State} A new state object.
+ * @private
+ */
+o3d.State.createDefaultState_ = function(gl) {
+ var state = new o3d.State;
+ state.gl = gl;
+ var infos = o3d.State.stateVariableInfos_;
+ for (name in infos) {
+ var info = infos[name];
+ state.getStateParam(name).value = info.defaultValue;
+ }
+ return state;
+};
-o3d.State.prototype.convertCmpFunc = function(cmp) {
+
+/**
+ * Converts a comparison function type constant from o3d to WebGL.
+ * @param {!WebGLContext} gl The current context.
+ * @param {number} blend_func The o3d constant.
+ * @return {number} The WebGL version of the constant.
+ * @private
+ */
+o3d.State.convertCmpFunc_ = function(gl, cmp) {
switch(cmp) {
case o3d.State.CMP_ALWAYS:
- return this.gl.ALWAYS;
+ return gl.ALWAYS;
case o3d.State.CMP_NEVER:
- return this.gl.NEVER;
+ return gl.NEVER;
case o3d.State.CMP_LESS:
- return this.gl.LESS;
+ return gl.LESS;
case o3d.State.CMP_GREATER:
- return this.gl.GREATER;
+ return gl.GREATER;
case o3d.State.CMP_LEQUAL:
- return this.gl.LEQUAL;
+ return gl.LEQUAL;
case o3d.State.CMP_GEQUAL:
- return this.gl.GEQUAL;
+ return gl.GEQUAL;
case o3d.State.CMP_EQUAL:
- return this.gl.EQUAL;
+ return gl.EQUAL;
case o3d.State.CMP_NOTEQUAL:
- return this.gl.NOTEQUAL;
+ return gl.NOTEQUAL;
default:
break;
}
- return this.gl.ALWAYS;
+ return gl.ALWAYS;
};
-o3d.State.prototype.convertFillMode = function(mode) {
- switch (mode) {
- case o3d.State.POINT:
- return this.gl.POINT;
- case o3d.State.WIREFRAME:
- return this.gl.LINE;
- case o3d.State.SOLID:
- return this.gl.FILL;
- default:
- break;
- }
- return this.gl.FILL;
-};
-
-
-o3d.State.prototype.convertBlendFunc = function(blend_func) {
+/**
+ * Converts a blend function type constant from o3d to WebGL.
+ * @param {!WebGLContext} gl The current context.
+ * @param {number} blend_func The o3d constant.
+ * @return {number} The WebGL version of the constant.
+ * @private
+ */
+o3d.State.convertBlendFunc_ = function(gl, blend_func) {
switch (blend_func) {
case o3d.State.BLENDFUNC_ZERO:
- return this.gl.ZERO;
+ return gl.ZERO;
case o3d.State.BLENDFUNC_ONE:
- return this.gl.ONE;
+ return gl.ONE;
case o3d.State.BLENDFUNC_SOURCE_COLOR:
- return this.gl.SRC_COLOR;
+ return gl.SRC_COLOR;
case o3d.State.BLENDFUNC_INVERSE_SOURCE_COLOR:
- return this.gl.ONE_MINUS_SRC_COLOR;
+ return gl.ONE_MINUS_SRC_COLOR;
case o3d.State.BLENDFUNC_SOURCE_ALPHA:
- return this.gl.SRC_ALPHA;
+ return gl.SRC_ALPHA;
case o3d.State.BLENDFUNC_INVERSE_SOURCE_ALPHA:
- return this.gl.ONE_MINUS_SRC_ALPHA;
+ return gl.ONE_MINUS_SRC_ALPHA;
case o3d.State.BLENDFUNC_DESTINATION_ALPHA:
- return this.gl.DST_ALPHA;
+ return gl.DST_ALPHA;
case o3d.State.BLENDFUNC_INVERSE_DESTINATION_ALPHA:
- return this.gl.ONE_MINUS_DST_ALPHA;
+ return gl.ONE_MINUS_DST_ALPHA;
case o3d.State.BLENDFUNC_DESTINATION_COLOR:
- return this.gl.DST_COLOR;
+ return gl.DST_COLOR;
case o3d.State.BLENDFUNC_INVERSE_DESTINATION_COLOR:
- return this.gl.ONE_MINUS_DST_COLOR;
+ return gl.ONE_MINUS_DST_COLOR;
case o3d.State.BLENDFUNC_SOURCE_ALPHA_SATUTRATE:
- return this.gl.SRC_ALPHA_SATURATE;
+ return gl.SRC_ALPHA_SATURATE;
default:
break;
}
- return this.gl.ONE;
+ return gl.ONE;
};
-o3d.State.prototype.convertBlendEquation = function(blend_equation) {
+/**
+ * Converts a stencil type constant from o3d to WebGL.
+ * @param {!WebGLContext} gl The current context.
+ * @param {number} stencil_func The o3d constant.
+ * @return {number} The WebGL version of the constant.
+ * @private
+ */
+o3d.State.convertBlendEquation_ = function(gl, blend_equation) {
switch (blend_equation) {
case o3d.State.BLEND_ADD:
- return this.gl.FUNC_ADD;
+ return gl.FUNC_ADD;
case o3d.State.BLEND_SUBTRACT:
- return this.gl.FUNC_SUBTRACT;
+ return gl.FUNC_SUBTRACT;
case o3d.State.BLEND_REVERSE_SUBTRACT:
- return this.gl.FUNC_REVERSE_SUBTRACT;
+ return gl.FUNC_REVERSE_SUBTRACT;
case o3d.State.BLEND_MIN:
- return this.gl.MIN;
+ return gl.MIN;
case o3d.State.BLEND_MAX:
- return this.gl.MAX;
+ return gl.MAX;
default:
break;
}
- return this.gl.FUNC_ADD;
+ return gl.FUNC_ADD;
};
-o3d.State.prototype.convertStencilOp = function(stencil_func) {
- switch (stencil_func) {
- case o3d.State.STENCIL_KEEP:
- return this.gl.KEEP;
- case o3d.State.STENCIL_ZERO:
- return this.gl.ZERO;
- case o3d.State.STENCIL_REPLACE:
- return this.gl.REPLACE;
- case o3d.State.STENCIL_INCREMENT_SATURATE:
- return this.gl.INCR;
- case o3d.State.STENCIL_DECREMENT_SATURATE:
- return this.gl.DECR;
- case o3d.State.STENCIL_INVERT:
- return this.gl.INVERT;
- case o3d.State.STENCIL_INCREMENT:
- return this.gl.INCR_WRAP;
- case o3d.State.STENCIL_DECREMENT:
- return this.gl.DECR_WRAP;
- default:
+/**
+ * Sets the internal state to the this state.
+ * @private
+ */
+o3d.State.prototype.push_ = function() {
+ this.gl.client.pushState_(this.getVariableMap_());
+};
+
+
+/**
+ * Recovers the internal state prior to this state gettings set.
+ * @private
+ */
+o3d.State.prototype.pop_ = function() {
+ this.gl.client.popState_();
+};
+
+
+/**
+ * Returns a new javascript object of name value pairs indicating
+ * what values to set each of the (changing) state variables.
+ * @return {!Object} The variable map.
+ * @private
+ */
+o3d.State.prototype.getVariableMap_ = function() {
+ var m = {};
+ var stateParams = this.state_params_;
+ for (var name in stateParams) {
+ m[name] = stateParams[name].value;
+ }
+ return m;
+};
+
+
+
+/**
+ * Helper function for setVariables_, looks for each of the given state
+ * variables' names in the given variable map. If any one of them is a key
+ * in the map, it fills in the rest in the target_map with the value either
+ * from the variable map or from the state if it isn't on the variable map.
+ * @param {Array.<!string>} names The names of the variables in question.
+ * @param {!Object} variable_map An object connecting names to values.
+ * @param {!Object} target_map An object to fill out with the variables from
+ * the given array of names.
+ * @return {boolean} True if any of the variable names in the given array were
+ * found in the variable_map
+ * @private
+ */
+o3d.State.relevantValues_ =
+ function(gl, names, variable_map, target_map) {
+ var found = false;
+ for (var i = 0; i < names.length; ++i) {
+ var name = names[i];
+ if (variable_map[name] !== undefined) {
+ found = true;
break;
+ }
+ }
+
+ if (found) {
+ for (var i = 0; i < names.length; ++i) {
+ var name = names[i];
+ var value = variable_map[name];
+ if (value === undefined) {
+ value = gl.client.getState_(name);
+ }
+ target_map[name] = value;
+ }
}
- return this.gl.KEEP;
+ return found;
};
-o3d.State.prototype.set = function() {
- var stateParams = this.state_params_;
+/**
+ * Sets the internal state according to the name value pairs in the given
+ * object.
+ * @param {WebGLContext} gl The gl context to use.
+ * @param {Object} variable_map A map linking state variable names to values.
+ * @private
+ */
+o3d.State.setVariables_ = function(gl, variable_map) {
+ // TODO(petersont): Only some of the state variables have been implemented.
+ // Others are unavailable in webgl.
+
+ // Remember, any state variable might be missing from variable_map. When the
+ // key is not present, the state should be left alone.
+
+ // Temporary map to hold name value pairs.
+ var v = {};
+
+ if (this.relevantValues_(gl, ['AlphaBlendEnable'], variable_map, v)) {
+ if (v['AlphaBlendEnable']) {
+ gl.enable(gl.BLEND);
+ } else {
+ gl.disable(gl.BLEND);
+ }
+ }
- if (stateParams['AlphaBlendEnable'].value) {
- this.gl.enable(this.gl.BLEND);
- } else {
- this.gl.disable(this.gl.BLEND);
+ if (this.relevantValues_(gl, ['SeparateAlphaBlendEnable',
+ 'SourceBlendFunction',
+ 'SourceBlendAlphaFunction',
+ 'DestinationBlendAlphaFunction',
+ 'BlendEquation',
+ 'BlendAlphaEquation'], variable_map, v)) {
+ if (v['SeparateAlphaBlendEnable']) {
+ gl.blendFuncSeparate(
+ o3d.State.convertBlendFunc_(gl, v['SourceBlendFunction']),
+ o3d.State.convertBlendFunc_(gl, v['DestinationBlendFunction']),
+ o3d.State.convertBlendFunc_(gl, v['SourceBlendAlphaFunction']),
+ o3d.State.convertBlendFunc_(gl, v['DestinationBlendAlphaFunction']));
+ gl.blendEquationSeparate(
+ o3d.State.convertBlendEquation_(gl, v['BlendEquation']),
+ o3d.State.convertBlendEquation_(gl, v['BlendAlphaEquation']));
+ }
}
- if (stateParams['SeparateAlphaBlendEnable'].value) {
- this.gl.blendFuncSeparate(
- this.convertBlendFunc(stateParams['SourceBlendFunction'].value),
- this.convertBlendFunc(stateParams['DestinationBlendFunction'].value),
- this.convertBlendFunc(stateParams['SourceBlendAlphaFunction'].value),
- this.convertBlendFunc(
- stateParams['DestinationBlendAlphaFunction'].value));
- this.gl.blendEquationSeparate(
- this.convertBlendEquation(stateParams['BlendEquation'].value),
- this.convertBlendEquation(stateParams['BlendAlphaEquation'].value));
- } else {
- this.gl.blendFunc(
- this.convertBlendFunc(stateParams['SourceBlendFunction'].value),
- this.convertBlendFunc(stateParams['DestinationBlendFunction'].value));
- this.gl.blendEquation(
- this.convertBlendEquation(stateParams['BlendEquation'].value));
+ if (this.relevantValues_(gl, ['SourceBlendFunction',
+ 'DestinationBlendFunction'], variable_map, v)) {
+ gl.blendFunc(
+ o3d.State.convertBlendFunc_(gl, v['SourceBlendFunction']),
+ o3d.State.convertBlendFunc_(gl, v['DestinationBlendFunction']));
}
- switch (stateParams['CullMode'].value) {
- case o3d.State.CULL_CW:
- this.gl.enable(this.gl.CULL_FACE);
- this.gl.cullFace(this.gl.BACK);
- break;
- case o3d.State.CULL_CCW:
- this.gl.enable(this.gl.CULL_FACE);
- this.gl.cullFace(this.gl.FRONT);
- break;
- default:
- this.gl.disable(this.gl.CULL_FACE);
- break;
+ if (this.relevantValues_(gl, ['BlendEquation'], variable_map, v)) {
+ gl.blendEquation(o3d.State.convertBlendEquation_(gl, v['BlendEquation']));
+ }
+
+ if (this.relevantValues_(gl, ['CullMode'], variable_map, v)) {
+ switch (v['CullMode']) {
+ case o3d.State.CULL_CW:
+ gl.enable(gl.CULL_FACE);
+ gl.cullFace(gl.BACK);
+ break;
+ case o3d.State.CULL_CCW:
+ gl.enable(gl.CULL_FACE);
+ gl.cullFace(gl.FRONT);
+ break;
+ default:
+ gl.disable(gl.CULL_FACE);
+ break;
+ }
+ }
+
+ if (this.relevantValues_(gl, ['DitherEnable'], variable_map, v)) {
+ if (v['DitherEnable']) {
+ gl.enable(gl.DITHER);
+ } else {
+ gl.disable(gl.DITHER);
+ }
+ }
+
+ if (this.relevantValues_(gl, ['ZEnable', 'ZComparisonFunction'],
+ variable_map, v)) {
+ if (v['ZEnable']) {
+ gl.enable(gl.DEPTH_TEST);
+ gl.depthFunc(
+ this.convertCmpFunc_(gl, v['ZComparisonFunction']));
+ } else {
+ gl.disable(gl.DEPTH_TEST);
+ }
}
- if (stateParams['DitherEnable'].value) {
- this.gl.enable(this.gl.DITHER);
- } else {
- this.gl.disable(this.gl.DITHER);
+ if (this.relevantValues_(gl, ['ZWriteEnable'], variable_map, v)) {
+ gl.depthMask(v['ZWriteEnable']);
}
- this.gl.depthMask(stateParams['ZWriteEnable'].value);
+ if (this.relevantValues_(gl, ['StencilEnable', 'StencilComparisonFunction'],
+ variable_map, v)) {
+ if (v['StencilEnable']) {
+ gl.enable(gl.STENCIL_TEST);
+ gl.stencilFunc(
+ this.convertCmpFunc_(gl, v['StencilComparisonFunction']));
+ } else {
+ gl.disable(gl.STENCIL_TEST);
+ }
+ }
- if (stateParams['ZEnable'].value) {
- this.gl.enable(this.gl.DEPTH_TEST);
- this.gl.depthFunc(
- this.convertCmpFunc(stateParams['ZComparisonFunction'].value));
- } else {
- this.gl.disable(this.gl.DEPTH_TEST);
+ if (this.relevantValues_(gl, ['PolygonOffset1',
+ 'PolygonOffset2'], variable_map, v)) {
+ var polygon_offset_factor = v['PolygonOffset1'] || 0;
+ var polygon_offset_bias = v['PolygonOffset2'] || 0;
+
+ if (polygon_offset_factor || polygon_offset_bias) {
+ gl.enable(gl.POLYGON_OFFSET_FILL);
+ gl.polygonOffset(polygon_offset_factor, polygon_offset_bias);
+ } else {
+ gl.disable(gl.POLYGON_OFFSET_FILL);
+ }
}
- if (stateParams['StencilEnable'].value) {
- this.gl.enable(this.gl.STENCIL_TEST);
- this.gl.stencilFunc(
- this.convertCmpFunc(stateParams['StencilComparisonFunction'].value));
- } else {
- this.gl.disable(this.gl.STENCIL_TEST);
+ if (this.relevantValues_(gl, ['FillMode'], variable_map, v)) {
+ // We emulate the behavior of the fill mode state in the primitive class.
+ gl.fillMode_ = v['FillMode'];
}
};
+
+
diff --git a/o3d/samples/o3d-webgl/state_set.js b/o3d/samples/o3d-webgl/state_set.js
index e421622..a2b8bdd 100644
--- a/o3d/samples/o3d-webgl/state_set.js
+++ b/o3d/samples/o3d-webgl/state_set.js
@@ -34,7 +34,7 @@
* A StateSet is a render node that sets render states of all of its
* children. You can make this a parent of a part of the render graph to set
* render states in a more global way.
- *
+ *
* @param {o3d.State} opt_state The State the defines what states to set.
* @constructor
*/
@@ -55,7 +55,16 @@ o3d.ParamObject.setUpO3DParam_(o3d.StateSet, 'state', 'ParamState');
* Sets the current state to the member state.
*/
o3d.StateSet.prototype.before = function() {
- if (this.state)
- this.state.set();
+ if (this.state) {
+ this.state.push_();
+ }
};
+/**
+ * Sets the current state to the member state.
+ */
+o3d.StateSet.prototype.after = function() {
+ if (this.state) {
+ this.state.pop_();
+ }
+};
diff --git a/o3d/samples/o3d-webgl/stream_bank.js b/o3d/samples/o3d-webgl/stream_bank.js
index 8329709..d0f1ca7 100644
--- a/o3d/samples/o3d-webgl/stream_bank.js
+++ b/o3d/samples/o3d-webgl/stream_bank.js
@@ -36,14 +36,32 @@
*/
o3d.StreamBank = function() {
o3d.NamedObject.call(this);
- this.vertexStreams = [];
+ this.vertex_streams_ = [];
};
o3d.inherit('StreamBank', 'NamedObject');
/**
* Array of streams.
*/
-o3d.StreamBank.prototype.vertexStreams = [];
+o3d.StreamBank.prototype.vertex_streams_ = [];
+
+o3d.StreamBank.prototype.__defineGetter__('vertexStreams',
+ function() {
+ result = [];
+ for (var i = 0; i < this.vertex_streams_.length; ++i) {
+ var stream_array = this.vertex_streams_[i];
+ if (stream_array && stream_array.length) {
+ for (var j = 0; j < stream_array.length; ++j) {
+ var stream = stream_array[j];
+ if (stream) {
+ result.push(stream);
+ }
+ }
+ }
+ }
+ return result;
+ }
+);
/**
@@ -58,10 +76,10 @@ o3d.StreamBank.prototype.vertexStreams = [];
*/
o3d.StreamBank.prototype.setVertexStream =
function(semantic, semantic_index, field, start_index) {
- if (this.vertexStreams[semantic] == undefined) {
- this.vertexStreams[semantic] = [];
+ if (this.vertex_streams_[semantic] == undefined) {
+ this.vertex_streams_[semantic] = [];
}
- this.vertexStreams[semantic][semantic_index] = new o3d.Stream(
+ this.vertex_streams_[semantic][semantic_index] = new o3d.Stream(
semantic, semantic_index, field, start_index);
};
@@ -76,10 +94,10 @@ o3d.StreamBank.prototype.setVertexStream =
*/
o3d.StreamBank.prototype.getVertexStream =
function(semantic, semantic_index) {
- if (this.vertexStreams[semantic] == undefined) {
+ if (this.vertex_streams_[semantic] == undefined) {
return;
}
- return this.vertexStreams[semantic][semantic_index];
+ return this.vertex_streams_[semantic][semantic_index];
};
@@ -92,10 +110,10 @@ o3d.StreamBank.prototype.getVertexStream =
*/
o3d.StreamBank.prototype.removeVertexStream =
function(semantic, semantic_index) {
- if (this.vertexStreams[semantic] == undefined) {
+ if (this.vertex_streams_[semantic] == undefined) {
return false;
}
- this.vertexStreams[semantic][semantic_index] = null;
+ this.vertex_streams_[semantic][semantic_index] = null;
return true;
};
diff --git a/o3d/samples/o3d-webgl/transform.js b/o3d/samples/o3d-webgl/transform.js
index 01231a1..640592c 100644
--- a/o3d/samples/o3d-webgl/transform.js
+++ b/o3d/samples/o3d-webgl/transform.js
@@ -257,7 +257,7 @@ o3d.Transform.prototype.addShape =
*/
o3d.Transform.prototype.removeShape =
function(shape) {
- o3d.notImplemented();
+ o3d.removeFromArray(this.shapes, shape);
};
@@ -601,7 +601,6 @@ o3d.Transform.prototype.rotateX =
};
-
/**
* Takes a 4-by-4 matrix and a vector with 3 entries,
* interprets the vector as a point, transforms that point by the matrix, and
diff --git a/o3d/samples/o3djs/event.js b/o3d/samples/o3djs/event.js
index f5de0d3..333aa0c 100644
--- a/o3d/samples/o3djs/event.js
+++ b/o3d/samples/o3djs/event.js
@@ -157,7 +157,7 @@ o3djs.event.getEventKeyChar = function(event) {
event = window.event;
}
var charCode = 0;
- if (event.keyIdentifier)
+ if (event.keyIdentifier)
charCode = o3djs.event.keyIdentifierToChar(event.keyIdentifier);
if (!charCode)
charCode = (window.event) ? window.event.keyCode : event.charCode;