summaryrefslogtreecommitdiffstats
path: root/o3d/samples/io
diff options
context:
space:
mode:
Diffstat (limited to 'o3d/samples/io')
-rw-r--r--o3d/samples/io/README.txt29
-rw-r--r--o3d/samples/io/actors/actor.js144
-rw-r--r--o3d/samples/io/actors/arrow.js94
-rw-r--r--o3d/samples/io/actors/avatar.js67
-rw-r--r--o3d/samples/io/actors/coin.js68
-rw-r--r--o3d/samples/io/actors/horizontalpad.js85
-rw-r--r--o3d/samples/io/actors/mover.js48
-rw-r--r--o3d/samples/io/actors/spikem.js126
-rw-r--r--o3d/samples/io/actors/verticalpad.js84
-rw-r--r--o3d/samples/io/autoincludes.js49
-rw-r--r--o3d/samples/io/cutscenes.js148
-rw-r--r--o3d/samples/io/dynamic_lights.js123
-rw-r--r--o3d/samples/io/editor.html126
-rw-r--r--o3d/samples/io/gamelogic.js578
-rw-r--r--o3d/samples/io/init.js395
-rw-r--r--o3d/samples/io/io.html173
-rw-r--r--o3d/samples/io/levels/all_actors.js383
-rw-r--r--o3d/samples/io/levels/all_actors.skpbin0 -> 1514934 bytes
-rw-r--r--o3d/samples/io/levels/map1.js156
-rw-r--r--o3d/samples/io/levels/map1.skpbin0 -> 663342 bytes
-rw-r--r--o3d/samples/io/levels/starter_level.skpbin0 -> 557136 bytes
-rw-r--r--o3d/samples/io/sound/_MISS.mp3bin0 -> 627 bytes
-rw-r--r--o3d/samples/io/sound/_PUNCH.mp3bin0 -> 940 bytes
-rw-r--r--o3d/samples/io/sound/_SMASH.mp3bin0 -> 40333 bytes
-rw-r--r--o3d/samples/io/sound/_woosh.mp3bin0 -> 6653 bytes
-rw-r--r--o3d/samples/io/sound/ah.mp3bin0 -> 7549 bytes
-rw-r--r--o3d/samples/io/sound/arrow.mp3bin0 -> 5459 bytes
-rw-r--r--o3d/samples/io/sound/coin_3.mp3bin0 -> 12564 bytes
-rw-r--r--o3d/samples/io/sound/music.mp3bin0 -> 3276800 bytes
-rw-r--r--o3d/samples/io/sound/page.mp3bin0 -> 12146 bytes
-rw-r--r--o3d/samples/io/sound/soundplayer.js147
-rw-r--r--o3d/samples/io/sound/soundplayer.swfbin0 -> 3869 bytes
-rw-r--r--o3d/samples/io/sound/step1.mp3bin0 -> 4623 bytes
-rw-r--r--o3d/samples/io/sound/step2.mp3bin0 -> 5041 bytes
-rw-r--r--o3d/samples/io/sound/step3.mp3bin0 -> 4205 bytes
-rw-r--r--o3d/samples/io/sound/ug.mp3bin0 -> 2951 bytes
-rw-r--r--o3d/samples/io/ui/Thumbs.dbbin0 -> 27648 bytes
-rw-r--r--o3d/samples/io/ui/bgtile.jpgbin0 -> 2495 bytes
-rw-r--r--o3d/samples/io/ui/book_capbottom.jpgbin0 -> 18693 bytes
-rw-r--r--o3d/samples/io/ui/book_capleft.jpgbin0 -> 11719 bytes
-rw-r--r--o3d/samples/io/ui/book_capright.jpgbin0 -> 14239 bytes
-rw-r--r--o3d/samples/io/ui/book_captop.jpgbin0 -> 16493 bytes
-rw-r--r--o3d/samples/io/ui/book_cover.jpgbin0 -> 86247 bytes
-rw-r--r--o3d/samples/io/ui/book_innercover.jpgbin0 -> 25296 bytes
-rw-r--r--o3d/samples/io/ui/book_page1.jpgbin0 -> 97294 bytes
-rw-r--r--o3d/samples/io/ui/book_page2.jpgbin0 -> 95923 bytes
-rw-r--r--o3d/samples/io/ui/book_page3.jpgbin0 -> 75059 bytes
-rw-r--r--o3d/samples/io/ui/book_pageblank.jpgbin0 -> 44635 bytes
-rw-r--r--o3d/samples/io/ui/covershadow.pngbin0 -> 6490 bytes
-rw-r--r--o3d/samples/io/ui/io.css181
-rw-r--r--o3d/samples/io/ui/logo.gifbin0 -> 1577 bytes
-rw-r--r--o3d/samples/io/ui/scrollwork.gifbin0 -> 26553 bytes
52 files changed, 3204 insertions, 0 deletions
diff --git a/o3d/samples/io/README.txt b/o3d/samples/io/README.txt
new file mode 100644
index 0000000..e6ede03
--- /dev/null
+++ b/o3d/samples/io/README.txt
@@ -0,0 +1,29 @@
+Steps to Create a level:
+
+1. Install the SketchUp Level Creation tools
+2. Start SU 6
+3. Draw your "world path" using the line tool
+
+- Using the line tool, draw a line from the drawing origin along the solid green axis line (that's your x axis) It can be as long or as short as you want.
+- From there, you can draw lines continuously from the end of your first line segment. Each line is a distinct plane in the world path.
+- Only draw horizontal lines along the Sketchup drawing's ground plane. No slopes or vertical changes in altitude.
+- Your avatar will NOT walk on these lines. They are only used to define the path that the world will run along.
+
+4. Draw your platforms
+- Each horizontal line must be exactly parallel and exactly "above" or "below" one of your "world path" line segments.
+- Good way to do this is to CTRL+MOVE your base lines up or down, and then chop them up from there.
+- Each horizontal line is a platform that your avatar can walk on.
+- Each vertical line is an "obstacle" that your avatar can't walk through.
+
+5. Drag in your actors
+- The installer created a directory under components > Prince IO (or it will, once we're done with it. -SEL)
+- Drag these suckers in. Note that you're going to want to put them on line segments, typically.
+
+6. Draw random geometry only in components and groups.
+
+7. Test everything in SU.
+- Press the "play" button in the Prince IO level designer. You can play the game.
+- Note: Set your field of view to 45 degrees to have approximately the same camera view as in O3D.
+
+8. Press the "export" button and save your myLevelName.js and myLevelName.kmz into your prince IO /levels directory.
+(this will also automatically generate the autoincludes.js file.)
diff --git a/o3d/samples/io/actors/actor.js b/o3d/samples/io/actors/actor.js
new file mode 100644
index 0000000..a0e1e50
--- /dev/null
+++ b/o3d/samples/io/actors/actor.js
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview This file defines the Actor class.
+ */
+
+/**
+ * Pulls in all names attributes of a source object and applies them to a
+ * target object. Handy for pulling in a bunch of name:value pairs that were
+ * passed all at once.
+ */
+function Actor() {
+ // Create some defaults for our "required" attributes.
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.width = 20;
+ this.height = 20;
+ this.mapX = 0;
+ this.platformID = 0;
+ this.rotZ = 0;
+ this.frameName = '';
+}
+
+Actor.prototype.absorbNamedValues = function(initObj) {
+ for (var key in initObj) {
+ this[key] = initObj[key];
+ }
+};
+
+/**
+ * Note that for collision detection, all actors are envisioned as 2d rectangles
+ * inside a single plane. These rectangles have a width and a height, and their
+ * "origin" is on the bottom center of the rectangle. So if you create a new
+ * actor, be sure to give it a reasonable width and height.
+ */
+Actor.prototype.collidesWith = function(otherActor) {
+ thisLeft = this.mapX - this.width/2;
+ thisRight = this.mapX + this.width/2;
+ thisTop = this.z + this.height;
+ thisBottom = this.z;
+
+ otherLeft = otherActor.mapX - otherActor.width/2;
+ otherRight = otherActor.mapX + otherActor.width/2;
+ otherTop = otherActor.z + otherActor.height;
+ otherBottom = otherActor.z;
+
+ // First see if we're not overlapping in any dimension.
+ if (thisRight < otherLeft ||
+ thisLeft > otherRight ||
+ thisBottom > otherTop ||
+ thisTop < otherBottom) {
+ return false;
+ }
+
+ // Next check for overlap along X.
+ if (thisRight >= otherLeft &&
+ thisLeft <= otherRight) {
+ // then we're still in the running...
+ } else {
+ return false;
+ }
+
+ // Next check for overlap along Y.
+ if (thisBottom <= otherTop &&
+ thisTop >= otherBottom) {
+ return true;
+ }
+
+ // We're not overlapping in Y, so bomb.
+ return false;
+};
+
+Actor.prototype.isHitBySword = function() {
+ var isHit = false;
+ if (avatar.animation == "Hero_Sword" && avatar.frame > 3) {
+ avatar.width += 80;
+ avatar.height += avatar.frame * 5;
+ if (this.collidesWith(avatar)) {
+ var isHit = true;
+ }
+ avatar.width -= 80;
+ avatar.height -= avatar.frame * 5;
+ }
+ return isHit;
+}
+
+Actor.prototype.isHitByArrow = function() {
+ var isHit = false;
+ // TODO: Make this allow multiple arrows, perform better, etc.
+ if (top.arrowActor != undefined) {
+ // If we don't have the same "parentPlatform, meaning we're in different
+ // world path space, then we don't collide.
+ if (world.platforms[top.arrowActor.platformID].parentID !=
+ world.platforms[this.platformID].parentID) {
+ return false;
+ }
+ if (this.collidesWith(top.arrowActor)) {
+ var isHit = true;
+ }
+ }
+ return isHit;
+}
+
+Actor.prototype.moveMapX = function(change) {
+ var platformAngle = world.platforms[this.platformID].rotZ;
+ this.mapX += change;
+ this.x += change * Math.cos(platformAngle);
+ this.y += change * Math.sin(platformAngle);
+};
+
+
+
+
diff --git a/o3d/samples/io/actors/arrow.js b/o3d/samples/io/actors/arrow.js
new file mode 100644
index 0000000..0103b5c
--- /dev/null
+++ b/o3d/samples/io/actors/arrow.js
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview This file defines the Arrow class.
+ */
+
+/**
+ * An arrow that Io can shoot.
+ */
+function Arrow(initObj) {
+ this.absorbNamedValues(initObj);
+
+ // Hide myself by moving way off the screen.
+ this.z = -10000;
+ this.mapX = -10000;
+ this.width = 40;
+ this.height = 1;
+ this.velX = 0;
+
+ // Figure out which arrow number I am.
+ this.arrowNumber = parseInt(initObj.name.substr(initObj.name.length-1,1));
+
+}
+Arrow.prototype = new Actor;
+
+Arrow.prototype.onTick = function(timeElapsed) {
+ if (this.mapX < avatar.mapX-500 || this.mapX > avatar.mapX+500 &&
+ this.z > -10000) {
+ // then hide ourselves way off screen.
+ this.mapX = -10000;
+ this.z = -10000;
+ updateActor(this);
+ } else {
+ // Here's how I move. moveMapX is a handy function that updates both
+ // my "virtual 2d world" mapX, as well as my literal x + y values
+ this.moveMapX(this.velX * timeElapsed)
+ updateActor(this);
+ }
+}
+
+Arrow.prototype.shoot = function() {
+ this.x = avatar.x;
+ this.y = avatar.y;
+ this.z = avatar.z + 33; // Approximate height of IO's crossbow.
+ this.platformID = avatar.platformID;
+ this.parentPlatformID = avatar.parentPlatformID;
+ this.rotZ = world.platforms[this.platformID].rotZ;
+ this.mapX = avatar.mapX;
+
+ if (Math.abs(avatar.rotZ - this.rotZ) < Math.PI/2) {
+ this.velX = 50 * 20;
+ } else {
+ this.velX = -50 * 20;
+ this.rotZ -= Math.PI;
+ }
+ soundPlayer.play('sound/arrow.mp3', 100);
+ updateActor(this);
+}
+
+// TODO: This should be a generic concept, not an arrow-specifc
+// thing.
+Arrow.prototype.hide = function() {
+ this.mapX = -10000;
+}
diff --git a/o3d/samples/io/actors/avatar.js b/o3d/samples/io/actors/avatar.js
new file mode 100644
index 0000000..aac4f45e
--- /dev/null
+++ b/o3d/samples/io/actors/avatar.js
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/**
+ * Our avatar object. Hooray!
+ */
+function Avatar(initObj) {
+ this.absorbNamedValues(initObj);
+
+ this.animation = "Hero_Stand"
+ this.velX = 0;
+ this.velY = 0;
+ this.velZ = 0;
+ this.targetRotZ = 0; // Where we'd like to be facing.
+ this.targetVelX = 0; // Speed we'd like to be going.
+ this.swordRate = .5;
+
+ this.width = 30;
+ this.height = 50;
+
+ this.frame = 1;
+ this.framesSinceShot = 0; // If > 0, tack a "#1" onto our instance name.
+ this.isJumping = false;
+
+ // We always start on platform 0 to fix a placement bug.
+ this.platformID = 0;
+ this.x = 0;
+ this.y = 0;
+ this.mapX = 0;
+ this.z = 200;
+ this.parentPlatformID = 0;
+
+}
+
+Avatar.prototype = new Actor;
+
+Avatar.prototype.onTick = function(timeElapsed) {
+ updateActor(this);
+}
diff --git a/o3d/samples/io/actors/coin.js b/o3d/samples/io/actors/coin.js
new file mode 100644
index 0000000..1124d5e
--- /dev/null
+++ b/o3d/samples/io/actors/coin.js
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview This file defines the Coin class.
+ */
+
+/**
+ * A Coin to be picked up
+ */
+function Coin(initObj) {
+ this.absorbNamedValues(initObj);
+ this.hasBeenPickedUp = false;
+ this.width = 14;
+ this.height = 14;
+ this.isHidden = false;
+}
+Coin.prototype = new Actor;
+
+Coin.prototype.onTick = function(timeElapsed) {
+ if (this.isHidden == true) {
+ return;
+ } else if (this.hasBeenPickedUp == true) {
+ this.z = (this.z*6 + eyeZ+40)/7;
+ this.x = (this.x*3 + eyeX)/4;
+ this.y = (this.y*3 + eyeY)/4;
+ if (Math.abs(this.z - eyeZ+40) < 1) {
+ this.isHidden = true;
+ this.z = -10000;
+ }
+ } else {
+ if (this.collidesWith(avatar)) {
+ soundPlayer.play('sound/coin_3.mp3', 100, 0, true);
+ this.hasBeenPickedUp = true;
+ }
+ }
+ this.rotZ += .4 * 20 * timeElapsed;
+ updateActor(this);
+}
diff --git a/o3d/samples/io/actors/horizontalpad.js b/o3d/samples/io/actors/horizontalpad.js
new file mode 100644
index 0000000..b2e3f85
--- /dev/null
+++ b/o3d/samples/io/actors/horizontalpad.js
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview This file defines the HorizontalPad class.
+ */
+
+/**
+ * A Horizontal Floater.
+ */
+function HorizontalPad(initObj) {
+ this.absorbNamedValues(initObj);
+ this.maxSpeed = 4 * 20;
+ this.moveAmount = 4 * 20;
+ this.width = 42;
+ this.height = 1;
+}
+HorizontalPad.prototype = new Actor;
+
+HorizontalPad.prototype.onTick = function(timeElapsed) {
+ // When you attach me to a platform, I make it so nobody
+ // can stand on it... only me.
+ world.platforms[this.platformID].isNotSolid = true;
+
+ // I move based off of the platform that I'm on. So get that now.
+ var myPlatform = world.platforms[this.platformID];
+
+ // I bounce back and forth between the left and right points on my platform.
+ if (this.mapX < myPlatform.left.mapX) {
+ this.moveAmount += 1;
+ } else if (this.mapX > myPlatform.right.mapX) {
+ this.moveAmount -= 1;
+ } else if (this.moveAmount >= 0) {
+ this.moveAmount = this.maxSpeed;
+ } else {
+ this.moveAmount = -this.maxSpeed;
+ }
+
+ // I match my rotation to that of my platform.
+ this.rotZ = myPlatform.rotZ;
+
+ // Here's how I move. moveMapX is a handy function that updates both
+ // my "virtual 2d world" mapX, as well as my literal x + y values
+ this.moveMapX(this.moveAmount * timeElapsed)
+
+ // If I collide with the avatar, then move the avatar along with me,
+ // and set his "override" groundZ to be my own Z.
+ if (this.collidesWith(avatar)) {
+ if (avatar.velZ <= 0 && avatar.z >= this.z - 25) {
+ avatar.moveMapX(this.moveAmount * timeElapsed);
+ avatar.groundZ = this.z;
+ }
+ }
+
+ updateActor(this);
+}
diff --git a/o3d/samples/io/actors/mover.js b/o3d/samples/io/actors/mover.js
new file mode 100644
index 0000000..8a36eed
--- /dev/null
+++ b/o3d/samples/io/actors/mover.js
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview This file defines the Mover class.
+ */
+
+/**
+ * A Horizontal Floater.
+ */
+function Mover(initObj) {
+ this.absorbNamedValues(initObj);
+}
+Mover.prototype = new Actor;
+
+Mover.prototype.onTick = function(timeElapsed) {
+ this.z += 1 * 20 * timeElapsed;
+ updateActor(this);
+}
diff --git a/o3d/samples/io/actors/spikem.js b/o3d/samples/io/actors/spikem.js
new file mode 100644
index 0000000..e056c98
--- /dev/null
+++ b/o3d/samples/io/actors/spikem.js
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview This file defines the Spikem class.
+ */
+
+/**
+ * A Horizontal Floater.
+ */
+function Spikem(initObj) {
+ this.absorbNamedValues(initObj);
+ this.width = 24;
+ this.height = 55;
+ this.velX = -200;
+ this.velZ = 0;
+ this.isDead = false;
+ this.isHit = false;
+ this.pauseFrames = 0;
+ this.frameName = "spinning"
+}
+Spikem.prototype = new Actor;
+
+Spikem.prototype.onTick = function(timeElapsed) {
+ if (this.isDead == true) {
+ return;
+ }
+
+ if (this.isHit == true) {
+ if (this.z < -1000) {
+ isDead = true;
+ } else {
+ this.velX = this.velX*.9;
+ // Here's how I move. moveMapX is a handy function that updates both
+ // my "virtual 2d world" mapX, as well as my literal x + y values
+ this.z -= 20;
+ this.moveMapX(this.velX * timeElapsed)
+ }
+ } else {
+ // I move based off of the platform that I'm on. So get that now.
+ var myPlatform = world.platforms[this.platformID];
+
+ // I stay on my platform
+ if (this.mapX - this.width/2 < myPlatform.left.mapX
+ && this.velX < 0) {
+ this.velX *= -1;
+ } else if (this.mapX + this.width/2 > myPlatform.right.mapX
+ && this.velX > 0) {
+ this.velX *= -1;
+ }
+
+ this.rotZ += this.velX / 60 * timeElapsed;
+
+ if (Math.abs(this.velX) < .1) {
+ if (Math.random() > .5) {
+ this.velX = -400;
+ } else {
+ this.velX = 400;
+ }
+ this.pauseFrames = Math.random() * 0.5 + 1;
+ }
+
+ if (this.pauseFrames > 0) {
+ this.frameName = "spinning"
+ this.pauseFrames -= timeElapsed;
+ } else {
+ this.frameName = "charging"
+ this.velX = this.velX*.9;
+ // Here's how I move. moveMapX is a handy function that updates both
+ // my "virtual 2d world" mapX, as well as my literal x + y values
+ this.moveMapX(this.velX * timeElapsed)
+ }
+
+ if (this.isHitBySword()) {
+ this.isHit = true;
+ soundPlayer.play('sound/_SMASH.mp3', 100);
+ this.velX = 0;
+ } else if (this.isHitByArrow()) {
+ top.arrowActor.hide();
+ this.isHit = true;
+ soundPlayer.play('sound/_SMASH.mp3', 100);
+ this.velX = top.arrowActor.velX;
+ } else if (this.collidesWith(avatar)) {
+ // Play an event sound @100% volume, 0 repeats
+ soundPlayer.play('sound/ah.mp3', 100);
+
+ this.velZ = 0;
+ if (avatar.velX < 1) {
+ avatar.velX = this.velX * 7;
+ } else {
+ avatar.velX = avatar.velX * -7;
+ }
+ }
+ }
+
+ updateActor(this);
+}
diff --git a/o3d/samples/io/actors/verticalpad.js b/o3d/samples/io/actors/verticalpad.js
new file mode 100644
index 0000000..fd90425
--- /dev/null
+++ b/o3d/samples/io/actors/verticalpad.js
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview This file defines the VerticalPad class.
+ */
+
+/**
+ * A Vertical Pad you can run on. These things oscillate between their starting
+ * position and a z of 350"
+ */
+function VerticalPad(initObj) {
+ this.absorbNamedValues(initObj);
+ this.maxSpeed = 4 * 20;
+ this.moveAmount = 4 * 20;
+ this.bottomZ = this.z;
+ this.topZ = 350;
+ this.width = 42;
+ this.height = 10;
+}
+VerticalPad.prototype = new Actor;
+
+VerticalPad.prototype.onTick = function(timeElapsed) {
+ // I bounce back and forth between the left and right points on my platform.
+ if (this.z < this.bottomZ) {
+ this.moveAmount += 1;
+ } else if (this.z > this.topZ) {
+ this.moveAmount -= 1;
+ } else if (this.moveAmount >= 0) {
+ this.moveAmount = this.maxSpeed;
+ } else {
+ this.moveAmount = -this.maxSpeed;
+ }
+
+ // I match my rotation to that of my platform.
+ var myPlatform = world.platforms[this.platformID];
+ this.rotZ = myPlatform.rotZ;
+
+
+ this.z += this.moveAmount * timeElapsed;
+
+ // If I collide with the avatar, then move the avatar along with me,
+ // and set his "override" groundZ to be my own Z.
+ if (this.collidesWith(avatar)) {
+ if (avatar.velZ <= 0 && avatar.z >= this.z - 45) {
+ avatar.z = this.z
+ if (this.moveAmount < 0) {
+ avatar.z += this.moveAmount * timeElapsed;
+ }
+ avatar.groundZ = avatar.z;
+ }
+ }
+
+ updateActor(this);
+}
diff --git a/o3d/samples/io/autoincludes.js b/o3d/samples/io/autoincludes.js
new file mode 100644
index 0000000..be2163f
--- /dev/null
+++ b/o3d/samples/io/autoincludes.js
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/**
+ * This file was auto-generated by a SketchUp ruby script. Include this in your
+ * game and everything else will load right in.
+ *
+ * WARNING: This file will be overwritten when you publish a new level from
+ * SketchUp, so if you wan to manually modify it, you've been warned. :)
+ */
+document.write('<script type="text/javascript" src="actors/actor.js"></script>');
+document.write('<script type="text/javascript" src="actors/arrow.js"></script>');
+document.write('<script type="text/javascript" src="actors/avatar.js"></script>');
+document.write('<script type="text/javascript" src="actors/coin.js"></script>');
+document.write('<script type="text/javascript" src="actors/horizontalpad.js"></script>');
+document.write('<script type="text/javascript" src="actors/mover.js"></script>');
+document.write('<script type="text/javascript" src="actors/spikem.js"></script>');
+document.write('<script type="text/javascript" src="actors/verticalpad.js"></script>');
+
+document.write('<script type="text/javascript" src="levels/all_actors.js"></script>');
+document.write('<script type="text/javascript" src="levels/map1.js"></script>');
diff --git a/o3d/samples/io/cutscenes.js b/o3d/samples/io/cutscenes.js
new file mode 100644
index 0000000..376a7845
--- /dev/null
+++ b/o3d/samples/io/cutscenes.js
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview This file isn't important to the actual game. It just runs
+ * pretty animations outside the o3d window.
+ */
+
+/**
+ * "Opens" the cover. This thing calls itself again and again until it's done.
+ * @param {number} lastPercent Number from 0 to 100 representing how "done"
+ */
+function animateCover(lastPercent) {
+ // Move 10% more toward a 100% animation
+ lastPercent = ifEmpty(lastPercent,0);
+ lastPercent = lastPercent + 10;
+
+ // Play a nice sound.
+ if (lastPercent == 10) {
+ soundPlayer.play('sound/page.mp3', 100);
+ $('innercover-div').style.width = $('book-left').offsetWidth;
+ $('book-left').style.width = $('book-left').offsetWidth;
+ }
+
+ // Transform the cover graphic from "closed" to "open." If we're more than
+ // 50% along the way, then this cover gets hidden.
+ var cover = $('cover')
+ var innerCover = $('innercover')
+
+ var factor = Math.abs(Math.cos(lastPercent/50*Math.PI/2));
+ if (lastPercent < 50){
+ cover.style.width = factor * 1000;
+ cover.style.height = 600;
+ } else {
+ cover.visibility = 'hidden';
+ cover.style.width = 1;
+ innerCover.style.width = factor * 1000;
+ innerCover.style.height = 600;
+ }
+
+ var shadow = $('cover-shadow');
+ if (lastPercent <= 70) {
+ factor = Math.abs(Math.cos(lastPercent/70*Math.PI/2));
+ shadow.style.width = factor * 1000;
+ shadow.style.height = 600;
+ shadow.style.opacity = (70 - lastPercent)/70;
+ }
+
+ if (lastPercent < 100) {
+ setTimeout('animateCover(' + lastPercent + ')',100);
+ } else {
+ shadow.style.visibility = 'hidden';
+ }
+}
+
+
+/**
+ * "Opens" a page. This thing calls itself again and again until it's done.
+ * @param {string} id HTML element ID of the page image that we're animating.
+ * @param {number} lastPercent Number from 0 to 100 representing how "done"
+ */
+function animatePage(id, lastPercent) {
+ // Transform the page graphic from "closed" to "open." If we're more than
+ // 50% along the way, then this cover gets hidden.
+ var page = $(id)
+ page.style.zIndex = 200;
+ lastPercent = ifEmpty(lastPercent,0);
+
+ // if we've already animated this page... don't do it again.
+ if (parseInt(page.style.width) < 900 && lastPercent == 0) {
+ return;
+ }
+
+ // Move 10% more toward a 100% animation
+ lastPercent = lastPercent + 10;
+
+ // Play a nice sound.
+ if (lastPercent == 10) {
+ soundPlayer.play('sound/page.mp3', 100);
+ }
+
+ var factor = Math.abs(Math.cos(lastPercent/50*Math.PI/2));
+ if (lastPercent < 50) {
+ page.style.width = factor * 951;
+ page.style.height = 549;
+ } else {
+ page.visibility = 'hidden';
+ page.style.width = 1;
+ }
+
+ var shadow = $('cover-shadow')
+ var coverDiv = $('cover-div')
+
+ if (lastPercent <= 70){
+ coverDiv.style.zIndex = 99;
+ factor = Math.abs(Math.cos(lastPercent/70*Math.PI/2));
+ shadow.style.width = factor * 1000;
+ shadow.style.height = 600;
+ shadow.style.opacity = (70 - lastPercent)/70;
+ shadow.style.visibility = 'visible';
+ }
+
+ // Fade in a bit for the start of the animated shadow.
+ if (lastPercent <= 20) {
+ shadow.style.opacity = (lastPercent/30);
+ }
+
+ if (lastPercent < 100) {
+ setTimeout('animatePage("' + id + '",' + lastPercent + ')',100);
+ } else {
+ shadow.style.visibility = 'hidden';
+ if (id == "page2") {
+ // We'll fire the animation of page 3 after 2 seconds.
+ setTimeout('animatePage("page3")',2000);
+ } else if (id == "page3") {
+ loadLevel(0);
+ }
+ }
+}
diff --git a/o3d/samples/io/dynamic_lights.js b/o3d/samples/io/dynamic_lights.js
new file mode 100644
index 0000000..9a5b1f9
--- /dev/null
+++ b/o3d/samples/io/dynamic_lights.js
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview Manage all the dynamic lights in a level.
+ */
+
+
+var s_light_array = new Array();
+var s_number_of_lights_in_scene = 0;
+
+var s_number_of_lights_in_program = 0;
+var s_light_parameter_array = new Array();
+
+// Call this before any UpdateLightsInProgram.
+function InitializeLightParameters(context, number_of_lights) {
+ s_number_of_lights_in_program = number_of_lights;
+ for (var l = 0; l < number_of_lights; ++l) {
+ s_light_parameter_array[l] = {};
+ s_light_parameter_array[l].location = context.createParam(
+ 'light' + l + '_location', 'ParamFloat3');
+ s_light_parameter_array[l].location.value = [0, 0, 0];
+
+ // For the light, the final color parameter is the attentuation.
+ s_light_parameter_array[l].color = context.createParam(
+ 'light' + l + '_color', 'ParamFloat4');
+ s_light_parameter_array[l].color.value = [0, 0, 0, 1];
+ }
+}
+
+// Returns the index of the new light for future manipulation.
+// World location and color should be arrays.
+// These will be assigned to Param objects.
+function AddLight(world_location, color) {
+ var light_index = s_number_of_lights_in_scene++;
+ s_light_array[light_index] = {};
+ s_light_array[light_index].location = world_location;
+ s_light_array[light_index].color = color;
+ return light_index;
+}
+
+// Sets the shader parameters to render using the closest lights
+// to the 'focus' (whatever's passed in).
+// |focus_location| must provide .x, .y, and .z for determining the
+// distance to each light.
+function UpdateLightsInProgram(focus_location) {
+ // TODO: Modulate the lights' color / add behaviors for the lights.
+ var lights_to_render = new Array();
+ for (var i = 0; i < s_number_of_lights_in_program; ++i) {
+ lights_to_render[i] = {};
+ lights_to_render[i].distance = 10000000000000.0; // Arbitrary large number.
+ lights_to_render[i].index = -1;
+ }
+ var number_of_lights = s_number_of_lights_in_scene;
+ for (var l = 0; l < number_of_lights; ++l) {
+ var x_diff = s_light_array[l].location.x - focus_location.x;
+ var y_diff = s_light_array[l].location.y - focus_location.y;
+ // TODO: This should be focus_location.z, but the avatar's location that is
+ // passed in is offset from the world coordinates. For our relatively flat
+ // levels, this works more predictably.
+ var z_diff = s_light_array[l].location.z - 0;
+ var distance_to_focus = x_diff * x_diff + y_diff * y_diff + z_diff * z_diff;
+ // This may change if we assign to an entry early in the list.
+ var index_to_assign = l;
+ for (var i = 0; i < s_number_of_lights_in_program; ++i) {
+ if (distance_to_focus < lights_to_render[i].distance) {
+ // Swap the index into this entry. We will percolate the
+ // light up.
+ var replaced_index = lights_to_render[i].index;
+ lights_to_render[i].index = index_to_assign;
+ index_to_assign = replaced_index;
+
+ var replaced_distance = lights_to_render[i].distance;
+ lights_to_render[i].distance = distance_to_focus;
+ distance_to_focus = replaced_distance;
+ }
+ if (index_to_assign < 0) {
+ break;
+ }
+ }
+ }
+
+ // Finally, assign to the actual shader parameters.
+ for (var i = 0; i < s_number_of_lights_in_program; ++i) {
+ var light_index = lights_to_render[i].index;
+ if (light_index >= 0) {
+ s_light_parameter_array[i].location.value =
+ s_light_array[light_index].location;
+ s_light_parameter_array[i].color.value =
+ s_light_array[light_index].color;
+ }
+ }
+}
+
diff --git a/o3d/samples/io/editor.html b/o3d/samples/io/editor.html
new file mode 100644
index 0000000..a212e58
--- /dev/null
+++ b/o3d/samples/io/editor.html
@@ -0,0 +1,126 @@
+<!--
+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.
+-->
+
+<html>
+<head>
+ <title>Level Editor - Don't open this is a browser.
+ It's only good inside a SketchUp WebDialog</title>
+ <script type="text/javascript" src="init.js"></script>
+ <script type="text/javascript" src="autoincludes.js"></script>
+ <script type="text/javascript" src="gamelogic.js"></script>
+ <script type="text/javascript" src="sound/soundplayer.js"></script>
+
+<script>
+function parseWorld() {
+ url = 'skp:parse_world';
+ window.location.href = url;
+}
+
+function play() {
+ $('play-button').disabled = false;
+ $('pause-button').disabled = true;
+
+ url = 'skp:do_play@';
+ window.location.href = url;
+
+}
+
+function pause() {
+
+ $('play-button').disabled = false;
+ $('pause-button').disabled = true;
+ clearTimeout(timerID)
+}
+
+function save() {
+ url = 'skp:do_save@';
+ window.location.href = url;
+}
+
+function startNew() {
+ name = prompt("What do you want to call your new level?\n" +
+ "(Choose wisely... you can't rename yet.)","My First Level");
+ url = 'skp:do_new@';
+ url += 'name=' + name;
+ window.location.href = url;
+ $('export-button').disabled = false;
+ $('play-button').disabled = false;
+}
+
+function setWorldFromName(name) {
+ output.innerHTML += '<script type="text/javascript" src="autoincludes.js"><' + '/script>';
+ for (i=0;i<levels.length; i++) {
+ //alert('looking at ' + levels[i].colladaFile);
+ if (levels[i].colladaFile == name + '.o3dtgz') {
+ world = levels[i];
+ avatar = levels[i].actors[0];
+ nextFrame();
+ $('pause-button').disabled = false;
+ $('play-button').disabled = true;
+ break;
+ }
+ }
+
+}
+
+</script>
+</head>
+<style>
+A { font-family: sans-serif; text-decoration: none; }
+A:link { color: yellow; }
+A:visited { color: yellow; }
+A:active { color: yellow; }
+A:hover { color: yellow; }
+BODY { font-family: sans-serif; }
+INPUT { width: 100%; text-align: left; padding-left: 6px; margin-top: 3px;}
+.head { background-color: black; color: gold; font-weight: bold; padding: 6px; }
+.levellink {
+ color: blue;
+ text-decoration: underline;
+ cursor: pointer;
+
+}
+</style>
+<body style="background-color:threedface;" onload="init()">
+ <div class="head">Select an action...</div>
+ <input type="button" onclick="startNew()" value="Start a new level from a template">
+ <input id="export-button" type="button" onclick="save()" disabled="true" value="Save this file and export to O3D">
+ <input id="play-button" type="button" disabled="true" onclick="play();" value="Play the level inside SketchUp">
+ <input id="pause-button" type="button" disabled="true" onclick="pause();" value="Pause playback">
+
+ <br><div class="head">Or select an existing level to load...</div>
+
+ <span id="content">List...</span>
+
+ <span id="output"></span>
+</body>
+</html>
+
diff --git a/o3d/samples/io/gamelogic.js b/o3d/samples/io/gamelogic.js
new file mode 100644
index 0000000..65f5ff6
--- /dev/null
+++ b/o3d/samples/io/gamelogic.js
@@ -0,0 +1,578 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview This file sets up the game state JS structures, sets up
+ * keyboard handlers, and contains the main game loop.
+ */
+
+ /**
+ * Global constants that drive the game engine.
+ */
+var FRAMES_PER_SECOND = 20; // Change for a faster or slower game.
+var FRAME_DELAY = 1000 / FRAMES_PER_SECOND; // Milliseconds between frames.
+var GRAVITY = -2000; // Inches per second per second.
+var JUMP_VELOCITY = 650;
+var RUN_VELOCITY = 200;
+var WORLD_ANGLE = 0;
+var CAMERA_SOFTNESS = 15;
+
+
+/**
+ * These are some global pointers that we'll use for to point at our world
+ * object (aka "current map" or "current level"), and our happy avatar (aka
+ * the protagonist, Prince Io.)
+ */
+var world;
+var avatar;
+
+/**
+ * Keyboard constants.
+ */
+var BACKSPACE = 8;
+var TAB = 9;
+var ENTER = 13;
+var SHIFT = 16;
+var CTRL = 17;
+var ALT = 18;
+var ESCAPE = 27;
+var PAGEUP = 33;
+var PAGEDOWN = 34;
+var END = 35;
+var HOME = 36;
+var LEFT = 37;
+var UP = 38;
+var RIGHT = 39;
+var DOWN = 40;
+var DELETE = 46;
+var SPACE = 32;
+
+/**
+ * These variables are special SketchUp constants that aren't really constant.
+ * They are updated by SketchUp every frame to indicate what's around the
+ * avatar.
+ * TODO: ADDENDUM! These vars used to be "special constants,"
+ * but now they're leftovers of a time when SU was the main engine, and the
+ * game logic below should be cleaned up so we're not using all caps on these.
+ */
+var GROUNDZ; // Absolute Z of the obstacle beneath the avatar.
+var OBSTACLE_LEFT; // Distance to nearest obstacle to the left.
+var OBSTACLE_RIGHT; // Distance to nearest obstacle on the right.
+
+/**
+ * Camera position stuff.
+ * TODO: These are redundant vs. the camera.eye.x stuff in
+ * init.js. Clean that outa thar!
+ */
+var eyeX = 0;
+var eyeY = -1000;
+var eyeZ = 1000;
+var targetX = 0;
+var targetY = 0;
+var targetZ = 0;
+
+/**
+ * If the user presses the swing button while we're showing a swing, then we'll
+ * mark the fact that we need to immediately swing again once the current
+ * animation is done.
+ */
+var swingAgain = false;
+
+/**
+ * Way of determining that the user just pressed then unpressed certain keys.
+ */
+var upWasJustDown = false;
+var ctrlWasJustUp = false;
+
+/**
+ * Identifier for our global game timer. This is only used when SketchUp is the
+ * main CG engine.
+ */
+var timerID;
+
+/**
+ * Code to keep track of the current key state. Since these events can fire at
+ * any time but we only want to apply changes to our game state at the start of
+ * each game loop, we do this trick so that the nextFrame() function can poll
+ * the keyIsDown data structure to determine what's happened since the last
+ * frame.
+ */
+var keyIsDown = {};
+
+function keyMessage(e, state) {
+ keyIsDown[o3djs.event.getEventKeyChar(e ? e : window.event)] = state;
+}
+
+document.onkeydown = function(e) { keyMessage(e, true); };
+
+document.onkeyup = function(e) { keyMessage(e, false); };
+
+
+/**
+ * Main Game Loop.... Here's where we actually run the game.
+ * @param {number} elapsedTime Number of seconds since we were last called.
+ */
+function nextFrame(elapsedTime) {
+ // First, let's look at our avatar. If he's jumping, then figure out which
+ // platform (if any) he's currently over.
+ if (avatar.isJumping) {
+ var lowestZFound = -5000;
+ for (var i = 0; i < world.platforms.length; i++) {
+ platform = world.platforms[i];
+ if (platform.parentID == avatar.parentPlatformID ||
+ i == avatar.parentPlatformID) {
+ if (avatar.z > platform.z &&
+ avatar.mapX > platform.left.mapX &&
+ avatar.mapX < platform.right.mapX &&
+ platform.z > lowestZFound && platform.isNotSolid != true) {
+ lowestZFound = world.platforms[i].z
+ avatar.platformID = i;
+ }
+ }
+ }
+ }
+
+ // Create a myPlatform variable for convenience.
+ var myPlatform = world.platforms[avatar.platformID]
+
+ // Platforms without a parentID aren't really platforms. The actually define
+ // the "world path" that meanders through our level. Therefore, if the only
+ // platform that Io is over is one of these, then our current GROUNDZ (aka
+ // the nearest walkable altitude),
+ if (exists(myPlatform.parentID)) {
+ GROUNDZ = myPlatform.z
+ avatar.parentPlatformID = myPlatform.parentID;
+ } else {
+ GROUNDZ = -5000;
+ avatar.parentPlatformID = avatar.platformID;
+ }
+
+ // The avatar's mapX is really important. It defines his position in the
+ // imaginary 2d platformer that we weave through a 3D world. When he's at
+ // mapX of 0, he's at the far left of the level (think super mario.) As
+ // he proceeds through the level, his mapX will get bigger. Meanwhile, his
+ // actual x, y, and z (aka altitude) values will be kept track of as well.
+ // Anyway, every platform that Io can stand on has a "left" and a "right"
+ // to them. Let's check to see if we've walked off of it...
+ if (avatar.mapX < myPlatform.left.mapX) {
+ // Whoa! We've walked off the left of our platform! If there's an adjacent
+ // platform to step onto, then do that. Otherwise, it's fallin' time.
+ if (exists(myPlatform.left.adjacentID)) {
+ // Do some math to ensure that our actual x and y values are corrected
+ // so Io stays perfectly in our "world path" plane.
+ oldPlatform = myPlatform;
+ overshot = avatar.mapX - myPlatform.left.mapX;
+ avatar.platformID = myPlatform.left.adjacentID;
+ myPlatform = world.platforms[avatar.platformID];
+ avatar.x -= Math.cos(oldPlatform.rotZ) * overshot;
+ avatar.y -= Math.sin(oldPlatform.rotZ) * overshot;
+ avatar.x += Math.cos(myPlatform.rotZ) * overshot;
+ avatar.y += Math.sin(myPlatform.rotZ) * overshot;
+ } else {
+ GROUNDZ = -5000;
+ }
+ } else if (avatar.mapX > myPlatform.right.mapX) {
+ // Whoa! We've walked off the right of our platform!
+ if (exists(myPlatform.right.adjacentID)) {
+ oldPlatform = myPlatform;
+ overshot = avatar.mapX - myPlatform.right.mapX;
+ avatar.platformID = myPlatform.right.adjacentID;
+ myPlatform = world.platforms[avatar.platformID];
+ avatar.x -= Math.cos(oldPlatform.rotZ) * overshot;
+ avatar.y -= Math.sin(oldPlatform.rotZ) * overshot;
+ avatar.x += Math.cos(myPlatform.rotZ) * overshot;
+ avatar.y += Math.sin(myPlatform.rotZ) * overshot;
+ } else {
+ GROUNDZ = -5000;
+ }
+ }
+
+ // Now it's time to figure out if there's a "obstacle" nearby. Each platform
+ // can potentially have a left.obstacleHeight and/or a right.obstableHeight.
+ // We'll store how close any of them are in these OBSTABLE_LEFT type
+ // "constants."
+ OBSTACLE_RIGHT = 9000
+ OBSTACLE_RIGHT_HEIGHT = 0
+ OBSTACLE_LEFT = 9000
+ OBSTACLE_LEFT_HEIGHT = 0
+
+ if (myPlatform.right.obstacleHeight > 0) {
+ OBSTACLE_RIGHT = myPlatform.right.mapX - avatar.mapX;
+ OBSTACLE_RIGHT_HEIGHT = myPlatform.right.obstacleHeight - avatar.velZ + 20;
+ }
+ if (myPlatform.left.obstacleHeight > 0) {
+ OBSTACLE_LEFT = avatar.mapX - myPlatform.left.mapX;
+ OBSTACLE_LEFT_HEIGHT = myPlatform.left.obstacleHeight - avatar.velZ + 20;
+ }
+
+ // So... now that we've figured all of that stuff out, let's store how
+ // far *above* the current platform Io is.
+ avatar.relativeZ = avatar.z - myPlatform.z;
+
+ // This special variable, avatar.groundZ, can be set by moving
+ // platforms and other actors to override our actual groundZ. This allows
+ // the avatar to "float" in space (or really, to stand on stuff that's
+ // not a static platform but a moving one.) So if we find that variable,
+ // it trumps the calculated GROUNDZ. However, we *always* clear that
+ // variable out after using it. It's up to the Actor who is moving Io to
+ // keep this updated inside their onTick event. (See horizontalpad.js for
+ // an example of this.)
+ if (exists(avatar.groundZ)) {
+ GROUNDZ = avatar.groundZ;
+ avatar.groundZ = undefined;
+ }
+
+ // Gah. Another one of our "special constants" that used to be updated
+ // by SketchUp but now is done via JS data structures.
+ // TODO: Clean 'tup.
+ WORLD_ANGLE = myPlatform.rotZ;
+
+ // Check for keyboard stuff.
+ handleInput();
+
+ // Handle falling and gravity.
+ avatar.z += avatar.velZ * elapsedTime;
+ if (avatar.z - GROUNDZ > 1) {
+ avatar.isJumping = true;
+ } else {
+ if (avatar.isJumping == true) {
+ soundPlayer.play('sound/step2.mp3', 100);
+ }
+ avatar.isJumping = false;
+ }
+ if (avatar.isJumping == true) {
+ avatar.velZ += GRAVITY * elapsedTime;
+ }
+ if (avatar.z < GROUNDZ) {
+ avatar.velZ = 0;
+ avatar.z = GROUNDZ + .1;
+ avatar.isJumping = false;
+ avatar.animation = 'Hero_Run';
+
+ }
+ if (avatar.z < -1000) {
+ avatar.x = 0;
+ avatar.y = 0;
+ avatar.z = 200;
+ avatar.mapX = 0;
+ avatar.platformID = 0;
+ avatar.parentPlatformID = 0;
+ }
+
+ // Handle collision with things to the left and right of our avatar.
+ // From here is where we start to decide which animation cycle we're on.
+ // Now you can see how we're using avatar.relativeZ along with our
+ // OBSTACLE_FOO "special constants" to determine not only if we've hit an
+ // obstacle, but whether we've jumped high enough to get over it.
+ if (OBSTACLE_LEFT < 25 && keyIsDown[LEFT] &&
+ OBSTACLE_LEFT_HEIGHT > avatar.relativeZ) {
+ avatar.targetVelX = 0;
+ avatar.animation = 'Hero_Stand';
+ avatar.frame = 1;
+ }
+ if (OBSTACLE_RIGHT < 25 && keyIsDown[RIGHT] &&
+ OBSTACLE_RIGHT_HEIGHT > avatar.relativeZ) {
+ avatar.targetVelX = 0;
+ avatar.animation = 'Hero_Stand';
+ avatar.frame = 1;
+ }
+
+ // If we're jumping, then use the jumping animation cycle.
+ if (avatar.isJumping == true) {
+ avatar.animation = 'Hero_Jump';
+ if (avatar.velZ > 0) {
+ avatar.frame += elapsedTime * 20;
+ if (avatar.frame > 3) {
+ avatar.frame = 3;
+ }
+ } else {
+ if (avatar.z > GROUNDZ + 20) {
+ avatar.frame = 4;
+ } else {
+ avatar.frame = 5;
+ }
+ }
+ }
+
+ // Figure out which frame to display inside our current cycle.
+ didSwordStrike = '0';
+ if (avatar.animation == 'Hero_Run') {
+ avatar.frame += elapsedTime * 20;
+ if (avatar.frame > 10) {
+ avatar.frame = 1;
+ }
+ if (Math.floor(avatar.frame % 5) == 0) {
+ var soundToPlay = 'sound/step'
+ soundToPlay += (Math.floor(Math.random() * 3) + 1);
+ soundToPlay += '.mp3'
+ soundPlayer.play(soundToPlay, 100);
+ }
+ } else if (avatar.animation == 'Hero_Sword') {
+ avatar.targetVelX = 0;
+ avatar.framesSinceShot = 0;
+ avatar.frame += avatar.swordRate * 20 * elapsedTime;
+ if (avatar.frame < 1) {
+ avatar.animation = 'Hero_Stand'
+ avatar.frame = 1;
+ } else if (avatar.frame > 7) {
+ avatar.swordRate = -.5;
+ avatar.frame = 6.2;
+ didSwordStrike = '1';
+ } else if (avatar.frame == 3 && avatar.swordRate < 0) {
+ if (swingAgain == true) {
+ avatar.swordRate = 1;
+ swingAgain = false;
+ } else {
+ avatar.swordRate = -.5;
+ }
+ }
+
+ if (avatar.frame == 3 && avatar.swordRate > 0) {
+ soundPlayer.play('sound/_MISS.mp3', 100);
+ }
+ }
+
+ // Update our position.
+ avatar.velX = (avatar.velX + avatar.targetVelX + avatar.targetVelX) / 3;
+ if (Math.abs(avatar.velX) < .2) {
+ avatar.velX = 0;
+ }
+ avatar.mapX += avatar.velX * elapsedTime;
+ avatar.x += avatar.velX * Math.cos(WORLD_ANGLE) * elapsedTime;
+ avatar.y += avatar.velX * Math.sin(WORLD_ANGLE) * elapsedTime;
+ avatar.rotZ = (avatar.rotZ + avatar.targetRotZ + avatar.targetRotZ) / 3;
+
+ // Calculate our final frameName string to pass to SketchUp (or o3d).
+ frameName = avatar.animation;
+ if (avatar.frame < 10) {
+ frameName += '0';
+ }
+ frameName += Math.floor(avatar.frame);
+ if (avatar.framesSinceShot > 0) {
+ frameName += 'Shoot';
+ avatar.framesSinceShot--;
+ }
+ if (avatar.framesSinceShot == 3) {
+ // TODO: Make this work with multiple arrows, perform
+ // better, and be smart enough to handle level reloads.
+ if (top.arrowActor == undefined) {
+ for (var actorID = 0; actorID < world.actors.length; actorID++) {
+ arrow = world.actors[actorID];
+ if (arrow.name.indexOf('Arrow') == 0) {
+ top.arrowActor = arrow;
+ top.arrowActor.shoot();
+ }
+ }
+ } else {
+ top.arrowActor.shoot();
+ }
+ }
+ avatar.frameName = frameName;
+
+ // Here's where we send our state down to SketchUp or O3D.
+ // Always do our avatar last, since he's the one likely to have
+ // been modified by other things in the environment. (Our avatar
+ // is guaranteed by the level exporter to be in world.actors[0])
+ for (i = world.actors.length - 1; i >= 0; i--) {
+ world.actors[i].onTick(elapsedTime);
+ }
+
+ // Now move the camera in a pleasing motion to float over Io's
+ // right shoulder. (Well, it's his right shoulder when he's
+ // facing "right" toward the end of the level.)
+ newEyeX = avatar.x + 350 * Math.sin(WORLD_ANGLE);
+ newEyeY = avatar.y - 350 * Math.cos(WORLD_ANGLE);
+ newEyeZ = avatar.z + 150;
+ eyeX = (newEyeX + eyeX * CAMERA_SOFTNESS) / (CAMERA_SOFTNESS + 1);
+ eyeY = (newEyeY + eyeY * CAMERA_SOFTNESS) / (CAMERA_SOFTNESS + 1);
+ eyeZ = (newEyeZ + eyeZ * CAMERA_SOFTNESS) / (CAMERA_SOFTNESS + 1);
+ targetX = (avatar.x + targetX) / 2;
+ targetY = (avatar.y + targetY) / 2;
+ targetZ = (avatar.z + 200 + targetZ * 3) / 5;
+
+ // Here's where we send our camera down to SketchUp or O3D.
+ updateCamera(targetX, targetY, targetZ, eyeX, eyeY, eyeZ)
+
+ // If we're running inside SketchUp, clear out our old timer and set a new
+ // one.
+ if (isSU) {
+ clearTimeout(timerID);
+ timerID = self.setTimeout('nextFrame()', FRAME_DELAY);
+ }
+}
+
+
+/**
+ * Sends our state to our render engine. (See knightgame.rb for the Sketchup
+ * ruby handler.)
+ * @param {Object} actor An instance of an Actor object.
+ */
+function updateActor(actor) {
+ var frameName = actor.frameName;
+ var x = actor.x;
+ var y = actor.y;
+ var z = actor.z;
+ var rotZ = actor.rotZ;
+
+ // Sending stuff to SU vs. to O3D.
+ if (isSU == true) {
+ url = 'skp:push_frame_js@';
+ url += 'name=' + actor.name;
+ url += '&frame=' + frameName;
+ url += '&x=' + x;
+ url += '&y=' + y;
+ url += '&z=' + z;
+ url += '&rotz=' + rotZ;
+ window.location.href = url;
+ } else {
+ // For performance reasons, we want to cache node pointers directly onto
+ // our Actor object, so we don't have to look it all up every time.
+ if (actor.nodesHaveBeenCached != true) {
+ actor.hasBeenCached = true;
+ nodes = client.getObjects(actor.colladaID, 'o3d.Transform');
+ actor.node = nodes[0];
+
+ var instance = actor.node.children[0];
+ actor.children = instance.children;
+ actor.nodesHaveBeenCached = true;
+ }
+
+ var m = math.matrix4.rotationZYX([0, rotZ, 0]);
+ math.matrix4.setTranslation(m, [x, z, -y]);
+ actor.node.localMatrix = m;
+
+ if (!isEmpty(frameName)) {
+ for (var c = 0; c < actor.children.length; c++) {
+ var child = actor.children[c];
+ child_name = child.name;
+ child.visible = (child_name == frameName ||
+ child_name == frameName + '1' ||
+ child_name == frameName + '_1');
+ }
+ }
+ }
+}
+
+/**
+ * Sends our state down to SketchUp or o3d. (See knightgame.rb for the handler.)
+ * @param {number} targetX Where we want the camera to point at.
+ * @param {number} targetY Where we want the camera to point at.
+ * @param {number} targetZ Where we want the camera to point at.
+ * @param {number} eyeX Where we want the camera to point from.
+ * @param {number} eyeY Where we want the camera to point from.
+ * @param {number} eyeZ Where we want the camera to point from.
+ */
+function updateCamera(targetX, targetY, targetZ, eyeX, eyeY, eyeZ) {
+ if (isSU == true) {
+ url = 'skp:push_camera@';
+ url += 'targetX=' + targetX;
+ url += '&targetY=' + targetY;
+ url += '&targetZ=' + targetZ;
+ url += '&eyeX=' + eyeX;
+ url += '&eyeY=' + eyeY;
+ url += '&eyeZ=' + eyeZ;
+ window.location.href = url;
+ } else {
+ var target = [targetX, targetZ, -targetY];
+ var eye = [eyeX, eyeZ, -eyeY];
+ var up = [0, 1, 0];
+ var view_matrix = math.matrix4.lookAt(eye, target, up);
+
+ drawContext.view = view_matrix;
+
+ // !lacz modified!
+ camera_eye_param.value = eye;
+ camera_target_param.value = target;
+ }
+}
+
+/**
+ * Checks for keyboard stuff.
+ */
+function handleInput() {
+ if (keyIsDown[SPACE]) {
+ avatar.framesSinceShot = 5;
+ }
+
+ if (keyIsDown[DOWN]) {
+ if (avatar.animation == 'Hero_Sword') {
+ if (ctrlWasJustUp == true) {
+ swingAgain = true;
+ }
+ } else {
+ avatar.animation = 'Hero_Sword';
+ avatar.frame = 1;
+ avatar.swordRate = 1;
+ ctrlWasJustUp = false;
+ }
+ } else {
+ ctrlWasJustUp = true;
+ }
+
+ if (keyIsDown[UP] && avatar.isJumping != true && upWasJustDown == false) {
+ avatar.velZ = JUMP_VELOCITY;
+ avatar.isJumping = true;
+ upWasJustDown = true;
+ }
+ if (keyIsDown[UP]) {
+ upWasJustDown = true;
+ } else {
+ upWasJustDown = false;
+ }
+
+ if (keyIsDown[RIGHT] || keyIsDown[LEFT]) {
+ if (avatar.animation == 'Hero_Stand' && avatar.frame == 1) {
+ avatar.frame = 2;
+ } else if (avatar.animation == 'Hero_Stand' && avatar.frame == 2) {
+ avatar.animation = 'Hero_Run';
+ avatar.frame = 1;
+ }
+
+ } else {
+ if (avatar.animation == 'Hero_Run') {
+ avatar.animation = 'Hero_Stand';
+ avatar.frame = 2;
+ } else if (avatar.animation == 'Hero_Stand' && avatar.frame == 2) {
+ avatar.frame = 1;
+ }
+ }
+
+ if (keyIsDown[RIGHT]) {
+ avatar.targetVelX = RUN_VELOCITY;
+ avatar.targetRotZ = WORLD_ANGLE;
+ } else if (keyIsDown[LEFT]) {
+ avatar.targetVelX = -RUN_VELOCITY;
+ avatar.targetRotZ = -(Math.PI) + WORLD_ANGLE;
+ } else {
+ avatar.targetVelX = 0;
+ }
+}
diff --git a/o3d/samples/io/init.js b/o3d/samples/io/init.js
new file mode 100644
index 0000000..e6c145f
--- /dev/null
+++ b/o3d/samples/io/init.js
@@ -0,0 +1,395 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview This file creates all of the global o3d stuff that
+ * establishes the plugin window, sets its size, creates necessary light
+ * and camera parameters, and stuff like that.
+ */
+o3djs.require('o3djs.util');
+o3djs.require('O3D.math');
+o3djs.require('o3djs.rendergraph');
+o3djs.require('o3djs.pack');
+o3djs.require('o3djs.scene');
+
+// Create some globals that store our main pointers to o3d objects.
+var o3d;
+var math;
+var math;
+var client;
+var pack;
+var globalParams;
+var g_viewInfo;
+var drawContext;
+var blackSampler;
+var g_loadInfo;
+
+// This variable keeps track of whether a collada file is correctly loaded.
+var isLoaded = false;
+
+// This variable, surprisingly, contains the time since the last frame
+// (in seconds)
+var timeSinceLastFrame = 0;
+var frameCount = 0;
+
+// This is only a handy data structure for storing camera information. It's not
+// actually a core O3D object.
+var camera = {
+ eye: [0, 0, 500],
+ target: [0, 0, 0]
+};
+
+/**
+ * This is a top-level switch that tells us whether we're running inside a
+ * SketchUp web dialog. (If not, then we're in O3D.)
+ * TODO : Re-enable the SketchUp web-dialog functionality, but through
+ * a check different than simply testing if we are running in IE.
+ */
+//var isSU = (navigator.appVersion.indexOf('MSIE') != -1) ? true : false;
+var isSU = false;
+
+// Some parameters to pass to the shaders as the camera moves around.
+var camera_eye_param;
+var camera_target_param;
+
+// Keep track of the lights in the level.
+var light_array;
+var max_number_of_lights = 4; // Determined from the GPU effect.
+
+/**
+ * Creates the client area.
+ */
+function init() {
+ o3djs.util.makeClients(initStep2);
+}
+
+/**
+ * Gets called at the page's onLoad event. This function sets up our plugin and
+ * level selection UI.
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function initStep2(clientElements) {
+ // Walk across all levels loaded by includes.js and show a list for the user
+ // to choose from.
+ $('content').innerHTML = 'Choose a level...<br>';
+ for (var i = 0; i < levels.length; i++) {
+ var level = levels[i];
+ var str = '<span class="levellink" onclick="loadLevel(' + i + ')">' +
+ level.name + '</span><br>'
+ $('content').innerHTML += str;
+ }
+
+ soundPlayer.play('sound/music.mp3', 100, 999);
+
+ // If we're NOT running inside SketchUp, then we need to set up our o3d
+ // window.
+ if (!isSU) {
+ var o3dElement = clientElements[0];
+ o3dElement.id = 'o3dObj';
+ o3d = o3dElement.o3d;
+ math = o3djs.math;
+ client = o3dElement.client;
+ pack = client.createPack();
+ var blackTexture = pack.createTexture2D(1, 1, o3d.Texture.XRGB8, 1, false);
+ blackTexture.set(0, [0, 0, 0]);
+ blackSampler = pack.createObject('Sampler');
+ blackSampler.texture = blackTexture;
+
+ // Create the render graph for a view.
+ g_viewInfo = o3djs.rendergraph.createBasicView(
+ pack,
+ client.root,
+ client.renderGraphRoot);
+
+ drawContext = g_viewInfo.drawContext;
+
+ var target = [0, 0, 0];
+ var eye = [0, 0, 5];
+ var up = [0, 1, 0];
+ var view_matrix = math.matrix4.lookAt(eye, target, up);
+
+ drawContext.view = view_matrix;
+
+ globalParams = pack.createObject('ParamObject');
+
+ // Initialize all the effect's required parameters.
+ var ambient_light_color_param = globalParams.createParam(
+ 'ambientLightColor',
+ 'ParamFloat4');
+ ambient_light_color_param.value = [0.27, 0.2, 0.2, 1];
+ var sunlight_direction_param = globalParams.createParam('sunlightDirection',
+ 'ParamFloat3');
+
+ // 20 degrees off.
+ sunlight_direction_param.value = [-0.34202, 0.93969262, 0.0];
+ var sunlight_color_param = globalParams.createParam('sunlightColor',
+ 'ParamFloat4');
+
+ sunlight_color_param.value = [0.55, 0.6, 0.7, 1.0];
+ // global parameter, this will change as the character moves.
+ camera_eye_param = globalParams.createParam('cameraEye', 'ParamFloat3');
+ camera_eye_param.value = eye;
+ camera_target_param = globalParams.createParam('cameraTarget',
+ 'ParamFloat3');
+ camera_target_param.value = target;
+
+ InitializeLightParameters(globalParams, max_number_of_lights);
+
+ var fog_color_param = globalParams.createParam('fog_color', 'ParamFloat4');
+ fog_color_param.value = [0.5, 0.5, 0.5, 1.0];
+
+ // Create a perspective projection matrix.
+ var o3d_width = 845;
+ var o3d_height = 549;
+
+ var proj_matrix = math.matrix4.perspective(
+ 45 * Math.PI / 180, o3d_width / o3d_height, 0.1, 5000);
+
+ drawContext.projection = proj_matrix;
+
+ o3dElement.onkeydown = document.onkeydown;
+ o3dElement.onkeyup = document.onkeyup;
+
+ o3djs.event.startKeyboardEventSynthesis(o3dElement);
+ }
+}
+
+/**
+ * Remove callbacks on the o3d client.
+ */
+function uninit() {
+ if (client) {
+ client.cleanup();
+ }
+}
+
+/**
+ * Helper function to shorten document.getElementById()
+ * @param {string} value The elementID to find.
+ * @return {string} The document element with our ID.
+ */
+function $(id) {
+ return document.getElementById(id);
+}
+
+/**
+ * Helper function to tell us if a value is set to something useful.
+ * @param {Object} value The thing to check out.
+ * @return {boolean} Whether the thing is empty.
+ * TODO: 'Tis silly to have both an isEmpty and exists function
+ * when they're probably doing the same thing.
+ */
+function isEmpty(value) {
+ return (value == undefined) || (value == '');
+}
+
+/**
+ * Returns the 2nd value if the first is rmpty.
+ * @param {Object} val1 The thing to check for emptyness.
+ * @param {Object} val2 The thing to maybe pass back.
+ * @return {Object} One of the above.
+ */
+function ifEmpty(val1, val2) {
+ if (val1 == undefined || val1 == '') {
+ return val2;
+ }
+ return val1;
+}
+
+/**
+ * Helper function to tell us if a value exists.
+ * @param {Object} item The thing to check out.
+ * @return {boolean} Whether the thing exists.
+ */
+function exists(item) {
+ if (item == undefined || item == null) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+/**
+ * Takes an index number into our global levels[] array, and it loads up that
+ * level.
+ * @param {number} levelID The number of the level to load in.
+ */
+function loadLevel(levelID) {
+ if (isLoaded) {
+ return;
+ }
+ world = levels[levelID];
+
+ // If we're running in 'SketchUp mode' inside the level editor, tell SU to
+ // do the loading, then bail out of here.
+ if (isSU) {
+ clearTimeout(timerID)
+ url = 'skp:do_open@';
+ url += 'level_name=' + world.colladaFile;
+ url += '&friendly_name=' + world.name;
+ window.location.href = url;
+ $('export-button').disabled = false;
+ $('play-button').disabled = false;
+ $('pause-button').disabled = true;
+ isLoaded = true;
+ return;
+ }
+
+ var path = window.location.href;
+ var index = path.lastIndexOf('/');
+ path = path.substring(0, index + 1) + 'levels/' + world.colladaFile;
+ $('o3d').style.width = '845px';
+ $('o3d').style.height = '549px';
+
+ // Create a callback function to prepare the transform graph once its loaded.
+ function callback(exception) {
+ if (exception) {
+ alert('Could not load: ' + path + '\n' + exception);
+ } else {
+ var current_light = 0;
+ var my_effect = pack.createObject('Effect');
+ my_effect.name = 'global_effect';
+ var effect_string = $('global_effect').value;
+ my_effect.loadFromFXString(effect_string);
+
+ var xform_nodes = client.root.getTransformsInTree();
+ for (var i = 0; i < xform_nodes.length; ++i) {
+ var shape_name = xform_nodes[i].name;
+ if (shape_name.indexOf('Light') == 0) {
+ var world_transform = xform_nodes[i].getUpdatedWorldMatrix();
+ var world_loc = world_transform[3];
+ var world_location = world_loc;
+ var color = [1.0, 0.7, 0.10, 150.0];
+
+ var light_index = AddLight(world_location, color);
+ xform_nodes[i].parent = null;
+ ++current_light;
+ }
+ }
+
+ {
+ var materials = pack.getObjectsByClassName('o3d.Material');
+ for (var m = 0; m < materials.length; ++m) {
+ var material = materials[m];
+ if (!material.getParam('diffuseSampler')) {
+ diffuseParam = material.createParam('diffuseSampler',
+ 'ParamSampler');
+ diffuseParam.value = blackSampler;
+ }
+ material.effect = my_effect;
+ my_effect.createUniformParameters(material);
+ // go through each param on the material
+ var params = material.params;
+ for (var p = 0; p < params.length; ++p) {
+ var dst_param = params[p];
+ // see if there is one of the same name on the paramObject we're
+ // using for global parameters.
+ var src_param = globalParams.getParam(dst_param.name);
+ if (src_param) {
+ // see if they are compatible
+ if (src_param.isAClassName(dst_param.className)) {
+ // bind them
+ dst_param.bind(src_param);
+ }
+ }
+ }
+ }
+ }
+
+ // Remove all line primitives as we don't really want them to render.
+ {
+ var primitives = pack.getObjectsByClassName('o3d.Primitive');
+ for (var p = 0; p < primitives.length; ++p) {
+ var primitive = primitives[p];
+ if (primitive.primitiveType == o3d.Primitive.LINELIST) {
+ primitive.owner = null;
+ pack.removeObject(primitive);
+ }
+ }
+ }
+
+ o3djs.pack.preparePack(pack, g_viewInfo);
+ avatar = world.actors[0];
+ isLoaded = true;
+ client.setRenderCallback(onRender);
+ $('container').style.visibility = 'visible';
+ }
+ }
+
+ // Create a new transform node to attach our world to.
+ var world_parent = pack.createObject('Transform');
+ world_parent.parent = client.root;
+
+ function loadSceneCallback(pack, parent, exception) {
+ g_loadInfo = null;
+ callback(exception);
+ }
+ g_loadInfo = o3djs.scene.loadScene(client, pack, world_parent, path,
+ loadSceneCallback);
+}
+
+/**
+ * This is our little callback handler that o3d calls after each frame.
+ * @param {Object} renderEvent An event object.
+ */
+function onRender(renderEvent) {
+ if (g_loadInfo) {
+ $('fps').innerHTML = 'Loading: ' +
+ g_loadInfo.getKnownProgressInfoSoFar().percent + '%';
+ }
+ if (isLoaded == false) {
+ return;
+ }
+
+ var elapsedTime = Math.min(renderEvent.elapsedTime, 1 / 20);
+
+ nextFrame(elapsedTime);
+ UpdateLightsInProgram(avatar);
+
+ // Every 20 frames, update our frame rate display
+ frameCount++;
+ if (frameCount % 20 == 0) {
+ $('fps').innerHTML = Math.floor(1.0 / elapsedTime + 0.5);
+ }
+}
+
+/**
+ * This cancels scrolling and keeps focus on a hidden element so spacebar
+ * doesn't page down.
+ */
+function cancelScroll() {
+ $('focusHolder').focus();
+ var pageWidth = document.body.clientWidth;
+ var pageHeight = document.body.clientHeight;
+ document.body.scrollTop = 0;
+ document.body.scrollLeft = 0;
+}
diff --git a/o3d/samples/io/io.html b/o3d/samples/io/io.html
new file mode 100644
index 0000000..55c0db3
--- /dev/null
+++ b/o3d/samples/io/io.html
@@ -0,0 +1,173 @@
+<!--
+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.
+-->
+
+<html>
+ <title>The Journies of Prince IO: An O3D Adventure</title>
+ <link href="ui/io.css" rel="stylesheet" type="text/css"/>
+ <script type="text/javascript" src="../o3djs/base.js"></script>
+ <script type="text/javascript" src="dynamic_lights.js"></script>
+ <script type="text/javascript" src="init.js"></script>
+ <script type="text/javascript" src="autoincludes.js"></script>
+ <script type="text/javascript" src="gamelogic.js"></script>
+ <script type="text/javascript" src="cutscenes.js"></script>
+ <script type="text/javascript" src="sound/soundplayer.js"></script>
+</head>
+
+<body onload="init();" onscroll="cancelScroll()" onunload="uninit();">
+
+<table id="table-main"><tr><td valign=center>
+
+<table id="table-middle" cellspacing="0" cellpadding="0" border="0">
+ <tr>
+ <td id="book-left" width="50%"><div id="innercover-div"><img id="innercover" src="ui/book_innercover.jpg"></div></td>
+ <td id="book-center" width="1000"><div id="cover-div"><img id="cover-shadow" src="ui/covershadow.png"><img onclick="animateCover()" id="cover" src="ui/book_cover.jpg"></div><img src="ui/book_captop.jpg" width="988" height="39"><br><div id="cover-seam"></div><div id="content">
+
+ Choose a level...
+
+ </div><div id="container" name="container" >
+ <div id="o3d" style="width: 1px; height: 1px;"></div>
+ </div><img id="page1" src="ui/book_page1.jpg" onclick="animatePage('page1')"><img id="page2" src="ui/book_page2.jpg" onclick="animatePage('page2')"><img id="page3" src="ui/book_page3.jpg" onclick="animatePage('page3')"><img src="ui/book_pageblank.jpg" width="951" height="549"><img src="ui/book_capright.jpg" width="37" height="549"><br><img src="ui/book_capbottom.jpg" width="988" height="90"></td>
+ <td id="book-right" width="50%">&nbsp;</td>
+ </tr>
+</table>
+
+</td></tr></table>
+
+<form>
+<input id="focusHolder" style="position:absolute;top:-100px;">
+</form>
+
+<div id="footer"><div id="output"></div><div id="fps"></div><img src="ui/logo.gif" alt="Google"></div>
+<div id="fx" style="visibility:hidden">
+<textarea id="global_effect">
+struct a2v {
+ float4 position : POSITION;
+ float3 normal : NORMAL;
+ float2 texCoord : TEXCOORD0;
+};
+
+struct v2f {
+ float4 position : POSITION;
+ float3 worldPosition : TEXCOORD0;
+ float2 texCoord : TEXCOORD1;
+ float3 n : TEXCOORD2;
+ float3 l : TEXCOORD3;
+};
+
+float4x4 worldViewProj : WorldViewProjection;
+float4x4 world : World;
+float4x4 worldIT : WorldInverseTranspose;
+
+uniform float4 ambientLightColor;
+uniform float3 sunlightDirection;
+uniform float4 sunlightColor;
+uniform float3 cameraEye;
+uniform float3 cameraTarget;
+
+uniform float3 light0_location;
+uniform float3 light1_location;
+uniform float3 light2_location;
+uniform float3 light3_location;
+uniform float3 light4_location;
+
+uniform float4 light0_color;
+uniform float4 light1_color;
+uniform float4 light2_color;
+uniform float4 light3_color;
+uniform float4 light4_color;
+uniform float4 fog_color;
+
+// The texture from a sketchup6 file
+// A diffuseTexture and a diffuse color (when there isn't a texture)
+uniform float4 diffuse; // The color, unless texture
+sampler2D diffuseSampler;
+
+v2f vsMain(a2v IN) {
+ v2f OUT;
+ OUT.position = mul(IN.position, worldViewProj);
+ OUT.worldPosition = mul(IN.position, world).xyz;
+ OUT.texCoord = IN.texCoord;
+
+ OUT.n = mul(float4(IN.normal,0), worldIT).xyz;
+ OUT.l = IN.normal;
+ return OUT;
+}
+
+float4 fsMain(v2f IN): COLOR {
+ float4 textureColor = tex2D(diffuseSampler, IN.texCoord);
+ float3 normalDirection = normalize(IN.n);
+ float3 viewDirection = normalize(cameraEye - IN.worldPosition.xyz);
+ // Only diffuse light until we can get better than face normals.
+ float4 litWorld = lit(dot(normalDirection.xyz, sunlightDirection), 0, 0);
+ float4 total_color = ambientLightColor + litWorld.yyyy * sunlightColor;
+
+ float3 light_direction = light0_location - IN.worldPosition.xyz;
+ float attenuation = light0_color.a / length(light_direction);
+ light_direction = normalize(light_direction);
+ float4 litLight = lit(dot(normalDirection.xyz, light_direction), 0, 0);
+ litLight.y *= clamp(attenuation * attenuation, 0, 1);
+ total_color.rgb += litLight.yyy * light0_color.rgb;
+
+ light_direction = light1_location - IN.worldPosition.xyz;
+ attenuation = light1_color.a / length(light_direction);
+ light_direction = normalize(light_direction);
+ litLight = lit(dot(normalDirection.xyz, light_direction), 0, 0);
+ litLight.y *= clamp(attenuation * attenuation, 0, 1);
+ total_color.rgb += litLight.yyy * light1_color.rgb;
+
+ light_direction = light2_location - IN.worldPosition.xyz;
+ attenuation = light2_color.a / length(light_direction);
+ light_direction = normalize(light_direction);
+ litLight = lit(dot(normalDirection.xyz, light_direction), 0, 0);
+ litLight.y *= clamp(attenuation * attenuation, 0, 1);
+ total_color.rgb += litLight.yyy * light2_color.rgb;
+
+ light_direction = light3_location - IN.worldPosition.xyz;
+ attenuation = light3_color.a / length(light_direction);
+ light_direction = normalize(light_direction);
+ litLight = lit(dot(normalDirection.xyz, light_direction), 0, 0);
+ litLight.y *= clamp(attenuation * attenuation, 0, 1);
+ total_color.rgb += litLight.yyy * light3_color.rgb;
+
+ textureColor.rgb += diffuse.rgb;
+ total_color *= textureColor;
+
+ // Fog
+ float fog = saturate(pow(2.718, -.005 * (length(cameraEye - IN.worldPosition.xyz) - 300)));
+ return lerp(fog_color, total_color, fog);
+}
+
+// #o3d VertexShaderEntryPoint vsMain
+// #o3d PixelShaderEntryPoint fsMain
+// #o3d MatrixLoadOrder RowMajor
+</textarea>
+</div>
+</body>
diff --git a/o3d/samples/io/levels/all_actors.js b/o3d/samples/io/levels/all_actors.js
new file mode 100644
index 0000000..e630949
--- /dev/null
+++ b/o3d/samples/io/levels/all_actors.js
@@ -0,0 +1,383 @@
+/*
+ * 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.
+ */
+
+/**
+ * @fileoverview This file defines one level that our little game can run
+ * inside of. This file was auto-generated by io.rb from a SketchUp model.
+ */
+if (levels == undefined) {
+ var levels = [];
+}
+
+levels.push({
+ name: 'All Actors',
+ colladaFile: 'all_actors.o3dtgz',
+
+ platforms: [
+ {'left': {'mapX': 0},
+ 'z': 0, 'rotZ': 0.0,
+ 'right': {'adjacentID': 1, 'mapX': 1151}},
+ {'left': {'adjacentID': 0, 'mapX': 1151},
+ 'z': 0, 'rotZ': 0.432710088213842,
+ 'right': {'adjacentID': 2, 'mapX': 2588}},
+ {'left': {'adjacentID': 1, 'mapX': 2588},
+ 'z': 0, 'rotZ': 0.0,
+ 'right': {'adjacentID': 3, 'mapX': 3159}},
+ {'left': {'adjacentID': 2, 'mapX': 3159},
+ 'z': 0, 'rotZ': 5.85194141379659,
+ 'right': {'adjacentID': 4, 'mapX': 3474}},
+ {'left': {'adjacentID': 3, 'mapX': 3474},
+ 'z': 0, 'rotZ': 5.27977245408739,
+ 'right': {'adjacentID': 5, 'mapX': 4178}},
+ {'left': {'adjacentID': 4, 'mapX': 4178},
+ 'z': 0, 'rotZ': 4.97548502987221,
+ 'right': {'adjacentID': 6, 'mapX': 4798}},
+ {'left': {'adjacentID': 5, 'mapX': 4798},
+ 'z': 0, 'rotZ': 4.71238898038469,
+ 'right': {'mapX': 6726}},
+ {'left': {'mapX': 3960},
+ 'z': 397, 'parentID': 4, 'rotZ': 5.27977245408739,
+ 'right': {'mapX': 4051}},
+ {'left': {'mapX': 1308},
+ 'z': 45, 'parentID': 1, 'rotZ': 0.432710088213843,
+ 'right': {'obstacleHeight': 15, 'mapX': 1563}},
+ {'left': {'mapX': 312},
+ 'z': 172, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'mapX': 524}},
+ {'left': {'mapX': 2915},
+ 'z': 123, 'parentID': 2, 'rotZ': 0.0,
+ 'right': {'obstacleHeight': 64, 'mapX': 3066}},
+ {'left': {'obstacleHeight': 72, 'mapX': 525},
+ 'z': 99, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'mapX': 545}},
+ {'left': {'mapX': 2117},
+ 'z': 74, 'parentID': 1, 'rotZ': 0.432710088213842,
+ 'right': {'obstacleHeight': 76, 'mapX': 2441}},
+ {'left': {'mapX': 514},
+ 'z': 365, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'mapX': 576}},
+ {'left': {'mapX': 1377},
+ 'z': 115, 'parentID': 1, 'rotZ': 0.432710088213839,
+ 'right': {'mapX': 1433}},
+ {'left': {'mapX': 1828},
+ 'z': 309, 'parentID': 1, 'rotZ': 0.432710088213842,
+ 'right': {'mapX': 1897}},
+ {'left': {'obstacleHeight': 37, 'mapX': 6233},
+ 'z': 166, 'parentID': 6, 'rotZ': 4.71238898038469,
+ 'right': {'mapX': 6327}},
+ {'left': {'mapX': 714},
+ 'z': 138, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'mapX': 869}},
+ {'left': {'mapX': 1505},
+ 'z': 233, 'parentID': 1, 'rotZ': 0.432710088213845,
+ 'right': {'mapX': 1563}},
+ {'left': {'obstacleHeight': 43, 'mapX': 4338},
+ 'z': 222, 'parentID': 5, 'rotZ': 4.97548502987221,
+ 'right': {'mapX': 4502}},
+ {'left': {'mapX': 593},
+ 'z': 287, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'obstacleHeight': 24, 'mapX': 717}},
+ {'left': {'mapX': 3377},
+ 'z': 326, 'parentID': 3, 'rotZ': 5.85194141379659,
+ 'right': {'obstacleHeight': 144, 'mapX': 4466}},
+ {'left': {'mapX': 3704},
+ 'z': 194, 'parentID': 4, 'rotZ': 5.27977245408739,
+ 'right': {'mapX': 3862}},
+ {'left': {'mapX': 4087},
+ 'z': 397, 'parentID': 4, 'rotZ': 5.27977245408739,
+ 'right': {'mapX': 4161}},
+ {'left': {'mapX': 2699},
+ 'z': 351, 'parentID': 2, 'rotZ': 0.0,
+ 'right': {'mapX': 2705}},
+ {'left': {'obstacleHeight': 22, 'mapX': 545},
+ 'z': 76, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'obstacleHeight': 22, 'mapX': 636}},
+ {'left': {'mapX': 1678},
+ 'z': 309, 'parentID': 1, 'rotZ': 0.432710088213842,
+ 'right': {'mapX': 1767}},
+ {'left': {'mapX': 4208},
+ 'z': 373, 'parentID': 5, 'rotZ': 4.97548502987219,
+ 'right': {'mapX': 4232}},
+ {'left': {'mapX': 2441},
+ 'z': 150, 'parentID': 1, 'rotZ': 0.432710088213842,
+ 'right': {'adjacentID': 29, 'mapX': 2587}},
+ {'left': {'adjacentID': 28, 'mapX': 2587},
+ 'z': 150, 'parentID': 2, 'rotZ': 0.0,
+ 'right': {'obstacleHeight': 200, 'mapX': 2705}},
+ {'left': {'mapX': 4208},
+ 'z': 252, 'parentID': 5, 'rotZ': 4.97548502987219,
+ 'right': {'obstacleHeight': 30, 'mapX': 4238}},
+ {'left': {'obstacleHeight': 107, 'mapX': -24},
+ 'z': 76, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'obstacleHeight': 42, 'mapX': 265}},
+ {'left': {'mapX': 4239},
+ 'z': 282, 'parentID': 5, 'rotZ': 4.9754850298722,
+ 'right': {'mapX': 4301}},
+ {'left': {'obstacleHeight': 38, 'mapX': 1433},
+ 'z': 76, 'parentID': 1, 'rotZ': 0.432710088213846,
+ 'right': {'obstacleHeight': 34, 'mapX': 1477}},
+ {'left': {'obstacleHeight': 17, 'mapX': 4302},
+ 'z': 265, 'parentID': 5, 'rotZ': 4.97548502987222,
+ 'right': {'mapX': 4338}},
+ {'left': {'mapX': 1505},
+ 'z': 148, 'parentID': 1, 'rotZ': 0.432710088213845,
+ 'right': {'mapX': 1563}},
+ {'left': {'obstacleHeight': 30, 'mapX': 2441},
+ 'z': 43, 'parentID': 1, 'rotZ': 0.432710088213842,
+ 'right': {'mapX': 2587}},
+ {'left': {'mapX': 1478},
+ 'z': 111, 'parentID': 1, 'rotZ': 0.432710088213837,
+ 'right': {'obstacleHeight': 37, 'mapX': 1504}},
+ {'left': {'mapX': 1927},
+ 'z': 290, 'parentID': 1, 'rotZ': 0.432710088213842,
+ 'right': {'mapX': 2193}},
+ {'left': {'mapX': 2706},
+ 'z': 351, 'parentID': 2, 'rotZ': 0.0,
+ 'right': {'mapX': 2738}},
+ {'left': {'obstacleHeight': 37, 'mapX': 6136},
+ 'z': 203, 'parentID': 6, 'rotZ': 4.71238898038469,
+ 'right': {'mapX': 6232}},
+ {'left': {'mapX': 4843},
+ 'z': 240, 'parentID': 6, 'rotZ': 4.71238898038469,
+ 'right': {'mapX': 6135}},
+ {'left': {'mapX': 3921},
+ 'z': 222, 'parentID': 4, 'rotZ': 5.27977245408739,
+ 'right': {'adjacentID': 43, 'mapX': 4177}},
+ {'left': {'adjacentID': 42, 'mapX': 4177},
+ 'z': 222, 'parentID': 5, 'rotZ': 4.97548502987222,
+ 'right': {'obstacleHeight': 30, 'mapX': 4207}},
+ {'left': {'mapX': 1478},
+ 'z': 196, 'parentID': 1, 'rotZ': 0.432710088213837,
+ 'right': {'mapX': 1504}},
+ {'left': {'obstacleHeight': 61, 'mapX': 870},
+ 'z': 76, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'adjacentID': 46, 'mapX': 1151}},
+ {'left': {'adjacentID': 45, 'mapX': 1151},
+ 'z': 76, 'parentID': 1, 'rotZ': 0.432710088213843,
+ 'right': {'obstacleHeight': 38, 'mapX': 1377}},
+ {'left': {'mapX': 4665},
+ 'z': 222, 'parentID': 5, 'rotZ': 4.97548502987221,
+ 'right': {'mapX': 4739}},
+ {'left': {'obstacleHeight': 72, 'mapX': 1563},
+ 'z': 76, 'parentID': 1, 'rotZ': 0.432710088213843,
+ 'right': {'mapX': 2018}},
+ {'left': {'mapX': 4769},
+ 'z': 222, 'parentID': 5, 'rotZ': 4.97548502987221,
+ 'right': {'adjacentID': 50, 'mapX': 4798}},
+ {'left': {'adjacentID': 49, 'mapX': 4798},
+ 'z': 222, 'parentID': 6, 'rotZ': 4.71238898038469,
+ 'right': {'obstacleHeight': 18, 'mapX': 4843}},
+ {'left': {'mapX': 312},
+ 'z': 234, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'mapX': 362}},
+ {'left': {'mapX': 265},
+ 'z': 119, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'obstacleHeight': 53, 'mapX': 312}},
+ {'left': {'mapX': 2642},
+ 'z': 326, 'parentID': 2, 'rotZ': 0.0,
+ 'right': {'obstacleHeight': 25, 'mapX': 2699}},
+ {'left': {'obstacleHeight': 37, 'mapX': 6327},
+ 'z': 129, 'parentID': 6, 'rotZ': 4.71238898038469,
+ 'right': {'mapX': 6596}},
+ {'left': {'obstacleHeight': 96, 'mapX': 6596},
+ 'z': 32, 'parentID': 6, 'rotZ': 4.71238898038469,
+ 'right': {'mapX': 6726}},
+ {'left': {'mapX': 1352},
+ 'z': 155, 'parentID': 1, 'rotZ': 0.432710088213843,
+ 'right': {'mapX': 1388}},
+ {'left': {'mapX': 4551},
+ 'z': 222, 'parentID': 5, 'rotZ': 4.97548502987221,
+ 'right': {'mapX': 4595}},
+ {'left': {'mapX': 636},
+ 'z': 98, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'obstacleHeight': 39, 'mapX': 714}},
+ {'left': {'obstacleHeight': 227, 'mapX': 2738},
+ 'z': 123, 'parentID': 2, 'rotZ': 0.0,
+ 'right': {'mapX': 2762}},
+ {'left': {'mapX': 2642},
+ 'z': 247, 'parentID': 2, 'rotZ': 0.0,
+ 'right': {'obstacleHeight': 78, 'mapX': 2701}},
+ {'left': {'mapX': 4401},
+ 'z': 394, 'parentID': 3, 'rotZ': 5.85194141379659,
+ 'right': {'obstacleHeight': 161, 'mapX': 4463}},
+ {'left': {'mapX': 1561},
+ 'z': 309, 'parentID': 1, 'rotZ': 0.432710088213842,
+ 'right': {'mapX': 1623}},
+ {'left': {'mapX': 3248},
+ 'z': 222, 'parentID': 3, 'rotZ': 5.85194141379659,
+ 'right': {'adjacentID': 64, 'mapX': 3473}},
+ {'left': {'adjacentID': 63, 'mapX': 3473},
+ 'z': 222, 'parentID': 4, 'rotZ': 5.2797724540874,
+ 'right': {'mapX': 3607}},
+ {'left': {'mapX': 400},
+ 'z': 270, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'mapX': 524}},
+ {'left': {'mapX': 3066},
+ 'z': 188, 'parentID': 2, 'rotZ': 0.0,
+ 'right': {'adjacentID': 67, 'mapX': 3159}},
+ {'left': {'adjacentID': 66, 'mapX': 3159},
+ 'z': 188, 'parentID': 3, 'rotZ': 5.85194141379659,
+ 'right': {'obstacleHeight': 33, 'mapX': 3248}}],
+ actors: [
+ new Avatar({ name: 'Avatar1', colladaID: 'Avatar1',
+ x: 23, y: 0, z: 77, mapX: 24, rotZ: 0.0628318530722379,
+
+ platformID: 31}),
+ new Spikem({ name: 'Spikem1', colladaID: 'Spikem1',
+ x: 186, y: -1, z: 76, mapX: 186, rotZ: 0.0,
+ platformID: 31}),
+ new Spikem({ name: 'Spikem2', colladaID: 'Spikem2',
+ x: 763, y: -2, z: 144, mapX: 762, rotZ: 0.0,
+ platformID: 17}),
+ new Spikem({ name: 'Spikem3', colladaID: 'Spikem3',
+ x: 437, y: -1, z: 178, mapX: 436, rotZ: 0.0,
+ platformID: 9}),
+ new Spikem({ name: 'Spikem4', colladaID: 'Spikem4',
+ x: 1819, y: 311, z: 80, mapX: 1886, rotZ: 0.0,
+ platformID: 48}),
+ new Spikem({ name: 'Spikem5', colladaID: 'Spikem5',
+ x: 2861, y: 602, z: 130, mapX: 2992, rotZ: 0.0,
+ platformID: 10}),
+ new Spikem({ name: 'Spikem6', colladaID: 'Spikem6',
+ x: 3830, y: -631, z: 228, mapX: 4704, rotZ: 0.0,
+ platformID: 47}),
+ new Spikem({ name: 'Spikem7', colladaID: 'Spikem7',
+ x: 3854, y: -1682, z: 246, mapX: 5757, rotZ: 0.0,
+ platformID: 41}),
+ new Spikem({ name: 'Spikem8', colladaID: 'Spikem8',
+ x: 3796, y: -507, z: 228, mapX: 4575, rotZ: 0.0,
+ platformID: 57}),
+ new Spikem({ name: 'Spikem9', colladaID: 'Spikem9',
+ x: 3765, y: -390, z: 228, mapX: 4454, rotZ: 0.0,
+ platformID: 19}),
+ new Spikem({ name: 'Spikem10', colladaID: 'Spikem10',
+ x: 3848, y: -2623, z: 22, mapX: 6699, rotZ: 0.0,
+ platformID: 55}),
+ new Arrow({ name: 'Arrow1', colladaID: 'Arrow1',
+ x: 40, y: 3, z: 99, mapX: 40, rotZ: 0.0,
+ platformID: 31}),
+ new Arrow({ name: 'Arrow2', colladaID: 'Arrow2',
+ x: 37, y: 0, z: 76, mapX: 37, rotZ: 0.0,
+ platformID: 31}),
+ new Arrow({ name: 'Arrow3', colladaID: 'Arrow3',
+ x: 40, y: 3, z: 86, mapX: 40, rotZ: 0.0,
+ platformID: 31}),
+ new HorizontalPad({ name: 'HorizontalPad1', colladaID: 'HorizontalPad1',
+ x: 1692, y: 247, z: 312, mapX: 1745, rotZ: -0.411897703470668,
+ platformID: 26}),
+ new HorizontalPad({ name: 'HorizontalPad2', colladaID: 'HorizontalPad2',
+ x: 1926, y: 355, z: 292, mapX: 2003, rotZ: -0.411897703470668,
+ platformID: 38}),
+ new Coin({ name: 'Coin1', colladaID: 'Coin1',
+ x: 342, y: -2, z: 247, mapX: 341, rotZ: 0.0,
+ platformID: 51}),
+ new Coin({ name: 'Coin2', colladaID: 'Coin2',
+ x: 424, y: -2, z: 299, mapX: 423, rotZ: 0.0,
+ platformID: 65}),
+ new Coin({ name: 'Coin3', colladaID: 'Coin3',
+ x: 461, y: -2, z: 303, mapX: 461, rotZ: 0.0,
+ platformID: 65}),
+ new Coin({ name: 'Coin4', colladaID: 'Coin4',
+ x: 496, y: -2, z: 303, mapX: 495, rotZ: 0.0,
+ platformID: 65}),
+ new Coin({ name: 'Coin5', colladaID: 'Coin5',
+ x: 1426, y: 121, z: 83, mapX: 1450, rotZ: 0.0,
+ platformID: 33}),
+ new Coin({ name: 'Coin6', colladaID: 'Coin6',
+ x: 1659, y: 232, z: 344, mapX: 1709, rotZ: 0.0,
+ platformID: 26}),
+ new Coin({ name: 'Coin7', colladaID: 'Coin7',
+ x: 1697, y: 254, z: 344, mapX: 1753, rotZ: 0.0,
+ platformID: 26}),
+ new Coin({ name: 'Coin8', colladaID: 'Coin8',
+ x: 1971, y: 382, z: 304, mapX: 2055, rotZ: 0.0,
+ platformID: 38}),
+ new Coin({ name: 'Coin9', colladaID: 'Coin9',
+ x: 2053, y: 419, z: 304, mapX: 2145, rotZ: 0.0,
+ platformID: 38}),
+ new Coin({ name: 'Coin10', colladaID: 'Coin10',
+ x: 2015, y: 402, z: 305, mapX: 2103, rotZ: 0.0,
+ platformID: 38}),
+ new Coin({ name: 'Coin11', colladaID: 'Coin11',
+ x: 2184, y: 475, z: 229, mapX: 2287, rotZ: 0.0,
+ platformID: 38}),
+ new Coin({ name: 'Coin12', colladaID: 'Coin12',
+ x: 2184, y: 475, z: 256, mapX: 2287, rotZ: 0.0,
+ platformID: 38}),
+ new Coin({ name: 'Coin13', colladaID: 'Coin13',
+ x: 2184, y: 475, z: 307, mapX: 2287, rotZ: 0.0,
+ platformID: 38}),
+ new Coin({ name: 'Coin14', colladaID: 'Coin14',
+ x: 2184, y: 475, z: 282, mapX: 2287, rotZ: 0.0,
+ platformID: 38}),
+ new Coin({ name: 'Coin15', colladaID: 'Coin15',
+ x: 546, y: -2, z: 422, mapX: 545, rotZ: 0.0,
+ platformID: 13}),
+ new Coin({ name: 'Coin16', colladaID: 'Coin16',
+ x: 2590, y: 607, z: 371, mapX: 2721, rotZ: 0.0,
+ platformID: 39}),
+ new Coin({ name: 'Coin17', colladaID: 'Coin17',
+ x: 2737, y: 606, z: 246, mapX: 2961, rotZ: 0.0,
+ platformID: 10}),
+ new Coin({ name: 'Coin18', colladaID: 'Coin18',
+ x: 2737, y: 606, z: 273, mapX: 2868, rotZ: 0.0,
+ platformID: 39}),
+ new Coin({ name: 'Coin19', colladaID: 'Coin19',
+ x: 3599, y: 21, z: 433, mapX: 4005, rotZ: 0.0,
+ platformID: 7}),
+ new Coin({ name: 'Coin20', colladaID: 'Coin20',
+ x: 3665, y: -78, z: 429, mapX: 4125, rotZ: 0.0,
+ platformID: 23}),
+ new Coin({ name: 'Coin21', colladaID: 'Coin21',
+ x: 4156, y: 77, z: 423, mapX: 4402, rotZ: 0.0,
+ platformID: 61}),
+ new Coin({ name: 'Coin22', colladaID: 'Coin22',
+ x: 4182, y: 71, z: 418, mapX: 4428, rotZ: 0.0,
+ platformID: 61}),
+ new Coin({ name: 'Coin23', colladaID: 'Coin23',
+ x: 4182, y: 71, z: 447, mapX: 4428, rotZ: 0.0,
+ platformID: 61}),
+ new Coin({ name: 'Coin24', colladaID: 'Coin24',
+ x: 4156, y: 77, z: 452, mapX: 4402, rotZ: 0.0,
+ platformID: 61}),
+ new Coin({ name: 'Coin25', colladaID: 'Coin25',
+ x: 4156, y: 77, z: 482, mapX: 4402, rotZ: 0.0,
+ platformID: 61}),
+ new Coin({ name: 'Coin26', colladaID: 'Coin26',
+ x: 4182, y: 71, z: 477, mapX: 4428, rotZ: 0.0,
+ platformID: 61}),
+ new VerticalPad({ name: 'VerticalPad1', colladaID: 'VerticalPad1',
+ x: 2663, y: 603, z: 221, mapX: 2794, rotZ: 0.0,
+ platformID: 60}),
+ new VerticalPad({ name: 'VerticalPad2', colladaID: 'VerticalPad2',
+ x: 2799, y: 603, z: 152, mapX: 2930, rotZ: 0.0,
+ platformID: 10})]
+});
diff --git a/o3d/samples/io/levels/all_actors.skp b/o3d/samples/io/levels/all_actors.skp
new file mode 100644
index 0000000..99e97ee
--- /dev/null
+++ b/o3d/samples/io/levels/all_actors.skp
Binary files differ
diff --git a/o3d/samples/io/levels/map1.js b/o3d/samples/io/levels/map1.js
new file mode 100644
index 0000000..2bd7eee
--- /dev/null
+++ b/o3d/samples/io/levels/map1.js
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+/**
+ * @fileoverview This file defines one level that our little game can run
+ * inside of. This file was auto-generated by io.rb from a SketchUp model.
+ */
+if (levels == undefined) {
+ var levels = [];
+}
+
+levels.push({
+ name: 'Chapter One',
+ colladaFile: 'map1.o3dtgz',
+
+ platforms: [
+ {'left': {'mapX': 0},
+ 'z': 0.0, 'rotZ': 0.0,
+ 'right': {'adjacentID': 1, 'mapX': 99.9999999999998}},
+ {'left': {'adjacentID': 0, 'mapX': 99.9999999999998},
+ 'z': 0.0, 'rotZ': 0.785398163397443,
+ 'right': {'adjacentID': 2, 'mapX': 399.999999999999}},
+ {'left': {'adjacentID': 1, 'mapX': 399.999999999999},
+ 'z': 0.0, 'rotZ': 1.5707963267949,
+ 'right': {'adjacentID': 3, 'mapX': 561.617965644037}},
+ {'left': {'adjacentID': 2, 'mapX': 561.617965644037},
+ 'z': 0.0, 'rotZ': 0.0,
+ 'right': {'adjacentID': 4, 'mapX': 812.03592686014}},
+ {'left': {'adjacentID': 3, 'mapX': 812.03592686014},
+ 'z': 0.0, 'rotZ': 5.49970875351729,
+ 'right': {'adjacentID': 5, 'mapX': 922.215597985646}},
+ {'left': {'adjacentID': 4, 'mapX': 922.215597985646},
+ 'z': 0.0, 'rotZ': 4.716232199855,
+ 'right': {'adjacentID': 6, 'mapX': 1105.95801639536}},
+ {'left': {'adjacentID': 5, 'mapX': 1105.95801639536},
+ 'z': 0.0, 'rotZ': 4.04298946008257,
+ 'right': {'adjacentID': 7, 'mapX': 1208.29233370876}},
+ {'left': {'adjacentID': 6, 'mapX': 1208.29233370876},
+ 'z': 0.0, 'rotZ': 4.71238898038469,
+ 'right': {'adjacentID': 8, 'mapX': 1367.79233370876}},
+ {'left': {'adjacentID': 7, 'mapX': 1367.79233370876},
+ 'z': 0.0, 'rotZ': 0.0,
+ 'right': {'mapX': 1748.54233370876}},
+ {'left': {'mapX': 672.461706167729},
+ 'z': 133.25, 'parentID': 3, 'rotZ': 0.0,
+ 'right': {'mapX': 725.904505439235}},
+ {'left': {'mapX': 70.3557338817432},
+ 'z': 58.5, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'adjacentID': 11, 'mapX': 99.9999999999998}},
+ {'left': {'adjacentID': 10, 'mapX': 99.9999999999998},
+ 'z': 58.5, 'parentID': 1, 'rotZ': 0.785398163397443,
+ 'right': {'mapX': 177.235601196938}},
+ {'left': {'obstacleHeight': 32.0, 'mapX': 832.589734479398},
+ 'z': 65.5, 'parentID': 4, 'rotZ': 5.49970875351729,
+ 'right': {'adjacentID': 13, 'mapX': 922.215597985645}},
+ {'left': {'adjacentID': 12, 'mapX': 922.215597985645},
+ 'z': 65.5, 'parentID': 5, 'rotZ': 4.716232199855,
+ 'right': {'mapX': 1025.68972725654}},
+ {'left': {'mapX': 1176.12562519989},
+ 'z': 133.25, 'parentID': 6, 'rotZ': 4.04298946008257,
+ 'right': {'adjacentID': 15, 'mapX': 1208.29233370876}},
+ {'left': {'adjacentID': 14, 'mapX': 1208.29233370876},
+ 'z': 133.25, 'parentID': 7, 'rotZ': 4.71238898038469,
+ 'right': {'adjacentID': 16, 'mapX': 1367.79233370876}},
+ {'left': {'adjacentID': 15, 'mapX': 1367.79233370876},
+ 'z': 133.25, 'parentID': 8, 'rotZ': 0.0,
+ 'right': {'mapX': 1748.54233370876}},
+ {'left': {'obstacleHeight': 13.75, 'mapX': -13.0628855147159},
+ 'z': 69.5, 'parentID': 0, 'rotZ': 0.0,
+ 'right': {'mapX': 31.2499999999998}},
+ {'left': {'mapX': 812.03592686014},
+ 'z': 47.0, 'parentID': 4, 'rotZ': 5.49970875351729,
+ 'right': {'mapX': 922.215597985646}},
+ {'left': {'mapX': 177.235601196938},
+ 'z': 75.5, 'parentID': 1, 'rotZ': 0.785398163397443,
+ 'right': {'obstacleHeight': 28.25, 'mapX': 254.471202393877}},
+ {'left': {'mapX': 757.192725889269},
+ 'z': 97.5, 'parentID': 3, 'rotZ': 0.0,
+ 'right': {'adjacentID': 21, 'mapX': 812.03592686014}},
+ {'left': {'adjacentID': 20, 'mapX': 812.03592686014},
+ 'z': 97.5, 'parentID': 4, 'rotZ': 5.49970875351729,
+ 'right': {'mapX': 832.589734479398}},
+ {'left': {'mapX': 254.471202393877},
+ 'z': 103.75, 'parentID': 1, 'rotZ': 0.785398163397442,
+ 'right': {'mapX': 331.706803590815}},
+ {'left': {'mapX': 1091.9536790532},
+ 'z': 60.5, 'parentID': 5, 'rotZ': 4.71623219985501,
+ 'right': {'adjacentID': 24, 'mapX': 1105.95801639536}},
+ {'left': {'adjacentID': 23, 'mapX': 1105.95801639536},
+ 'z': 60.5, 'parentID': 6, 'rotZ': 4.04298946008257,
+ 'right': {'obstacleHeight': 31.5, 'mapX': 1143.95891669101}},
+ {'left': {'mapX': 399.999999999999},
+ 'z': 133.25, 'parentID': 2, 'rotZ': 1.5707963267949,
+ 'right': {'adjacentID': 26, 'mapX': 561.617965644037}},
+ {'left': {'adjacentID': 25, 'mapX': 561.617965644037},
+ 'z': 133.25, 'parentID': 3, 'rotZ': 0.0,
+ 'right': {'mapX': 621.461706167729}},
+ {'left': {'obstacleHeight': 74.25, 'mapX': 621.461706167729},
+ 'z': 59.0, 'parentID': 3, 'rotZ': 0.0,
+ 'right': {'obstacleHeight': 74.25, 'mapX': 672.461706167729}},
+ {'left': {'mapX': 1143.95891669101},
+ 'z': 92.0, 'parentID': 6, 'rotZ': 4.04298946008257,
+ 'right': {'mapX': 1176.12562519989}},
+ {'left': {'obstacleHeight': 21.25, 'mapX': 331.706803590815},
+ 'z': 82.5, 'parentID': 1, 'rotZ': 0.785398163397442,
+ 'right': {'mapX': 384.382894323691}}],
+ actors: [
+ new Avatar({
+ name: 'Avatar1', colladaID: 'Avatar1',
+ x: 8.25548871083476, y: -10.107499431384, z: 70.0761619683742,
+ mapX: 8.25548871083476, rotZ: 0.0628318530722379, platformID: 17}),
+ new HorizontalPad({
+ name: 'HorizontalPad1', colladaID: 'HorizontalPad1',
+ x: 69.9999999999999, y: 0.0, z: 0.0,
+ mapX: 69.9999999999999, rotZ: 0.0, platformID: 0}),
+ new Arrow({
+ name: 'Arrow1', colladaID: 'Arrow1',
+ x: 24.8151490181853, y: -1.89670669278537, z: 68.75,
+ mapX: 24.8151490181853, rotZ: 0.0, platformID: 17}),
+ new Arrow({
+ name: 'Arrow2', colladaID: 'Arrow2',
+ x: 24.8151490181853, y: -1.89670669278537, z: 79.25,
+ mapX: 24.8151490181853, rotZ: 0.0, platformID: 17}),
+ new Arrow({
+ name: 'Arrow3', colladaID: 'Arrow3',
+ x: 24.8151490181853, y: -1.89670669278537, z: 92,
+ mapX: 24.8151490181853, rotZ: 0.0, platformID: 17})]
+});
diff --git a/o3d/samples/io/levels/map1.skp b/o3d/samples/io/levels/map1.skp
new file mode 100644
index 0000000..8014334
--- /dev/null
+++ b/o3d/samples/io/levels/map1.skp
Binary files differ
diff --git a/o3d/samples/io/levels/starter_level.skp b/o3d/samples/io/levels/starter_level.skp
new file mode 100644
index 0000000..31869f0
--- /dev/null
+++ b/o3d/samples/io/levels/starter_level.skp
Binary files differ
diff --git a/o3d/samples/io/sound/_MISS.mp3 b/o3d/samples/io/sound/_MISS.mp3
new file mode 100644
index 0000000..7acfc80
--- /dev/null
+++ b/o3d/samples/io/sound/_MISS.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/_PUNCH.mp3 b/o3d/samples/io/sound/_PUNCH.mp3
new file mode 100644
index 0000000..abb7277
--- /dev/null
+++ b/o3d/samples/io/sound/_PUNCH.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/_SMASH.mp3 b/o3d/samples/io/sound/_SMASH.mp3
new file mode 100644
index 0000000..c655a11
--- /dev/null
+++ b/o3d/samples/io/sound/_SMASH.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/_woosh.mp3 b/o3d/samples/io/sound/_woosh.mp3
new file mode 100644
index 0000000..5687be2
--- /dev/null
+++ b/o3d/samples/io/sound/_woosh.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/ah.mp3 b/o3d/samples/io/sound/ah.mp3
new file mode 100644
index 0000000..ff40207
--- /dev/null
+++ b/o3d/samples/io/sound/ah.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/arrow.mp3 b/o3d/samples/io/sound/arrow.mp3
new file mode 100644
index 0000000..e106d668
--- /dev/null
+++ b/o3d/samples/io/sound/arrow.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/coin_3.mp3 b/o3d/samples/io/sound/coin_3.mp3
new file mode 100644
index 0000000..d8f3ff5
--- /dev/null
+++ b/o3d/samples/io/sound/coin_3.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/music.mp3 b/o3d/samples/io/sound/music.mp3
new file mode 100644
index 0000000..653d191
--- /dev/null
+++ b/o3d/samples/io/sound/music.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/page.mp3 b/o3d/samples/io/sound/page.mp3
new file mode 100644
index 0000000..f2c9a08
--- /dev/null
+++ b/o3d/samples/io/sound/page.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/soundplayer.js b/o3d/samples/io/sound/soundplayer.js
new file mode 100644
index 0000000..95c0470
--- /dev/null
+++ b/o3d/samples/io/sound/soundplayer.js
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @fileoverview This file defines a SoundPlayer object that can be used to
+ * play .mp3 files via a tiny soundplayer.swf file.
+ *
+ * Here's some example javascript for how you'd use this thing:
+ * var soundPlayer = new SoundPlayer();
+ * soundPlayer.play('songToPlayOnce.mp3')
+ * soundPlayer.play('soundToLoopForeverAt50PercentVolume.mp3',50,999)
+ * soundPlayer.play('sfxToPlayAsEvent.mp3',100,0,true)
+ * soundPlayer.setVolume('soundToTurnOff.mp3',0);
+ * soundPlayer.setGlobalVolume(20);
+ *
+ */
+
+// Write a DIV to the screen that we can later use to embed our flash movie.
+ var html = '<div style="position:absolute; top:-1000px; left:-1000px; z-index: 0;width: 200px; height: 200px; ">'
+ html = '<OBJECT style="position:absolute; top:-1000px; left:-1000px;" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" '
+ html += 'codebase="http://download.macromedia.com/pub/shockwave/cabs/flash'
+ html += '/swflash.cab#version=6,0,0,0" WIDTH="200" HEIGHT="200" '
+ html += 'id="soundPlayer" ALIGN=""> '
+ html += '<PARAM NAME=movie VALUE="sound/soundplayer.swf"> '
+ html += '<PARAM NAME=quality VALUE=high> '
+ html += '<PARAM NAME=allowScriptAccess VALUE=always> '
+ html += '<EMBED src="sound/soundplayer.swf" quality=high WIDTH="200" HEIGHT="200" '
+ html += 'NAME="soundPlayer" swLiveConnect=true ALIGN="" '
+ html += 'TYPE="application/x-shockwave-flash" allowScriptAccess="always" '
+ html += 'PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer">'
+ html += '</EMBED></OBJECT></div>';
+ document.write(html);
+
+/**
+ * Constructor for our SoundPlayer object.
+ */
+function SoundPlayer() {
+ // TODO: Make this more generic so it loads at the author's
+ // request rather than at include time.
+}
+
+/**
+ * This is a helper function to simplify code throughout. Returns a default
+ * value if the first is empty.
+ * @param {Object} val1 Value to check for emptiness
+ * @param {Object} val2 Value to return if va1 is empty
+ * @return {Object} One of the above.
+ */
+SoundPlayer.prototype.defaultIfEmpty = function(val1,val2) {
+ if (val1 == undefined) {
+ return val2;
+ } else {
+ return val1;
+ }
+}
+
+/**
+ * This is the way to send action calls to the flash plugin. In this case,
+ * a string containing our action script that we want to execute. (Note that
+ * flash doesn't have a true "eval" function, so this isn't a security hole.)
+ * @param {string} callStr The command to have flash execute.
+ */
+SoundPlayer.prototype.makeActionScriptCall = function(callStr) {
+ try {
+ window.document['soundPlayer'].SetVariable('actionScriptCall', callStr);
+ } catch (ex) {
+ // Catch the exception so that any problems with the sound player don't
+ // derail the whle game.
+ }
+}
+
+// TODO: Need to clean up these function comments to follow
+// jsdoc standard. Also need to clean up for readability.
+
+/**
+ * SoundPlayer.play() : Call this guy to play a sound or music file.
+ *
+ * fileURL : a url to any mp3 you want to play (required)
+ * volumeLevel : a number from 0 (silent) to 100 (optional, defaults to 100)
+ * loopCount : How many times to loop the sound (optional, defaults to 0)
+ * isNewTrack : Boolean. If true, then a new "track" will be created,
+ * allowing you to layer as many sounds as you like
+ */
+SoundPlayer.prototype.play = function(fileURL,volumeLevel,loopCount,isNewTrack) {
+ volumeLevel = this.defaultIfEmpty(volumeLevel,100);
+ loopCount = this.defaultIfEmpty(loopCount,0);
+ isNewTrack = this.defaultIfEmpty(isNewTrack,false);
+ var actionScriptCall = 'play('+fileURL+',' + volumeLevel + ',' +
+ loopCount + ',' + isNewTrack + ')';
+ this.makeActionScriptCall(actionScriptCall);
+}
+
+/**
+ * SoundPlayer.setVolume() : Call this guy to change the volume on a sound.
+ *
+ * fileURL : a url to any mp3 or wav file you want to change the volume on
+ * volumeLevel : a number from 0 (silent) to 100 (loud)
+ */
+SoundPlayer.prototype.setVolume = function(fileURL,volumeLevel,fadeTime) {
+ var actionScriptCall = 'setVolume('+fileURL+',' + volumeLevel + ')';
+ this.makeActionScriptCall(actionScriptCall);
+}
+
+/**
+ * SoundPlayer.setGlobalVolume() : Call this guy to change the global
+ * volume on a sound. The global volume "multiplies" each sound's volume,
+ * so if your sound is playing at 100% and your global is at 50%, then
+ * your sounds will be half as loud.
+ *
+ * volumeLevel : a number from 0 (silent) to 100 (loud)
+ */
+SoundPlayer.prototype.setGlobalVolume = function(volumeLevel) {
+ var actionScriptCall = 'setGlobalVolume(' + volumeLevel + ')';
+ this.makeActionScriptCall(actionScriptCall);
+}
+
+// Create a global variable for this application to use.
+var soundPlayer = new SoundPlayer();
diff --git a/o3d/samples/io/sound/soundplayer.swf b/o3d/samples/io/sound/soundplayer.swf
new file mode 100644
index 0000000..4a1f0e0
--- /dev/null
+++ b/o3d/samples/io/sound/soundplayer.swf
Binary files differ
diff --git a/o3d/samples/io/sound/step1.mp3 b/o3d/samples/io/sound/step1.mp3
new file mode 100644
index 0000000..8419591
--- /dev/null
+++ b/o3d/samples/io/sound/step1.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/step2.mp3 b/o3d/samples/io/sound/step2.mp3
new file mode 100644
index 0000000..02895f0
--- /dev/null
+++ b/o3d/samples/io/sound/step2.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/step3.mp3 b/o3d/samples/io/sound/step3.mp3
new file mode 100644
index 0000000..8d7cf61
--- /dev/null
+++ b/o3d/samples/io/sound/step3.mp3
Binary files differ
diff --git a/o3d/samples/io/sound/ug.mp3 b/o3d/samples/io/sound/ug.mp3
new file mode 100644
index 0000000..7297175
--- /dev/null
+++ b/o3d/samples/io/sound/ug.mp3
Binary files differ
diff --git a/o3d/samples/io/ui/Thumbs.db b/o3d/samples/io/ui/Thumbs.db
new file mode 100644
index 0000000..1bb8f7a
--- /dev/null
+++ b/o3d/samples/io/ui/Thumbs.db
Binary files differ
diff --git a/o3d/samples/io/ui/bgtile.jpg b/o3d/samples/io/ui/bgtile.jpg
new file mode 100644
index 0000000..d6278f1
--- /dev/null
+++ b/o3d/samples/io/ui/bgtile.jpg
Binary files differ
diff --git a/o3d/samples/io/ui/book_capbottom.jpg b/o3d/samples/io/ui/book_capbottom.jpg
new file mode 100644
index 0000000..ef07486
--- /dev/null
+++ b/o3d/samples/io/ui/book_capbottom.jpg
Binary files differ
diff --git a/o3d/samples/io/ui/book_capleft.jpg b/o3d/samples/io/ui/book_capleft.jpg
new file mode 100644
index 0000000..eae6cd9
--- /dev/null
+++ b/o3d/samples/io/ui/book_capleft.jpg
Binary files differ
diff --git a/o3d/samples/io/ui/book_capright.jpg b/o3d/samples/io/ui/book_capright.jpg
new file mode 100644
index 0000000..0d7bfad
--- /dev/null
+++ b/o3d/samples/io/ui/book_capright.jpg
Binary files differ
diff --git a/o3d/samples/io/ui/book_captop.jpg b/o3d/samples/io/ui/book_captop.jpg
new file mode 100644
index 0000000..a1e2705
--- /dev/null
+++ b/o3d/samples/io/ui/book_captop.jpg
Binary files differ
diff --git a/o3d/samples/io/ui/book_cover.jpg b/o3d/samples/io/ui/book_cover.jpg
new file mode 100644
index 0000000..eaf42a0
--- /dev/null
+++ b/o3d/samples/io/ui/book_cover.jpg
Binary files differ
diff --git a/o3d/samples/io/ui/book_innercover.jpg b/o3d/samples/io/ui/book_innercover.jpg
new file mode 100644
index 0000000..7eca9e8
--- /dev/null
+++ b/o3d/samples/io/ui/book_innercover.jpg
Binary files differ
diff --git a/o3d/samples/io/ui/book_page1.jpg b/o3d/samples/io/ui/book_page1.jpg
new file mode 100644
index 0000000..3b62f53e
--- /dev/null
+++ b/o3d/samples/io/ui/book_page1.jpg
Binary files differ
diff --git a/o3d/samples/io/ui/book_page2.jpg b/o3d/samples/io/ui/book_page2.jpg
new file mode 100644
index 0000000..a0bfa1f
--- /dev/null
+++ b/o3d/samples/io/ui/book_page2.jpg
Binary files differ
diff --git a/o3d/samples/io/ui/book_page3.jpg b/o3d/samples/io/ui/book_page3.jpg
new file mode 100644
index 0000000..740e8b9
--- /dev/null
+++ b/o3d/samples/io/ui/book_page3.jpg
Binary files differ
diff --git a/o3d/samples/io/ui/book_pageblank.jpg b/o3d/samples/io/ui/book_pageblank.jpg
new file mode 100644
index 0000000..d266853
--- /dev/null
+++ b/o3d/samples/io/ui/book_pageblank.jpg
Binary files differ
diff --git a/o3d/samples/io/ui/covershadow.png b/o3d/samples/io/ui/covershadow.png
new file mode 100644
index 0000000..2409a78
--- /dev/null
+++ b/o3d/samples/io/ui/covershadow.png
Binary files differ
diff --git a/o3d/samples/io/ui/io.css b/o3d/samples/io/ui/io.css
new file mode 100644
index 0000000..03918ad
--- /dev/null
+++ b/o3d/samples/io/ui/io.css
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+
+BODY {
+ overflow: hidden;
+ background-image: url(../ui/bgtile.jpg);
+ padding: 0px;
+ margin: 0px;
+ color: white;
+}
+#content {
+ visibility: hidden; /* for now */
+ position: absolute;
+ color: black;
+ text-align: center;
+ padding-top: 50px;
+ font-size: 25px;
+ width: 951px;
+ height: 500px;
+}
+#container {
+ position: absolute;
+ text-align: center;
+ width: 882px;
+ height: 549px;
+ margin-left: 37px;
+}
+#footer {
+ position: absolute;
+ bottom: 0px;
+ height: 70px;
+ width: 100%;
+ text-align: center;
+}
+#whole-page {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ line-height: 100%;
+ border: 1px solid red;
+}
+#table-main {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+#table-middle {
+ padding: 0px;
+ margin: 0px;
+ border: 0px;
+}
+#book-left {
+ background-image: url(../ui/scrollwork.gif);
+ background-repeat: repeat-x;
+ background-position: right 40px;
+ text-align: right;
+ vertical-align: top;
+}
+#book-center {
+ width: 988px;
+ height: 662px;
+}
+#book-right {
+ background-image: url(../ui/scrollwork.gif);
+ background-repeat: repeat-x;
+ background-position: left 40px;
+}
+#book-capleft {
+ position: absolute;
+}
+#book-captop {
+ position: relative;
+}
+#cover-div {
+ position: absolute;
+ z-index: 100;
+ padding-top: 15px;
+ margin: 0px;
+}
+#cover-seam {
+ position: absolute;
+ z-index: 1000;
+ border-left: 1px solid #222222;
+ height: 575px;
+}
+#cover {
+ width: 975px;
+ height: 600px;
+ position: absolute;
+ z-index: 100;
+ cursor: pointer;
+ border: 0px;
+}
+#page1 {
+ position: absolute;
+ z-index: 90;
+ cursor: pointer;
+ border: 0px;
+}
+#page2 {
+ position: absolute;
+ z-index: 80;
+ cursor: pointer;
+}
+#page3 {
+ position: absolute;
+ z-index: 70;
+ cursor: pointer;
+}
+#cover-shadow {
+ position: absolute;
+ z-index: 99;
+}
+#innercover-div {
+ padding-top: 15px;
+ width: 20px;
+ height: 600px;
+ overflow: hidden;
+ text-align: right;
+ float: right;
+}
+
+#innercover {
+ width: 0px;
+ height: 600px;
+ float: right;
+}
+
+.levellink {
+ cursor: pointer;
+ text-decoration: underline;
+}
+
+
+#fps {
+ font-family: sans-serif;
+ text-align: left;
+ padding-top: 15px;
+ width: 250px;
+ float: left;
+ padding-left: 25px;
+ color: #B87333;
+}
+#output {
+ font-family: sans-serif;
+ text-align: right;
+ padding-top: 15px;
+ width: 250px;
+ float: right;
+ padding-right: 25px;
+ color: #222222;
+}
diff --git a/o3d/samples/io/ui/logo.gif b/o3d/samples/io/ui/logo.gif
new file mode 100644
index 0000000..7c9bae3
--- /dev/null
+++ b/o3d/samples/io/ui/logo.gif
Binary files differ
diff --git a/o3d/samples/io/ui/scrollwork.gif b/o3d/samples/io/ui/scrollwork.gif
new file mode 100644
index 0000000..55e2476
--- /dev/null
+++ b/o3d/samples/io/ui/scrollwork.gif
Binary files differ