diff options
author | luchen@chromium.org <luchen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-13 23:37:58 +0000 |
---|---|---|
committer | luchen@chromium.org <luchen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-13 23:37:58 +0000 |
commit | 5b75999a092d6071fcaa09b0b4e522e3d7feea97 (patch) | |
tree | 1d45989a26838022e80ab217aa75a9c3024bfe9d /o3d | |
parent | 10836fe9a967047565088b0dc1414185e89dd70a (diff) | |
download | chromium_src-5b75999a092d6071fcaa09b0b4e522e3d7feea97.zip chromium_src-5b75999a092d6071fcaa09b0b4e522e3d7feea97.tar.gz chromium_src-5b75999a092d6071fcaa09b0b4e522e3d7feea97.tar.bz2 |
o3d-webgl: Adding preliminary files for 'bubble blaster' demo.
Review URL: http://codereview.chromium.org/3123017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56110 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
13 files changed, 1735 insertions, 0 deletions
diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/extra/shadow-map.js b/o3d/samples/o3d-webgl-samples/bubbles/blaster/extra/shadow-map.js new file mode 100644 index 0000000..35f0161 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/extra/shadow-map.js @@ -0,0 +1,213 @@ +/* + * 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. + */ + +/** + * Represents the surface area that has been hit on a texture map by creating + * a same-sized canvas composed of uniquely colored pixels. + * + * The original intention was to render the target from a single bubble's point + * of view using this as the texture map in place of the original texture. With + * stenciling, you render only the pixels that the bubble occludes and thus + * intersects with when it hits the block. Since each pixel in the rendered + * buffer has a unique color, it can be reverse mapped to the corresponding + * texel position and marked off as "hit". + * + * @param {number} width The width of the texture to track hits for. + * @param {number} height The height of the texture to track hits for. + * @param {o3d.Pack} pack A pack to create objects with. + * @constructor + */ +var ShadowMap = function(width, height, pack) { + this.width = width; + this.height = height; + this.canvas = document.createElement("canvas"); + this.canvas.width = width; + this.canvas.height = height; + + this.cached_percent_ = 0; + this.dirty_cache_ = true; + + this.texture = pack.createTexture2D(width, height, + g.o3d.Texture.XRGB8, + 1, + false); + + ShadowMap.init(this.canvas); + this.redrawTexture(); +}; + +/** + * Updates the texture object to reflect the most recent values in the canvas. + */ +ShadowMap.prototype.redrawTexture = function() { + this.texture.setFromCanvas_(this.canvas, true, false, false); +}; + +/** + * Calculates the percent of the shadow map covered of the entire map. + * @private + */ +ShadowMap.prototype.calculatePercent_ = function() { + var context = this.canvas.getContext("2d"); + var imageData = context.getImageData(0, 0, this.width, this.height); + var count = 0; + for (var i = 0; i < this.width * this.height; i++) { + if (imageData.data[i * 4 + 3] != ShadowMap.ALPHA_START) { + count++; + } + } + this.cached_percent_ = + Math.round(count * 100.0 / (this.width * this.height)); +}; + + +/** + * Returns the percentage of the texture that is currently covered as a value + * from 0 to 100. Caching is used so this value is not recomputed if no changes + * have been made to the texture (via the apply method). + * + * @return {number} The percent, or -1 if the block has not been initialized. + */ +ShadowMap.prototype.percentCovered = function() { + if (this.dirty_cache_) { + this.dirty_cache_ = false; + this.calculatePercent_(); + } + return this.cached_percent_; +}; + +/** + * Given a canvas whose pixels contain the "hit" pixels, marks off the + * corresponding pixels in the original texture. Any pixels in the canvas with + * an alpha of 0 are ignored. + * + * @param {Canvas} renderedCanvas + */ +ShadowMap.prototype.apply = function(renderedCanvas) { + var data = this.canvas.getContext("2d").getImageData(0, 0, + this.width, this.height); + var rWidth = renderedCanvas.width; + var rHeight = renderedCanvas.height; + var rContext = renderedCanvas.getContext("2d"); + var rData = rContext.getImageData(0, 0, rWidth, rHeight); + + for (var i = 0; i < rWidth * rHeight; i++) { + if (rData.data[i * 4 + 3] > 0) { // Alpha of the rendered canvas > 0. + ShadowMap.updatePixel_(data, rData.data[i * 4], + rData.data[i * 4 + 1], rData.data[i * 4 + 2]); + } + } + this.canvas.getContext("2d").putImageData(data, 0, 0); +}; + +/** + * Number of values per channel. + * @type {number} + */ +ShadowMap.base = 256; + +/** + * The alpha value of unhit pixels in this map. In [0, 255] range. + * @type {number} + */ +ShadowMap.ALPHA_START = 127; + +/** + * The alpha value of hit pixels in this map. In [0, 255] range. + * @type {number} + */ +ShadowMap.ALPHA_PUT = 255; + +/** + * Given the index of a pixel in an image, computes the RGB color of that pixel + * based on the pattern we used to initialize the map. + * @param {number} index + * @return {!Array.<number>} + */ +ShadowMap.indexToRGB_ = function(index) { + var base = ShadowMap.base; + var r = Math.floor(index / (base * base)); + var g = Math.floor((index % (base * base)) / base); + var b = index % base; + return [r, g, b]; +} + +/** + * Given an array [r, g, b] of colors, computes the index of that pixel based on + * the pattern we used to initialize the map. + * @param {!Array.<number>} colors + * @return {number} + */ +ShadowMap.rgbToIndex_ = function(colors) { + var r = colors[0]; + var g = colors[1]; + var b = colors[2]; + var base = ShadowMap.base; + return b + (g * base) + (r * base * base); +}; + +/** + * Given a color, marks off the corresponding location in this map. + * @param {ImageData} the canvas' ImageData object + * @param {number} r + * @param {number} g + * @param {number} b + * @return {ImageData} a modified ImageData object + */ +ShadowMap.updatePixel_ = function(imageData, r, g, b) { + var index = ShadowMap.rgbToIndex_([r, g, b]); + imageData.data[index * 4 + 3] = ShadowMap.ALPHA_PUT; + return imageData; +}; + +/** + * Initializes this map so each pixel is a unique color, where the channels are + * incremented iteratively in B-G-R order. + * @param {Canvas} canvas The canvas object to initialize to unique colors. + */ +ShadowMap.init = function(canvas) { + var width = canvas.width; + var height = canvas.height; + var context = canvas.getContext("2d"); + var imageData = context.getImageData(0, 0, width, height); + for (var h = 0; h < height; h++) { + for (var w = 0; w < width; w++) { + var pixelNum = w + h * width; + var index = pixelNum * 4; + var color = ShadowMap.indexToRGB_(pixelNum); + imageData.data[index] = color[0]; + imageData.data[index + 1] = color[1]; + imageData.data[index + 2] = color[2]; + imageData.data[index + 3] = ShadowMap.ALPHA_START; + } + } + context.putImageData(imageData, 0, 0); +}; diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/index.html b/o3d/samples/o3d-webgl-samples/bubbles/blaster/index.html new file mode 100644 index 0000000..284fcb3 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/index.html @@ -0,0 +1,165 @@ +<!-- +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. +--> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<title> +Bubble Blaster (Experimental) +</title> + +<!-- CSS --> +<link href='http://fonts.googleapis.com/css?family=Inconsolata' + rel='stylesheet' type='text/css'> +<link href='resources/style.css' rel='stylesheet' type='text/css'> + +<!-- jQuery --> +<script type="text/javascript" + src="../third_party/jquery/jquery-1.4.2.min.js"></script> + +<!-- O3D --> +<script type="text/javascript" src="../../../o3d-webgl/base.js"></script> +<script type="text/javascript" src="../../../o3djs/base.js"></script> + +<!-- Demo files --> +<script type="text/javascript" src="js/camera.js"></script> +<script type="text/javascript" src="js/bubble.js"></script> +<script type="text/javascript" src="js/bubble-manager.js"></script> +<script type="text/javascript" src="js/block.js"></script> +<script type="text/javascript" src="js/level.js"></script> +<script type="text/javascript" src="js/game.js"></script> +<script type="text/javascript" src="js/main.js"></script> +</head> +<body onload="init();" onunload="uninit();" id="body"> + +<!-- Contains the level name and number. --> +<div id="level-description" class="main-container"></div> + +<!-- Bubble listing on the left. --> +<div id="bubble-manager" class="main-container"> + <div id="bubble-count"> + <div id="bubble-count-span"></div> bubbles remaining + </div> + <div id="bubble-bubbles"></div> +</div> + +<!-- Links in the upper right. --> +<div id="options" class="main-container"> + <ul> + <li><a id="link-help" href="#help">help</a></li> + <li><a id="link-restart" href="#restart">restart</a></li> + </ul> +</div> + +<!-- Progress bar at the bottom --> +<div id="progress"> + <div id="goal" style="width: 0%"></div> +</div> + +<!-- Help dialog. --> +<div id="help" style="display:none;"> + <b>Goal</b> + <p>Your mission is to use bubble "splats" to cover as much of the surface + area of the center target as possible. + </p> + <br /> + <b>Controls</b> + <ul> + <li> <b>SPACE</b> :: releases the next bubble in your queue.</li> + <li> <b>wasd</b> :: rotates your position around the model.</li> + </ul> + <br /> + <p> + <a href="#close-help" id="close-help">close</a> + </p> +</div> + +<!-- Final result --> +<div id="finalResult" style="display:none;"> + <b>Game over!</b> + <p>You successfully covered <span id="final"></span> of the target.</p> +</div> + +<!-- The o3d container --> +<div id="o3d-main" style="width: 100%; height: 100%;"></div> + +<!-- Shader for the block. --> +<textarea style="display:none;" id="blockShader"> + attribute vec4 position; + attribute vec2 texCoord0; + uniform mat4 worldViewProjection; + varying vec4 pos; + varying vec2 tex; + + /** + * The vertex shader simply transforms the input vertices to screen space. + */ + void main() { + // Multiply the vertex positions by the worldViewProjection matrix to + // transform them to screen space. + gl_Position = worldViewProjection * position; + pos = position; + tex = texCoord0; + } + + // #o3d SplitMarker + varying vec4 pos; + varying vec2 tex; + uniform sampler2D myTexture; + uniform vec4 bubblePosition[SIZE]; + + bool insideABubble(vec3 pos) { + bool count = false; + for (int i = 0; i < SIZE; i++) { + vec4 bubble = bubblePosition[i]; + if (length(abs(pos.xyz - bubble.xyz)) < bubble.w) { + return true; + } + } + return false; + } + + /** + * The fragment shader derives color based on the position. + */ + void main() { + vec4 color = texture2D(myTexture, tex); + if (insideABubble(pos.xyz)) { + // inside the bubble + gl_FragColor = vec4((color.xyz / 2.0), 1.0); + } else { + gl_FragColor = vec4(color.xyz, 1.0); + } + } +</textarea> +</body> +</html> diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/block.js b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/block.js new file mode 100644 index 0000000..a2102df1 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/block.js @@ -0,0 +1,145 @@ +/* + * 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. + */ + +/** + * Represents the rotating target that is the focus of each level. + * @param {string} src The path to the json scene. + * @constructor + */ +var Block = function(src) { + this.src = src; + this.load_(); +}; + +/** + * The URL of the scene.json file the target uses. + * @type {string} + */ +Block.prototype.src = ''; + +/** + * The top level transform that contains this block. Beneath this transform + * sits a custom transform for intermediate scaling, then the geometry. + * @type {o3d.Transform} + */ +Block.prototype.transform = null; + +/** + * A pack just for components belonging to this block. + * @type {o3d.Pack} + */ +Block.prototype.pack = null; + +/** + * A pick manager that helps computes intersections between the block and + * bubbles. + * + * @type {o3d.PickManager} + */ +Block.prototype.pickManager = null; + +/** + * Advances the block one time step. + * @param {number} elapsedTime + */ +Block.prototype.step = function(elapsedTime) { + // No op. Could potentially advance a clock to rotate the model. +}; + +/** + * Returns the overridden effect that the model should use. + * @return {o3d.Effect} + */ +Block.prototype.getOverrideEffect = function() { + var shader = document.getElementById('blockShader').value; + shader = shader.replace(/SIZE/g, + g_game.level.bubbleManager_.bubbleQueue_.length); + var effect = this.pack.createObject('Effect'); + effect.loadFromFXString(shader); + return effect; +}; + +/** + * Loads the scene.json file and adds it to the scene. Also binds the eye and + * bubble position parameters. + */ +Block.prototype.load_ = function() { + var that = this; + this.pack = g_client.createPack(); + this.transform = this.pack.createObject('Transform'); + + var parentTransform = this.transform; + function callback(pack, parent, exception) { + if (exception) { + alert("Could not load: \n" + exception); + } else { + o3djs.pack.preparePack(that.pack, g_viewInfo); + parent.parent = g_client.root; + // Create the pick manager. + that.pickManager = o3djs.picking.createPickManager(parent); + that.pickManager.update(); + + // TODO: Create a generic sampler with IO-loaded image texture that will + // be used for all models. + var samplers = pack.getObjectsByClassName('o3d.Sampler'); + var materials = pack.getObjectsByClassName('o3d.Material'); + for (var m = 0; m < materials.length; ++m) { + var material = materials[m]; + var effect = that.getOverrideEffect(); + effect.createUniformParameters(material); + material.effect = effect; + if (material.getParam('myTexture')) { + material.getParam('myTexture').value = samplers[0]; + } + if (material.getParam('bubblePosition')) { + material.getParam('bubblePosition').value = g_paramArray; + } + + // TODO: Not all materials will use this parameter, or it may be + // called something different. + if (material.getParam('lightWorldPos')) { + material.getParam('lightWorldPos').bind(g_lightWorldPosParam); + } + } + + } + } + + // Inner transform for scaling and adjustment. + var child = this.pack.createObject('Transform'); + child.parent = this.transform; + + try { + o3djs.scene.loadScene(g_client, this.pack, child, this.src, callback); + } catch (e) { + alert("loading failed : " + e); + } +}; diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/bubble-manager.js b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/bubble-manager.js new file mode 100644 index 0000000..e37eae7 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/bubble-manager.js @@ -0,0 +1,150 @@ +/* + * 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. + */ + +/** + * Manages a sequence of bubble objects. + * + * @constructor + * @param {!Array<!Bubble.BubbleType>} requestedSequence + * @param {o3d.Pack} pack + */ +var BubbleManager = function(requestedSequence, pack) { + this.bubbleQueue_ = []; + this.nextIndex_ = 0; + this.pack_ = pack; + + this.container_ = $('#bubble-bubbles'); + this.container_.html(" "); // reset + this.counter_ = $('#bubble-count-span'); + + for (var i = 0; i < requestedSequence.length; i++) { + var bubble = new Bubble(requestedSequence[i], this.pack_); + var el = g_paramArray.createParam(i, 'ParamFloat4'); + el.bind(bubble.param); + + this.bubbleQueue_.push(bubble); + var img = new Image(); + var imageSrc; + var type = requestedSequence[i]; + switch (type) { + case Bubble.SMALL: + imageSrc = "resources/bubble3.png"; + break; + case Bubble.MEDIUM: + imageSrc = "resources/bubble2.png"; + break; + case Bubble.LARGE: + imageSrc = "resources/bubble1.png"; + break; + } + img.src = imageSrc; + img.alt = "Bubble " + i; + this.container_.append(img); + this.counter_.text("" + requestedSequence.length); + } +}; + +/** + * The bubbles queued to be released. + * @type {!Array<!Bubble>} + * @private + */ +BubbleManager.prototype.bubbleQueue_ = []; + +/** + * The DOM container to show the queue of bubbles. + * @type {DOM.Element} + * @private + */ +BubbleManager.prototype.container_ = null; + +/** + * The DOM container that keeps the count of bubbles remaining. + * @type {DOM.Element} + * @private + */ +BubbleManager.prototype.counter_ = null; + +/** + * A pointer to the current position in the bubble queue. + * @type {number} + * @private + */ +BubbleManager.prototype.nextIndex_ = 0; + +/** + * A pack contains all the transforms, geometry and shaders of the bubbles it + * manages. + * @type {o3d.Pack} + * @private + */ +BubbleManager.prototype.pack_ = 0; + +/** + * Moves a bubble from the head of the queue to the tail of the bubblesInPlay + * list and returns that bubble. + * + * If the queue is empty, returns null. + * + * @return {Bubble} + */ +BubbleManager.prototype.pop = function() { + if (this.nextIndex_ == this.bubbleQueue_.length) { + return null; + } + var children = this.container_.children(); + var img = children[this.nextIndex_]; + img.className = "used"; + $(img).slideUp(); + this.counter_.text(this.bubbleQueue_.length - this.nextIndex_ - 1) + ""; + return this.bubbleQueue_[this.nextIndex_++]; +}; + +/** + * Returns the bubble at the head of the queue, but does not pop it. + * If the queue is empty, returns null. + * + * @return {Bubble} + */ +BubbleManager.prototype.peek = function() { + return (this.bubbleQueue_.length == this.nextIndex_) ? null : + this.bubbleQueue_[this.nextIndex_]; +}; + +/** + * Advances each bubble in the active queue by one timestep. + */ +BubbleManager.prototype.step = function() { + for (var i = 0; i < this.nextIndex_; i++) { + var bubble = this.bubbleQueue_[i]; + bubble.step(); + } +}; diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/bubble.js b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/bubble.js new file mode 100644 index 0000000..fef0107 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/bubble.js @@ -0,0 +1,231 @@ +/* + * 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 bubble object. + * @param {Bubble.BubbleType} type + * @param {o3d.Pack} pack + * @constructor + */ +var Bubble = function(type, pack) { + this.kind = type; + this.position = [0, 0, 0]; + this.velocity = [0, 0, 0]; + this.alive = false; + this.position = [2 * globals.playerRadius, 0, 0]; + this.param = pack.createObject('ParamFloat4'); + this.param.value = [0, 0, 0, 0]; + + switch (this.kind) { + case Bubble.SMALL: + this.scale = 0.2; + this.color = [0, 0.4, 0.7, 0.7]; + this.speed = 0.05; + break; + case Bubble.MEDIUM: + this.scale = 0.3; + this.color = [0, 0.6, 0.2, 0.7]; + this.speed = 0.08; + break; + case Bubble.LARGE: + this.scale = 0.45; // This is the radius. + this.color = [0.8, 0.2, 0.3, 0.7]; + this.speed = 0.1; + break; + default: + throw 'Invalid type of Bubble'; + } + + this.transform = pack.createObject('Transform'); + if (!Bubble.defaultShape) { + Bubble.createDefaultShape(pack); + } + this.transform.addShape(Bubble.defaultShape); + this.transform.visible = false; + this.transform.createParam('diffuse', 'ParamFloat4').value = this.color; +}; + + +/** + * BubbleType, + * SMALL + * MEDIUM + * LARGE + */ +Bubble.SMALL = 0; +Bubble.MEDIUM = 1; +Bubble.LARGE = 2; + +/** + * The type of a bubble. + * @type {number} + */ +Bubble.BubbleType = goog.typedef; + +/** + * The type of bubble. + * @type {Bubble.BubbleType} + */ +Bubble.prototype.kind = -1; + +/** + * The bubble's position. + * @type {!Array.<number>} + */ +Bubble.prototype.position = []; + +/** + * The bubble's velocity. + * @type {!Array.<number>} + */ +Bubble.prototype.velocity = []; + + +/** + * The bubble's color. + * @type {!Array.<number>} + */ +Bubble.prototype.color = [1, 1, 1]; + +/** + * The bubble's speed. Higher = faster. + * @type {number} + */ +Bubble.prototype.speed = 1.0; + +/** + * The bubble's relative size. + * @type {!Array.<number>} + */ +Bubble.prototype.scale = 1.0; + +/** + * If bubble is in bounds. + * @type {boolean} + */ +Bubble.prototype.alive = false; + +/** + * The bubble's parent transform. + * @type {o3d.Transform} + */ +Bubble.prototype.transform = null; + +/** + * A param that will pass this bubble's position and radius to the shader. + * @type {o3d.ParamFloat4} + */ +Bubble.prototype.param = null; + +/** + * A shared primitive used by all the bubbles. + * @type {o3d.Shape} + */ +Bubble.defaultShape = null; + +/** + * An initializer that creates the default shape. + * @param {o3d.Pack} pack + */ +Bubble.createDefaultShape = function(pack) { + var shader = o3djs.material.createBasicMaterial( + pack, + g_viewInfo, + [1, 1, 1, 1], + true); + Bubble.defaultShape = o3djs.primitives.createSphere(pack, shader, 1, 20, 20); +}; + +/** + * Initializes a bubble at given position. The velocity is inferred to be + * towards the origin and is scaled based on this bubble's speed. + * + * @param {!Array.<number>} position + */ +Bubble.prototype.launch = function(position) { + this.transform.visible = true; + this.alive = true; + this.position = position; + this.velocity = g_math.mulScalarVector(this.speed, + g_math.negativeVector(g_math.normalize(position))); + this.updateTransforms_(); + this.transform.parent = g_client.root; +}; + + +/** + * Updates the transforms so the bubble draws in the correct position. + * @private + */ +Bubble.prototype.updateTransforms_ = function() { + this.transform.identity(); + this.transform.translate(this.position); + this.transform.scale([this.scale, this.scale, this.scale]); +}; + +/** + * Updates the values of the uniform param associated with this bubble. + */ +Bubble.prototype.updateParam = function() { + this.param.value = [this.position[0], this.position[1], this.position[2], + this.scale]; +}; + +/** + * Advances the bubble by one timestep to its new location. + */ +Bubble.prototype.step = function() { + if (!this.alive) { + return; + } + + this.position[0] += this.velocity[0]; + this.position[1] += this.velocity[1]; + this.position[2] += this.velocity[2]; + this.updateParam(); + this.updateTransforms_(); + + // Compute the point furthest from the origin along the velocity ray. + var back = g_math.addVector(g_math.mulScalarVector(-this.scale, + g_math.normalize(this.velocity)), this.position); + var worldRay = {near: back, far: [0, 0, 0]}; + + // Use picking to determine if the origin has intersected the block. + var result = g_game.level.block.pickManager.pick(worldRay); + if (result) { + var ray = g_math.subVector(result.worldIntersectionPosition, back); + if (g_math.length(ray) <= this.scale) { + // Bubble intersected, so stop its movement. + this.alive = false; + this.transform.visible = false; + } + } +}; diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/camera.js b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/camera.js new file mode 100644 index 0000000..a9005d0 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/camera.js @@ -0,0 +1,190 @@ +/* + * 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 camera represents the view of the player. This class has a dependency on + * g_math. + * + * @param {number} fov + * @param {number} distance + * @param {o3d.DrawContext} context + */ +var Camera = function(fov, distance, context) { + this.eye_ = [0, 0, distance, 1]; + this.fov_ = fov; + this.target_ = [0, 0, 0, 1]; + this.up_ = [0, 1, 0, 0]; + this.context_ = context; +}; + +/** + * The camera's eye (position). + * @type {!Array.<number>} + * @private + */ +Camera.prototype.eye_ = [0, 0, 0, 1]; + +/** + * The camera's field of vision, in degrees. + * @type {number} + * @private + */ +Camera.prototype.fov_ = 45; + +/** + * The camera's target (lookAt). + * @type {!Array.<number>} + * @private + */ +Camera.prototype.target_ = [0, 0, 0, 1]; + +/** + * The up vector. + * @type {!Array.<number>} + * @private + */ +Camera.prototype.up_ = [0, 0, 0, 0]; + +/** + * The near plane. + * @type {number} + * @private + */ +Camera.prototype.nearPlane_ = 0.1; + +/** + * The far plane. + * @type {number} + * @private + */ +Camera.prototype.farPlane_ = 5000; + +/** + * The drawContext which this camera's position and perspective affects. + * @type {o3d.DrawContext} + * @private + */ +Camera.prototype.context_ = null; + +/** + * Returns the eye position of the camera as a 3-vector. + * @type {!Array.<number>} + */ +Camera.prototype.__defineGetter__('eye', + function() { + return [this.eye_[0], this.eye_[1], this.eye_[2]]; + } +); + +/** + * Returns the up vector of the camera as a 3-vector. + * @type {!Array.<number>} + */ +Camera.prototype.__defineGetter__('up', + function() { + return [this.up_[0], this.up_[1], this.up_[2]]; + } +); + +/** + * Returns the target/focal point of the camera as a 3-vector. + * @type {!Array.<number>} + */ +Camera.prototype.__defineGetter__('target', + function() { + return [this.target_[0], this.target_[1], this.target_[2]]; + } +); + +/** + * Camera.Dir + * UP, + * DOWN, + * LEFT, + * RIGHT, + */ +Camera.UP = 0; +Camera.DOWN = 1; +Camera.LEFT = 2; +Camera.RIGHT = 3; + +/** + * Updates the projection matrix to correspond to the new width and height of + * the canvas. + * @param {number} width The width of the screen/canvas. + * @param {number} height The height of the screen/canvas. + */ +Camera.prototype.updateProjection = function(width, height) { + this.context_.projection = g_math.matrix4.perspective( + g_math.degToRad(this.fov_), + width / height, + this.nearPlane_, + this.farPlane_); +}; + + +/** + * Updates the view matrix using this Camera's eye, target, and up vectors. + */ +Camera.prototype.updateView = function() { + this.context_.view = g_math.matrix4.lookAt(this.eye, this.target, this.up); +}; + +/** + * Rotates the Camera by delta radians in the given direction and updates the + * view. + * + * @param {Camera.Dir} direction + * @param {number} delta + */ +Camera.prototype.rotate = function(direction, delta) { + var axis; + switch(direction) { + case Camera.LEFT: + case Camera.RIGHT: + axis = this.up_; + break; + case Camera.UP: + case Camera.DOWN: + axis = g_math.cross(this.up_, g_math.negativeVector(this.eye)); + break; + } + switch(direction) { + case Camera.LEFT: + case Camera.DOWN: + delta *= -1; + break; + } + var matrix = g_math.matrix4.axisRotation(axis, delta); + this.up_ = g_math.rowMajor.mulMatrixVector(matrix, this.up_); + this.eye_ = g_math.rowMajor.mulMatrixVector(matrix, this.eye_); + this.updateView(); +}; diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/game.js b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/game.js new file mode 100644 index 0000000..d7f818c --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/game.js @@ -0,0 +1,125 @@ +/* + * 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. + */ + +/** + * Represents a game entity. There should be a single game object. + * @constructor + */ +var Game = function() { +}; + +/** + * Initializes the game object and populates its fields. + * @param {o3d.Pack} pack The pack that this game should create objects in. + */ +Game.prototype.init = function(pack) { + this.camera = new Camera(globals.fov, globals.playerRadius, + g_viewInfo.drawContext); + this.level = new Level(''); // TODO: This will eventually be a .json path. + this.level.start(); + g_lightWorldPosParam.value = this.camera.eye; + this.camera.updateView(); +}; + +/** + * The game's camera. + * @type {Camera} + */ +Game.prototype.camera = null; + +/** + * The current level. + * @type {Level} + */ +Game.prototype.level = null; + +/** + * An action handler to address key presses in the game. + * @param {Event} event + */ +Game.prototype.onKeyPress = function(event) { + event = event || window.event; + if (event.metaKey) + return; + + var keyChar = String.fromCharCode(o3djs.event.getEventKeyChar(event)); + keyChar = keyChar.toLowerCase(); + + var dir; + switch(keyChar) { + case 'a': + dir = Camera.LEFT; + break; + case 'd': + dir = Camera.RIGHT; + break; + case 'w': + dir = Camera.UP; + break; + case 's': + dir = Camera.DOWN; + break; + case ' ': + this.level.launchBubble(); + // fall through + default: + return; + } + this.camera.rotate(dir, globals.keyPressDelta); + g_lightWorldPosParam.value = this.camera.eye; +}; + +/** + * Ends the game and displays the score screen. + * @param {string} amount Coverage achieved, as a string. + */ +Game.prototype.endGame = function(amount) { + $("#final").text(amount); + $("#finalResult").fadeIn() +}; + +/** + * Steps the game forward one timestep (elapsedTime). + * @param {number} elapsedTime The seconds passed since the last call. + */ +Game.prototype.step = function(elapsedTime) { + this.level.step(elapsedTime); +}; + + +/** + * An action handler to address when the o3d container is resized. + * @param {number} newWidth + * @param {number} newHeight + */ +Game.prototype.onClientResize = function(newWidth, newHeight) { + this.camera.updateProjection(newWidth, newHeight); +}; diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/level.js b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/level.js new file mode 100644 index 0000000..c8aaebc --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/level.js @@ -0,0 +1,154 @@ +/* + * 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. + */ + +/** + * Represents a currently active level that is being played. + * @param config + */ +var Level = function(config) { + this.load_(config); + this.pack_ = g_client.createPack(); +}; + +/** + * This level's bubble manager. + * @type {BubbleManager} + * @private + */ +Level.prototype.bubbleManager_ = null; + +/** + * This level's block. + * @type {Block} + */ +Level.prototype.block = null; + +/** + * A pack for assets belonging to this level. + * @type {o3d.Pack} + * @private + */ +Level.prototype.pack_ = null; + +/** + * The current percent of surface area covered, as a percent value in the range + * 0 to 100. + * @type {number} + * @private + */ +Level.prototype.progress_ = 0; + +/** + * The name of the level. + * @type {string} + */ +Level.prototype.levelName = ''; + +/** + * The level number. + * @type {number} + */ +Level.prototype.levelNumber = 0; + +/** + * The sequence of bubbles alloted for this level. + * @type {!Array.<Bubble.BubbleType>} + */ +Level.prototype.bubbles = []; + +/** + * The target coverage goal for this level, in the range [0, 100]. + * @type {number} + */ +Level.prototype.goal = -1; + +/** + * The path to the resource used to load the block model. + * @type {string} + */ +Level.prototype.sceneSrc = ''; + +/** + * Launches a bubble into the game, if possible. Ends the game if no bubbles + * are remaining in the queue. + */ +Level.prototype.launchBubble = function() { + var bubble = this.bubbleManager_.pop(); + if (bubble) { + bubble.launch(g_game.camera.eye); + // TODO: We arbitrarily advance the progress counter. This should later + // compute the covered surface area and adjust appropriately. + this.progress_ += Math.floor(Math.random() * 10); + this.progress_ = Math.min(this.progress_, 99); + $("#goal").css("width", this.progress_ + "%"); + } else { + g_game.endGame($("#goal").css("width")); + } +}; + +/** + * Advances the level by a time duration of elapsedTime. + * @param {number} elapsedTime The seconds passed since the last call. + */ +Level.prototype.step = function(elapsedTime) { + this.bubbleManager_.step(elapsedTime); + this.block.step(elapsedTime); +}; + +/** + * Starts the level. Should be called after the configurations have loaded. + */ +Level.prototype.start = function() { + $('#level-description').text(this.levelNumber + ' ' + this.levelName); + this.bubbleManager_ = new BubbleManager(this.bubbles, this.pack_); + this.block = new Block(this.sceneSrc); +}; + +/** + * Loads a JSON-encoded configuration file and populates this level with its + * values. + * @param {string} config The path to the JSON file. + * @private + */ +Level.prototype.load_ = function(config) { + // TODO: This will eventually load config, a json path, and populate the + // fields below. + this.levelNumber = 12; + this.levelName = 'Crate'; + this.bubbles = [Bubble.SMALL, Bubble.LARGE, Bubble.SMALL, Bubble.MEDIUM, + Bubble.SMALL, Bubble.LARGE, Bubble.SMALL, Bubble.MEDIUM, + Bubble.SMALL, Bubble.LARGE, Bubble.SMALL, Bubble.MEDIUM, + Bubble.SMALL, Bubble.LARGE, Bubble.SMALL, Bubble.MEDIUM, + Bubble.SMALL, Bubble.LARGE, Bubble.SMALL, Bubble.MEDIUM, + Bubble.SMALL, Bubble.LARGE, Bubble.SMALL, Bubble.MEDIUM]; + this.goal = 90; + this.sceneSrc = "../../../simpleviewer/assets/cube/scene.json"; +}; diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/main.js b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/main.js new file mode 100644 index 0000000..7ec99c6 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/js/main.js @@ -0,0 +1,174 @@ +/* + * 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. + */ +o3djs.base.o3d = o3d; +o3djs.require('o3djs.webgl'); +o3djs.require('o3djs.util'); +o3djs.require('o3djs.math'); +o3djs.require('o3djs.quaternions'); +o3djs.require('o3djs.rendergraph'); +o3djs.require('o3djs.primitives'); +o3djs.require('o3djs.material'); +o3djs.require('o3djs.pack'); +o3djs.require('o3djs.arcball'); +o3djs.require('o3djs.scene'); +o3djs.require('o3djs.io'); +o3djs.require('o3djs.picking'); + +/** + * Some global settings. + */ +var globals = { + playerRadius: 5, + fov: 45, + keyPressDelta: 0.1, + bubbleCullDistance: 5, +}; + +/** + * Some global objects. + */ +var g_root; +var g_o3d; +var g_client; +var g_viewInfo; +var g_game; +var g_pack; +var g_o3dHeight, g_o3dWidth; +var g_paramArray; + +/** + * Run once the body is loaded. + */ +function init() { + o3djs.webgl.makeClients(init2); +} + +function init2(clientElements) { + var g_o3dElement = clientElements[0]; // A canvas element. + g_o3d = g_o3dElement.o3d; + g_client = g_o3dElement.client; + + g_client.normalizeClearColorAlpha = false; + g_math = o3djs.math; + + g_pack = g_client.createPack(); + var rootPack = g_client.createPack(); + g_viewInfo = o3djs.rendergraph.createBasicView( + rootPack, + g_client.root, + g_client.renderGraphRoot, + [0, 0, 0, 0]); + + var paramObject = rootPack.createObject('ParamObject'); + g_clockParam = paramObject.createParam('time', 'ParamFloat'); + g_clockParam.value = 0; + g_lightWorldPosParam = + paramObject.createParam('lightWorldPos', 'ParamFloat4'); + g_lightWorldPosParam.value = [0, 0, 5]; + + g_paramArray = rootPack.createObject('ParamArray'); + + g_game = new Game(); + g_game.init(g_pack); + checkClientSize(); + + // Pass the key press to the game's handler. + o3djs.event.addEventListener(g_o3dElement, 'keypress', function(e) { + g_game.onKeyPress(e); + }); + + // Attach click handlers to the level links. + $("#link-help").bind('click', function(e) { + $("#finalResult").hide(); + showHelpMenu(true); + return false; + }); + + $("#close-help").bind('click', function(e) { + showHelpMenu(false); + return false; + }); + + $("#link-restart").bind('click', function(e) { + $("#finalResult").hide(); + $("#help").hide(); + g_game = new Game(); + g_game.init(); + var children = g_client.root.children(); + for (var i = 0; i < children.length; ++i) { + children[i].parent = null; // remove from tree + } + return false; + }); + + g_client.setRenderCallback(onRender); +} + +/** + * Shows or hides the help menu. + * @param doShow + */ +function showHelpMenu(doShow) { + doShow ? $("#help").slideDown() : $("#help").slideUp(); +} + + +/** + * Called every frame. + */ +function onRender(renderEvent) { + g_clockParam.value += renderEvent.elapsedTime; + g_game.step(renderEvent.elapsedTime); + checkClientSize(); +} + +/** + * Checks if the window size has changed and updates the matrices if so. + * @return + */ +function checkClientSize() { + var newWidth = parseInt(g_client.width); + var newHeight = parseInt(g_client.height); + if (newWidth != g_o3dWidth || newHeight != g_o3dHeight) { + g_o3dWidth = newWidth; + g_o3dHeight = newHeight; + g_game.onClientResize(newWidth, newHeight); + } +} + +/** + * Removes any callbacks so they don't get called after the page has unloaded. + */ +function uninit() { + if (g_client) { + g_client.cleanup(); + } +} diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/bubble1.png b/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/bubble1.png Binary files differnew file mode 100644 index 0000000..9fb84c6 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/bubble1.png diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/bubble2.png b/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/bubble2.png Binary files differnew file mode 100644 index 0000000..570fc7f --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/bubble2.png diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/bubble3.png b/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/bubble3.png Binary files differnew file mode 100644 index 0000000..732d192 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/bubble3.png diff --git a/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/style.css b/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/style.css new file mode 100644 index 0000000..b5e8a55 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/bubbles/blaster/resources/style.css @@ -0,0 +1,188 @@ +/** + 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. +*/ + +* { + margin: 0; + padding: 0; + border: 0; +} + +html, body { + height: 100%; +} + +body { + position: relative; +} + +body, p, td, a { + font-family: 'Inconsolata', Verdana, Arial, Tahoma; + color: #FFF; +} + +a { + text-decoration: none; +} + +a:hover { + color: yellow; +} + +p { + margin: 5px 0; +} + +ul { + margin-left: 15px; +} + +/** The left hand side bubble viewer. */ +#bubble-manager { + min-width: 50px; + min-height: 300px; + height: 95%; + overflow: hidden; + padding: 10px; + position: absolute; + margin: 10px; + text-align: center; +} + +/** The bubble images within */ +#bubble-bubbles img { + display: block; + margin: 3px auto; +} + +/** Text div describing bubbles */ +#bubble-count { + font-size: 8pt; +} + +/** Number of bubbles left */ +#bubble-count-span { + font-size: 18pt; +} + +/** For bubbles that have been placed. */ +.used { + opacity: 0.5; + -moz-opacity: 0.5; +} + +body { + background: -webkit-gradient(radial, center center, 0, center center, + 400, from(#89EAF5), to(black)); + background: -moz-radial-gradient(#89EAF5, black); +} + +/** Links that float upper right corner */ +#options { + position: absolute; + top: 0; + right: 0; + padding: 15px; + font-size: 12pt; + z-index: 2; +} + +#options ul { + list-style-type: none; +} + +#options li { + margin: 5px; +} + +/** Links and transitions */ +#options a { + padding: 3px 6px; + -webkit-transition: all 0.5s ease-in-out; + -moz-transition: all 0.5s ease-in-out; + -o-transition: all 0.5s ease-in-out; + -webkit-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; +} + +#options a:hover { + background: #333; + color: #FFF; + border-radius: 5px; +} + +#level-description { + position: absolute; + bottom: 0; + width: 100%; + text-align: center; + padding-bottom: 30px; + font-size: 20pt; + font-weight: bold; +} + +.main-container { + border: 0px solid red; +} + +#progress { + position: absolute; + bottom: 0; + height: 10px; + width: 100%; + background: rgba(255, 0, 0, 0.2); + border-top: 1px solid #333; +} + +#goal { + height: 100%; + background: rgba(0, 255, 0, 0.5); + border-right: 3px solid rgba(0, 200, 0, 0.5); +} + +#help, #finalResult { + position: absolute; + z-index: 5; + border: 5px solid #888; + background: #FFF; + color: #000; + border-radius: 10px; + padding: 15px; + width: 400px; + left: 50%; + margin-left: -200px; + margin-top: 20%; +} + +#help, #help *, #finalResult, #finalResult * { + font-family: Verdana, Arial, Tahoma, sans-serif; + font-size: 8pt; + color: #000; +} |