diff options
author | luchen@google.com <luchen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-29 23:22:57 +0000 |
---|---|---|
committer | luchen@google.com <luchen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-29 23:22:57 +0000 |
commit | 4b09f35b854b66bd3554951d5fd8f9b322dadea0 (patch) | |
tree | c58b4fbf14b0253f2f7c82d2883cbf8f1c170460 /o3d | |
parent | fbf3714a8a46a52a95501aeaa73300b12bdfbae1 (diff) | |
download | chromium_src-4b09f35b854b66bd3554951d5fd8f9b322dadea0.zip chromium_src-4b09f35b854b66bd3554951d5fd8f9b322dadea0.tar.gz chromium_src-4b09f35b854b66bd3554951d5fd8f9b322dadea0.tar.bz2 |
Adding 2d and hud-2d demos to samples. Small addition to state.js to actually use the depthMask flag.
Review URL: http://codereview.chromium.org/2830020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@51192 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/samples/assets/one-pixel-white.png | bin | 0 -> 159 bytes | |||
-rw-r--r-- | o3d/samples/o3d-webgl-samples/2d.html | 562 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl-samples/hud-2d-overlay.html | 493 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl/state.js | 2 |
4 files changed, 1057 insertions, 0 deletions
diff --git a/o3d/samples/assets/one-pixel-white.png b/o3d/samples/assets/one-pixel-white.png Binary files differnew file mode 100644 index 0000000..823a18d --- /dev/null +++ b/o3d/samples/assets/one-pixel-white.png diff --git a/o3d/samples/o3d-webgl-samples/2d.html b/o3d/samples/o3d-webgl-samples/2d.html new file mode 100644 index 0000000..416c76c --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/2d.html @@ -0,0 +1,562 @@ +<!-- +Copyright 2009, 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. +--> + +<!-- +2D in O3D. + +2d is easy in o3d. + +Things to notice: + +*) Pixel perfect alignment with the screen. + + The client area is 800x600 pixels. google-square.png is 200x200 pixels. + There is a 1 pixel border in the google-square.png texture. Notice they line + up exactly with each other and to the edge of the client area. + +*) Screen Top Left = 0,0 vs Center = 0,0 + + This demo is set so the client area's top left corner is 0,0. + If you want the center to be 0,0 just call setScreenOriginToCenter. + You will have to adjust the math below to match. + +*) Image Top left = 0,0 vs Center = 0,0 + + The g_googleSquares are all loaded with their origin set to the top left + so you can see they rotate around the top left and are positioned from + the top left + + The g_squares and the g_things are loaded with their origin set to the center + so you can see they rotate and scale around their centers. + +*) 2d rotation, scale, fading, color changing + + transform.rotateZ rotates in 2d. + transform.scale(x, y, 1) scales in 2d. + image.setColor(1, 1, 1, ?) fades out. + image.setColor(?, ?, ?, 1) sets the color multiplier + +*) Setting draw order by setting Z. negative z is more behind. + + the g_googleSquares have a Z of -2 so they are the furthest back. + the g_squares have Z of -1 so they are in the middle + the g_things have a Z of 0 so they are in the front. + + The Z range is -0.998 to 999 + + That is because the camera is sitting at -1 Z and has the range set + in the projection matrix from 0.001 to 1000 + +*) Things to be aware of. + + Because we are doing 2d, draw order matters but you can only choose + the order by setting the Z value. If you don't set the Z values correctly + you will see issues. For example if 2 images are at the same Z and draw + so that they overlap there is no guarntee which one will get drawn first. + + Note: Right now I think it is which ever one happens to be in the transform + graph first. Maybe we should enforce this and then you can use insertBefore, + insertAfter to change the order instead of setting Z. + +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +2D in O3D. +</title> +<!-- Include sample javascript library functions--> +<script type="text/javascript" src="../o3d-webgl/base.js"></script> +<script type="text/javascript" src="../o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript" id="o3dscript"> +o3djs.base.o3d = o3d; +o3djs.require('o3djs.webgl'); +o3djs.require('o3djs.util'); +o3djs.require('o3djs.math'); +o3djs.require('o3djs.rendergraph'); +o3djs.require('o3djs.primitives'); +o3djs.require('o3djs.material'); +o3djs.require('o3djs.loader'); + + +// global variables +var g_coordWidth = 800; // The number of units across our area +var g_coordHeight = 600; // The number of units down our area +var g_tileWidth = 64; +var g_tileHeight = 64; +var g_pillarWidth = 128; +var g_pillarHeight = 256; +var g_playerWidth = 183; +var g_playerHeight = 198; +var g_tilesAcross = Math.floor((g_coordWidth + g_tileWidth - 1) / + g_tileWidth) + 1; +var g_tilesDown = Math.floor((g_coordHeight + g_tileHeight - 1) / + g_tileHeight) + 1; +var g_pixelsAcrossMap = g_tilesAcross * 64; +var g_pixelsAcrossPillarMap = (Math.floor((g_coordWidth + g_pillarWidth - 1) / + g_pillarWidth) + 1) * g_pillarWidth; +var g_o3d; +var g_math; +var g_client; +var g_viewInfo; +var g_pack; +var g_planeShape; +var g_textures = []; +var g_textureUrls = [ + '../assets/purple-flower.png', // 0 + '../assets/orange-flower.png', // 1 + '../assets/egg.png', // 2 + '../assets/google-square.png', // 3 + '../assets/square.png', // 4 + '../assets/texture_b3.jpg', // 5 + '../assets/pillar.png', // 6 + '../assets/block.png', // 7 + '../assets/android.png' // 8 +]; +var g_googleSquares = []; +var g_squares = []; +var g_things = []; +var g_tiles = []; +var g_pillars = []; +var g_pillarScale = []; +var g_player; +var g_map = [ + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0], + [ 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], + [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], +]; +var g_randSeed = 0; + +/** + * Creates the client area. + */ +function init() { + // These are here so they are visible to both the browser (so selenium sees + // them) and V8. + window.g_clock = 0; + window.g_timeMult = 1; + window.g_finished = false; // for selenium testing + + // Comment out the line below to run the sample in the browser JavaScript + // engine. This may be helpful for debugging. + o3djs.util.setMainEngine(o3djs.util.Engine.V8); + + o3djs.webgl.makeClients(initStep2); +} + +/** + * Sets the origin of the screen to the top left. Assumes the area is 800 pixels + * by 600 pixels. + * + * We have to pick some representation. If we have an image that's 800x600 and + * we want to display it pixel perfect in an 800x600 area then we set the values + * below to 800x600. If instead we were to set them to the width and height of + * the area and say our area was 400x300 it will still be pixel perfect (1 to 1 + * pixels) which would meaning only the top left 400x300 pixels of our 800x600 + * image would show up. + * + * Doing it this way, we get pixel perfect at 800x600 and if we change the size + * of the area, say to 400x300 to 640x480 or any other 4:3 ratio, our program + * will still work as expected. It won't be 1x1 pixels but it will put things + * where we want them within our scaled area. If our area is not 4:3 our image + * will get a little stretched into the new aspect ratio but generally that's + * still better than having some of our app not appear. + * + * The other option is to always set the values below to the width and height of + * our area and then make all the code that positions things calculate where to + * put things and how to scale them to fit which is a lot more work though may + * be appropriate depending on the application. + */ +function setScreenOriginToTopLeft() { + g_viewInfo.drawContext.projection = g_math.matrix4.orthographic( + 0 + 0.5, + g_coordWidth + 0.5, + g_coordHeight + 0.5, + 0 + 0.5, + 0.001, + 1000); + + g_viewInfo.drawContext.view = g_math.matrix4.lookAt( + [0, 0, 1], // eye + [0, 0, 0], // target + [0, 1, 0]); // up +} + +/** + * Sets the origin of the screen to the center. Assumes the area is 800 pixels + * by 600 pixels. See setScreenOriginToTopLeft. + */ +function setScreenOriginToCenter() { + g_viewInfo.drawContext.projection = g_math.matrix4.orthographic( + -g_coordWidth * 0.5 + 0.5, + g_coordWidth * 0.5 + 0.5, + g_coordHeight * 0.5 + 0.5, + -g_coordHeight * 0.5 + 0.5, + 0.001, + 1000); + + g_viewInfo.drawContext.view = g_math.matrix4.lookAt( + [0, 0, 1], // eye + [0, 0, 0], // target + [0, 1, 0]); // up +} + +/** + * Initializes O3D and creates one shape. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initializes global variables and libraries. + var o3dElement = clientElements[0]; + g_o3d = o3dElement.o3d; + g_math = o3djs.math; + + // Set window.g_client as well. Otherwise when the sample runs in V8, selenium + // won't be able to find this variable (it can only see the browser + // environment). + window.g_client = g_client = o3dElement.client; + + // Creates a pack to manage our resources/assets + g_pack = g_client.createPack(); + + g_viewInfo = o3djs.rendergraph.createBasicView( + g_pack, + g_client.root, + g_client.renderGraphRoot); + + // Set the background color to blue. + g_viewInfo.clearBuffer.clearColor = [0.1, 0.1, 1, 1]; + + // Set culling to none so we can flip images using rotation or negative scale. + g_viewInfo.zOrderedState.getStateParam('CullMode').value = + g_o3d.State.CULL_NONE; + g_viewInfo.zOrderedState.getStateParam('ZWriteEnable').value = false; + + // Create an orthographic matrix for 2d stuff. + setScreenOriginToTopLeft(); + //setScreenOriginToCenter(); + + // Load an effect file and create an effect and material with it. + var material = o3djs.material.createMaterialFromFile( + g_pack, + '../shaders/texture-colormult-glsl.shader', + g_viewInfo.zOrderedDrawList); + + // Set the material params which act as the default. We'll override these with + // params on transforms. + material.getParam('colorMult').value = [1, 1, 1, 1]; + + // Create a 2d plane. createPlane makes an XZ plane by default + // so we pass in matrix to rotate it to an XY plane. We could do + // all our manipluations in XZ but most people seem to like XY for 2D. + g_planeShape = o3djs.primitives.createPlane( + g_pack, + material, + 1, + 1, + 1, + 1, + [[1, 0, 0, 0], + [0, 0, 1, 0], + [0,-1, 0, 0], + [0, 0, 0, 1]]); + + // Load all the textures. + var loader = o3djs.loader.createLoader(initStep3); + for (var ii = 0; ii < g_textureUrls.length; ++ii) { + loadTexture(loader, g_textureUrls[ii], ii); + } + loader.finish(); +} + +/** + * Loads a texture and saves it in the g_textures array. + * @param {!o3djs.loader.Loader} loader The loader to load with. + * @param {string} url of texture to load + * @param {number} index Index to put texture in g_textures + */ +function loadTexture(loader, url, index) { + loader.loadTexture(g_pack, url, function(texture, exception) { + if (exception) { + alert(exception); + } else { + g_textures[index] = texture; + } + }); +} + +/** + * Now that the textures are loaded continue. + */ +function initStep3() { + for (var ii = 0; ii < 12; ++ii) { + g_googleSquares[ii] = new ImageTransform(g_textures[3], true); + g_squares[ii] = new ImageTransform(g_textures[4], false); + g_things[ii] = new ImageTransform(g_textures[ii % 3], false); + g_pillars[ii] = new ImageTransform(g_textures[6], true); + g_pillarScale[ii] = g_math.pseudoRandom() * 1.5 + 0.5; + } + + for (var yy = 0; yy < g_tilesDown; ++yy) { + g_tiles[yy] = []; + for (var xx = 0; xx < g_tilesAcross; ++xx) { + if (g_map[yy][xx]) { + g_tiles[yy][xx] = new ImageTransform(g_textures[7], true); + } + } + } + + g_player = new ImageTransform(g_textures[8], true); + + // Setup an onrender callback for animation. + g_client.setRenderCallback(onrender); + + window.g_finished = true; // for selenium testing. +} + +/** + * Called every frame. + * @param {!o3d.RenderEvent} renderEvent Rendering Information. + */ +function onrender(renderEvent) { + var elapsedTime = renderEvent.elapsedTime; + + // Update g_clock in the browser and cache a V8 copy that can be accesse + // efficiently. g_clock must be in the browser for selenium. + var clock = window.g_clock + elapsedTime * window.g_timeMult; + window.g_clock = clock; + + var duration = 4; + var parts = 4; + var fadeTime = 1; + var partOffset = duration - fadeTime; + var cycle = duration * parts - parts; + + var computeFade = function(fadeClock) { + var fade = 1; + if (fadeClock < fadeTime) { + fade = fadeClock / fadeTime; + } else if (fadeClock > duration - fadeTime) { + fade = Math.max(duration - fadeClock, 0) / fadeTime; + } + return fade; + }; + + // Position, fade and rotate the google squares and flowers, eggs. + for (var yy = 0; yy < 3; ++yy) { + for (var xx = 0; xx < 4; ++xx) { + var index = yy * 4 + xx; + var newIndex = (index + Math.floor(clock * 0.5)) % 12 + var offset = (newIndex == 0) ? (clock * 0.5 % 1) : 0; + var vary = 0.01 * index; + + // compute the amount to fade the google squares. + var fade = computeFade((clock + partOffset * 0) % cycle); + + // position and rotate the google squares. + var image = g_googleSquares[newIndex]; + image.transform.identity(); + image.transform.translate(xx * 200, yy * 200, -2 + vary); + image.transform.rotateZ(Math.PI * 2 * offset); + image.setColor(Math.sin(index + clock * 2.2) * 0.2 + 0.6, + Math.sin(index + clock * 3.3) * 0.2 + 0.6, + Math.sin(index + clock * 4.4) * 0.2 + 0.6, + fade); + + // compute the amount to fade the squares. + fade = computeFade((clock + partOffset * 1) % cycle); + + // position and rotate the squares. + var image = g_squares[index]; + image.setColor(1, 1, 1, + fade * (Math.sin(index + clock) * 0.5 + 0.5)); + image.transform.identity(); + image.transform.translate(xx * 200 + 100, yy * 200 + 100, -1 + vary); + image.transform.rotateZ(Math.PI * 2 * offset); + image.transform.scale(1, Math.sin(clock * 2+ index), 1); + + // compute the amount to fade the things. + fade = computeFade((clock + partOffset * 2) % cycle); + + // position, rotate and scale the things. + var image = g_things[index]; + var nx = newIndex % 4; + var ny = Math.floor(newIndex / 4); + offset = clock * 0.5 % 1; + image.transform.identity(); + image.transform.translate(nx * 300 - 200 + offset * 300, + ny * 200 + 100 + + Math.sin(clock * 4 + index * 2) * 50, + 0 + vary); + image.transform.rotateZ((0.1 + index * 0.1) * clock); + var scale = Math.sin(index + clock) * 1.0 + 1.7; + image.transform.scale(scale, scale, 1); + image.setColor(1, 1, 1, fade); + } + } + + // Position and fade the 2d tile based game. + { + // This is NOT the best way to a 2d platformer but it does at least show + // displaying the graphics of one. + + // compute the amount to fade the tiles and pillars. + var fade = computeFade((clock + partOffset * 3) % cycle); + + // position the pillars + for (var xx = 0; xx < 12; ++xx) { + var image = g_pillars[xx]; + image.setColor(1, 1 , 1, fade); + image.transform.identity(); + var xOffset = + (g_pixelsAcrossPillarMap - g_pillarWidth * 2) - + ((((xx + clock * 0.3) * 238) + g_pillarWidth) % + g_pixelsAcrossPillarMap - g_pillarWidth); + image.transform.translate(xOffset, 600 - 256 * g_pillarScale[xx], + -6 + 0.01 * xx); + image.transform.scale(1, g_pillarScale[xx], 1); + } + + // position the tiles. + for (var yy = 0; yy < g_tilesDown; ++yy) { + for (var xx = 0; xx < g_tilesAcross; ++xx) { + if (g_map[yy][xx]) { + var image = g_tiles[yy][xx]; + image.setColor(1, 1, 1, fade); + image.transform.identity(); + var xOffset = + (g_pixelsAcrossMap - g_tileWidth * 2) - + ((((xx + clock * 2) * g_tileWidth) + g_tileWidth) % + g_pixelsAcrossMap - g_tileWidth); + image.transform.translate(xOffset, yy * g_tileHeight, -5); + } + } + } + + { + // position the player. + g_player.setColor(1, 1, 1, fade); + var xOffset = + (g_pixelsAcrossMap - g_tileWidth * 2) - + (((((4.0 + clock * 2) * g_tileWidth) + g_tileWidth) % + g_pixelsAcrossMap + g_tileWidth) - g_tileWidth); + g_player.transform.identity(); + g_player.transform.translate(xOffset, + 5 * g_tileHeight - g_playerHeight - + Math.abs(Math.sin(clock * 5)) * 100, + -4); + } + } +} + +/** + * Creates an ImageTransform object which is a transform and a child + * scaleTransform scaled to match the texture + * + * @constructor + * @param {!o3d.Texture} texture The texture + * @param {boolean} opt_topLeft If true the origin of the image will be it's + * topleft corner, the default is the center of the image. + */ +function ImageTransform(texture, opt_topLeft) { + // create a transform for positioning + this.transform = g_pack.createObject('Transform'); + this.transform.parent = g_client.root; + + // create a transform for scaling to the size of the image just so + // we don't have to manage that manually in the transform above. + this.scaleTransform = g_pack.createObject('Transform'); + this.scaleTransform.parent = this.transform; + + // setup the sampler for the texture + this.sampler = g_pack.createObject('Sampler'); + this.sampler.addressModeU = g_o3d.Sampler.CLAMP; + this.sampler.addressModeV = g_o3d.Sampler.CLAMP; + this.paramSampler = this.scaleTransform.createParam('texSampler0', + 'ParamSampler'); + this.paramSampler.value = this.sampler; + + // Setup our UV offsets and color multiplier + this.paramColorMult = this.scaleTransform.createParam('colorMult', + 'ParamFloat4'); + + this.setColor(1, 1, 1, 1); + + this.sampler.texture = texture; + this.scaleTransform.addShape(g_planeShape); + if (opt_topLeft) { + this.scaleTransform.translate(texture.width / 2, texture.height / 2, 0); + } + this.scaleTransform.scale(texture.width, -texture.height, 1); +} + +/** + * Sets the color multiplier for the image. + * @param {number} r Red component. + * @param {number} g Green component. + * @param {number} b Blue component. + * @param {number} a Alpha component. + */ +ImageTransform.prototype.setColor = function(r, g, b, a) { + this.paramColorMult.value = [r, g, b, a]; +}; + +/** + * Remove any callbacks so they don't get called after the page has unloaded. + */ +function unload() { + if (g_client) { + g_client.cleanup(); + } +} +</script> +</head> +<body onload="init()" onunload="unload()"> +<h1>2D In O3D</h1> +Doing 2D in O3D. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 800px; height: 600px;"></div> +<!-- End of O3D plugin --> +</body> +</html> diff --git a/o3d/samples/o3d-webgl-samples/hud-2d-overlay.html b/o3d/samples/o3d-webgl-samples/hud-2d-overlay.html new file mode 100644 index 0000000..0464b30 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/hud-2d-overlay.html @@ -0,0 +1,493 @@ +<!-- +Copyright 2009, 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. +--> + +<!-- +HUD 2D Overlay. + +This example shows implementing a HUD or 2d Overlay +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +HUD 2D Overlay. +</title> +<!-- Include sample javascript library functions--> +<script type="text/javascript" src="../o3d-webgl/base.js"></script> +<script type="text/javascript" src="../o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript" id="o3dscript"> +o3djs.base.o3d = o3d; +o3djs.require('o3djs.webgl'); +o3djs.require('o3djs.math'); +o3djs.require('o3djs.rendergraph'); +o3djs.require('o3djs.primitives'); +o3djs.require('o3djs.material'); +o3djs.require('o3djs.loader'); + +// Events +// init() once the page has finished loading. +// unload() when the page is unloaded. +window.onload = init; +window.onunload= unload; + +// global variables +var g_o3d; +var g_math; +var g_client; +var g_3dRoot; +var g_hudRoot; +var g_viewInfo; +var g_hudViewInfo; +var g_pack; +var g_clock = 0; +var g_timeMult = 1; +var g_finished = false; // for selenium testing +var g_cameraRadius = 35; +var g_cameraSpeed = 0.3; +var g_gaugeWidth = 145; +var g_gaugeHeight = 16; +var g_planeShape; +var g_groundShape; +var g_cubeShape; +var g_materialUrls = [ + '../shaders/texture-colormult-glsl.shader', // 0 + '../shaders/phong-with-colormult-glsl.shader' // 1 +]; +var g_materials = []; +var g_textures = []; +var g_textureUrls = [ + '../assets/purple-flower.png', // 0 + '../assets/orange-flower.png', // 1 + '../assets/egg.png', // 2 + '../assets/gaugeback.png', // 3 + '../assets/gauge.png', // 4 + '../assets/iconback.png', // 5 + '../assets/radar.png', // 6 + '../assets/one-pixel-white.png' // 7 +]; +var g_radar; +var g_radarNeedle; +var g_gaugeBack; +var g_gauges = []; +var g_gaugeFrames = []; +var g_iconBacks = []; +var g_icons = []; +var g_selectedIndex = 0; +var g_randSeed = 0; + +/** + * Creates the client area. + */ +function init() { + o3djs.webgl.makeClients(initStep2); +} + +/** + * Initializes O3D and creates one shape. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initializes global variables and libraries. + var o3dElement = clientElements[0]; + g_o3d = o3dElement.o3d; + g_math = o3djs.math; + g_client = o3dElement.client; + + // Creates a pack to manage our resources/assets + g_pack = g_client.createPack(); + + // Create 2 root transforms, one for the 3d parts, one for the 2d parts. + // This is not strictly neccassary but it is helpful for organization. + g_3dRoot = g_pack.createObject('Transform'); + g_hudRoot = g_pack.createObject('Transform'); + + g_viewInfo = o3djs.rendergraph.createBasicView( + g_pack, + g_3dRoot, + g_client.renderGraphRoot); + + // Create a second view for the hud. There are other ways to do this but + // this is the easiest. + g_hudViewInfo = o3djs.rendergraph.createBasicView( + g_pack, + g_hudRoot, + g_client.renderGraphRoot); + + // Make sure the hud gets drawn after the 3d stuff + g_hudViewInfo.root.priority = g_viewInfo.root.priority + 1; + + // Turn off clearing the color for the hud since that would erase the 3d + // parts but leave clearing the depth and stencil so the HUD is unaffected + // by anything done by the 3d parts. + g_hudViewInfo.clearBuffer.clearColorFlag = false; + + // Set culling to none so we can flip images using rotation or negative scale. + g_hudViewInfo.zOrderedState.getStateParam('CullMode').value = + g_o3d.State.CULL_NONE; + g_hudViewInfo.zOrderedState.getStateParam('ZWriteEnable').value = false; + + // Create an orthographic matrix for 2d stuff in the HUD. + // We assume the area is 800 pixels by 600 pixels and therefore we can + // position things using a 0-799, 0-599 coordinate system. If we change the + // size of the client area everything will get scaled to fix but we don't + // have to change any of our code. See 2d.html + g_hudViewInfo.drawContext.projection = g_math.matrix4.orthographic( + 0 + 0.5, + 800 + 0.5, + 600 + 0.5, + 0 + 0.5, + 0.001, + 1000); + + g_hudViewInfo.drawContext.view = g_math.matrix4.lookAt( + [0, 0, 1], // eye + [0, 0, 0], // target + [0, 1, 0]); // up + + g_viewInfo.drawContext.projection = g_math.matrix4.perspective( + g_math.degToRad(30), // 30 degree fov. + g_client.width / g_client.height, + 0.1, // Near plane. + 5000); // Far plane. + + for (var ii = 0; ii < g_materialUrls.length; ++ii) { + var material = o3djs.material.createMaterialFromFile( + g_pack, + g_materialUrls[ii], + g_viewInfo.performanceDrawList); + + // Set the default params. We'll override these with params on transforms. + material.getParam('colorMult').value = [1, 1, 1, 1]; + + g_materials[ii] = material; + } + + // Set the materials' drawLists + g_materials[0].drawList = g_hudViewInfo.zOrderedDrawList; + g_materials[1].drawList = g_viewInfo.performanceDrawList; + + g_materials[1].getParam('lightWorldPos').value = [500, 1000, 0]; + g_materials[1].getParam('lightIntensity').value = [1, 1, 1, 1]; + g_materials[1].getParam('ambientIntensity').value = [0.1, 0.1, 0.1, 1]; + g_materials[1].getParam('ambient').value = [1, 1, 1, 1]; + g_materials[1].getParam('diffuse').value = [1, 1, 1, 1]; + g_materials[1].getParam('specular').value = [0.5, 0.5, 0.5, 1]; + g_materials[1].getParam('shininess').value = 20; + + // Create a 2d plane for images. createPlane makes an XZ plane by default + // so we pass in matrix to rotate it to an XY plane. We could do + // all our manipluations in XZ but most people seem to like XY for 2D. + g_planeShape = o3djs.primitives.createPlane( + g_pack, + g_materials[0], + 1, + 1, + 1, + 1, + [[1, 0, 0, 0], + [0, 0, 1, 0], + [0,-1, 0, 0], + [0, 0, 0, 1]]); + + // Create a ground plane + g_groundShape = o3djs.primitives.createPlane( + g_pack, + g_materials[1], + 30, + 30, + 10, + 10); + + // Create a cube with its origin at the bottom center. + g_cubeShape = o3djs.primitives.createCube( + g_pack, + g_materials[1], + 1, + [[0.9, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0.9, 0], + [0, 0.5, 0, 1]]); + + // Load all the textures. + var loader = o3djs.loader.createLoader(initStep3); + for (var ii = 0; ii < g_textureUrls.length; ++ii) { + loadTexture(loader, g_textureUrls[ii], ii); + } + loader.finish(); +} + +/** + * Loads a texture and saves it in the g_textures array. + * @param {Object} loader The loader to load with. + * @param {stinrg} url of texture to load + * @param {number} index Index to put texture in g_textures + */ +function loadTexture(loader, url, index) { + loader.loadTexture(g_pack, url, function(texture, exception) { + if (exception) { + alert(exception); + } else { + g_textures[index] = texture; + } + }); +} + +/** + * Now that the textures are loaded continue. + */ +function initStep3() { + // Setup the hud images. + g_radar = new ImageTransform(g_textures[6], true); + g_radar.transform.translate(3, 1, -2); + + g_radarNeedle = new ImageTransform(g_textures[7], false); + g_radarNeedle.scaleTransform.translate(0, 0.5, 0); + + g_gaugeBack = new ImageTransform(g_textures[3], true); + g_gaugeBack.transform.translate(201, 17, -2); + + for (var ii = 0; ii < 3; ++ii) { + g_gaugeFrames[ii] = new ImageTransform(g_textures[4], true); + g_gaugeFrames[ii].transform.translate(220, 39 + ii * 21, -2); + + g_gauges[ii] = new ImageTransform(g_textures[7], true); + g_gauges[ii].setColor((ii == 0) ? 1 : 0, + (ii == 1) ? 1 : 0, + (ii == 2) ? 1 : 0, + 1); + + g_iconBacks[ii] = new ImageTransform(g_textures[5], true); + g_iconBacks[ii].transform.translate(634, 17 + ii * 140, -2); + + // Make the icons' origin their center so we can easily rotate/scale them. + g_icons[ii] = new ImageTransform(g_textures[ii], false); + } + + resetIcons(); + + // make the ground plane. + var transform = g_pack.createObject('Transform'); + transform.addShape(g_groundShape); + transform.parent = g_3dRoot; + transform.createParam('colorMult', 'ParamFloat4').value = + [166 / 255, 124 / 255, 82 / 255, 1]; + + // Make a random city with 25 blocks. + for (var bz = -2; bz <= 2; ++bz) { + for (var bx = -2; bx <= 2; ++bx) { + for (var xx = 0; xx < 4; ++xx) { + createBuilding(bx * 5 + 1 + xx - 1.5, bz * 5 + 1 - 1.5); + createBuilding(bx * 5 + 1 + xx - 1.5, bz * 5 + 4 - 1.5); + } + for (var zz = 1; zz < 3; ++zz) { + createBuilding(bx * 5 + 1 - 1.5, bz * 5 + 1 + zz - 1.5); + createBuilding(bx * 5 + 4 - 1.5, bz * 5 + 1 + zz - 1.5); + } + } + } + + // Setup an onrender callback for animation. + g_client.setRenderCallback(onrender); + + g_finished = true; // for selenium testing. +} + +/** + * Creates a building. + * @param {number} x X coordinate to create building at + * @param {number} z Y coordinate to create building at + */ +function createBuilding(x, z) { + var transform = g_pack.createObject('Transform'); + transform.addShape(g_cubeShape); + transform.parent = g_3dRoot; + transform.translate(x, 0, z); + transform.scale(1, g_math.pseudoRandom() * 3 + 1, 1); + transform.createParam('colorMult', 'ParamFloat4').value = [ + g_math.pseudoRandom() * 0.6 + 0.4, + g_math.pseudoRandom() * 0.6 + 0.4, + g_math.pseudoRandom() * 0.6 + 0.4, + 1]; +} + +/** + * Resets the orientation of the icons. + */ +function resetIcons() { + for (var ii = 0; ii < g_icons.length; ++ii) { + g_icons[ii].transform.identity(); + g_icons[ii].transform.translate(634 + 6 + 64, 17 + ii * 140 + 5 + 64, -1); + g_icons[ii].transform.scale(0.8, 0.8, 0); + } +} + +/** + * Called every frame. + * @param {!o3d.RenderEvent} renderEvent Rendering Information. + */ +function onrender(renderEvent) { + var elapsedTime = renderEvent.elapsedTime; + g_clock += elapsedTime * g_timeMult; + + g_selectedIndex = Math.floor(g_clock / 3) % 3; + + // Fly the camera around the city. + var eye = [ + Math.sin(g_clock * g_cameraSpeed) * g_cameraRadius, + 10, + Math.cos(g_clock * g_cameraSpeed) * g_cameraRadius]; + + g_viewInfo.drawContext.view = g_math.matrix4.lookAt( + eye, + [0, 0, 0], // target + [0, 1, 0]); // up + + for (var i = 0; i < g_icons.length; i++) { + var icon = g_icons[i]; + icon.transform.identity(); + icon.transform.translate( + 634 + 6 + 64, 17 + i * 140 + 5 + 64, -1); + if (i == g_selectedIndex) { + icon.transform.rotateZ(g_clock * -1); + var scale = Math.sin(g_clock * 15) * 0.1 + 0.7; + icon.transform.scale(scale, scale, 1); + } else { + icon.transform.scale(0.8, 0.8, 0); + } + } + + // Adjust the gauges + for (var ii = 0; ii < 3; ++ii) { + var gauge = g_gauges[ii]; + gauge.transform.identity(); + gauge.transform.translate(220 + 1, 39 + ii * 21 + 1, -1); + switch (ii) { + case 0: + gauge.transform.scale((Math.sin(g_clock) * 0.5 + 0.5) * g_gaugeWidth, + g_gaugeHeight, + 1); + break; + case 1: + gauge.transform.scale((Math.cos(g_clock) * 0.5 + 0.5) * g_gaugeWidth, + g_gaugeHeight, + 1); + break; + case 2: + gauge.transform.scale( + (Math.cos(g_clock * 3.2) * 0.2 + 0.6) * g_gaugeWidth, + g_gaugeHeight, + 1); + break; + } + } + + // Rotate the radar + g_radarNeedle.transform.identity(); + g_radarNeedle.transform.translate(93, 89, 0); + g_radarNeedle.transform.rotateZ(g_clock * 3); + g_radarNeedle.transform.scale(1, 80, 1); +} + +/** + * Creates an ImageTransform object which is a transform and a child + * scaleTransform scaled to match the texture + * + * @constructor + * @param {!o3d.Texture} texture The texture + * @param {boolean} opt_topLeft If true the origin of the image will be its + * topleft corner, the default is the center of the image. + */ +function ImageTransform(texture, opt_topLeft) { + // create a transform for positioning + this.transform = g_pack.createObject('Transform'); + this.transform.parent = g_hudRoot; + + // create a transform for scaling to the size of the image just so + // we don't have to manage that manually in the transform above. + this.scaleTransform = g_pack.createObject('Transform'); + this.scaleTransform.parent = this.transform; + + // setup the sampler for the texture + this.sampler = g_pack.createObject('Sampler'); + this.sampler.addressModeU = g_o3d.Sampler.CLAMP; + this.sampler.addressModeV = g_o3d.Sampler.CLAMP; + this.paramSampler = this.scaleTransform.createParam('texSampler0', + 'ParamSampler'); + this.paramSampler.value = this.sampler; + + // Setup our UV offsets and color multiplier + this.paramColorMult = this.scaleTransform.createParam('colorMult', + 'ParamFloat4'); + + this.setColor(1, 1, 1, 1); + + this.sampler.texture = texture; + this.scaleTransform.addShape(g_planeShape); + if (opt_topLeft) { + this.scaleTransform.translate(texture.width / 2, texture.height / 2, 0); + } + this.scaleTransform.scale(texture.width, -texture.height, 1); +} + +/** + * Sets the color multiplier for the image. + * @param {number} r Red component. + * @param {number} g Green component. + * @param {number} b Blue component. + * @param {number} a Alpha component. + */ +ImageTransform.prototype.setColor = function(r, g, b, a) { + this.paramColorMult.value = [r, g, b, a]; +}; + +/** + * Remove any callbacks so they don't get called after the page has unloaded. + */ +function unload() { + if (g_client) { + g_client.cleanup(); + } +} +</script> +</head> +<body> +<h1>HUD 2D Overlay</h1> +HUD = Heads Up Display. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 800px; height: 600px;"></div> +<!-- End of O3D plugin --> +</body> +</html> diff --git a/o3d/samples/o3d-webgl/state.js b/o3d/samples/o3d-webgl/state.js index b77cdd2..632e88a 100644 --- a/o3d/samples/o3d-webgl/state.js +++ b/o3d/samples/o3d-webgl/state.js @@ -544,6 +544,8 @@ o3d.State.prototype.set = function() { this.gl.disable(this.gl.DITHER); } + this.gl.depthMask(stateParams['ZWriteEnable'].value); + if (stateParams['ZEnable'].value) { this.gl.enable(this.gl.DEPTH_TEST); this.gl.depthFunc( |